Kyoo 5.2.1 配置参数详解

Kyoo 5.2.1 全量配置面逐项深挖:35+ 环境变量按消费方溯源分组(auth/api/scanner/transcoder 源码行号实证)、claims 权限四变量与 KEIBI_APIKEY 机制、PUBLIC_URL 与 JWT issuer 实测联动、生产 .env 模板与凭据注入规范、5 类改参不生效类故障实录。

KyooKyoo媒体服务器流媒体自托管2026/10/29

Kyoo 5.2.1 配置参数详解

目标:把 Kyoo 5.2.1 的全部配置面(.env 环境变量、compose 注入项、运行时探查端点)按服务与功能域逐项讲透——每个变量给默认值、消费方、实测行为与改动方式;全部结论在 Ubuntu 24.04 实测环境取得,关键语义均溯源到官方源码文件与行号。

一、环境信息

  • 操作系统:Ubuntu 24.04.5 LTS(x86_64),Docker 29.9.2 + Compose v5.6.1
  • Kyoo:5.2.1(镜像 ghcr.io/zoriya/kyoo_*:5.2)
  • 配置载体:单份 .env(compose 的 env_file: ./.env 注入到 auth/api/scanner/transcoder/postgres)+ compose 文件内的固定注入项
  • 源码参照:官方仓库 5.2.1 源码树(auth 为 Go、api 为 TypeScript、scanner 为 Python、transcoder 为 Go)
  • 部署目录:/opt/kyoo/(与部署指南篇一致)

二、前置条件

  1. 已按《Kyoo 5.2.1 Docker Compose 部署指南》完成部署,docker compose ps 中服务 Up(scanner 的外网依赖问题不影响本文参数验证,涉及 scanner 的变量以源码口径说明);
  2. 已注册管理员账号(本文示例 admin / q1w2e3r4);
  3. 理解一个前提:Kyoo 没有配置文件,全部配置走环境变量——没有 kyoo.conf、没有管理后台设置页,.env 是唯一配置源(front 的 API 地址在构建时注入,也由 compose 传值)。

三、参数查看与修改方式

3.1 查看运行值:三条实测路径

路径一:看某个服务实际生效的环境变量(compose 注入后的最终值):

$ docker compose exec auth env | grep -E 'PUBLIC_URL|CLAIMS|PGUSER' | head -5
PUBLIC_URL=http://localhost:8136
EXTRA_CLAIMS={"permissions": ["core.read", "core.play"], "verified": false}
FIRST_USER_CLAIMS={"permissions": ["users.read", "users.write", "users.delete", "apikeys.read", "apikeys.write", "core.read", "core.write", "core.play", "scanner.trigger", "scanner.guess", "scanner.search", "scanner.add"], "verified": true}
PGUSER=kyoo

路径二:运行时探查端点(不用进容器,curl 直接问):

$ curl -s http://localhost:8136/auth/info
{"publicUrl":"http://localhost:8136","allowRegister":true,"oidc":{}}

publicUrl 即 PUBLIC_URL 生效值、allowRegister 反映注册开关(DISABLE_REGISTRATION 未设置时为 true)、oidc 列出已启用的 OIDC 提供方。

路径三:数据库侧核对(claims 类配置的实际落库效果):

$ docker exec kyoo-5.2.1-postgres psql -U kyoo -d kyoo \
  -c "select username, claims from keibi.users where username='admin';"

实测输出节选(首个用户的 claims 与 .env 的 FIRST_USER_CLAIMS 字段值一致,JSONB 键序规范化后 verified 在前):

 username |                                     claims
----------+-----------------------------------------------------------------------------
 admin    | {"verified": true, "permissions": ["users.read", "users.write", "users.delete", "apikeys.read", "apikeys.write", "core.read", "core.write", "core.play", "scanner.trigger", "scanner.guess", "scanner.search", "scanner.add"]}
(1 row)

3.2 修改方式:改 .env 后定向重建

$ cd /opt/kyoo
$ vim .env
$ docker compose up -d --force-recreate auth api   # 只重建消费该变量的服务

定向重建是关键:不是每个变量都需要全栈重启。判断依据见第四节「参数总览」的消费方列——例如只改 GOCODER_PRESET 重建 transcoder 即可;改 PUBLIC_URL 则 auth 与 api 都要重建(前者签发、后者校验 issuer)。

⚠️ 直接 docker compose exec <svc> export XXX=... 或 docker exec 设置的环境变量只在 exec 会话内生效,不会写入服务进程——Kyoo 的配置只能经 compose/env_file 注入。

四、参数总览(按消费方分组)

以下变量清单逐一溯源自 5.2.1 官方源码(grep 实证,非转述文档):auth 服务 config.go 等、api 服务 process.env.* 引用、scanner os.getenv 调用、transcoder GOCODER_* 常量。

分组变量消费方默认值(实测/官方示例)
入口与身份PUBLIC_URLauth、api(经 compose 的 JWT_ISSUER)http://localhost:8901
入口与身份JWT_ISSUERapi、scannercompose 注入 ${PUBLIC_URL}
入口与身份KYOO_URLscanner、frontscanner 默认 http://traefik:8901/api
入口与身份AUTH_SERVERapicompose 内部注入
账号与权限EXTRA_CLAIMSauth{"permissions":["core.read","core.play"],"verified":false}
账号与权限FIRST_USER_CLAIMSauth管理员全量权限 JSON
账号与权限GUEST_CLAIMSauth{"permissions":["core.read"],"verified":true}
账号与权限PROTECTED_CLAIMSauthpermissions,verified
账号与权限DISABLE_REGISTRATIONauth未设置(允许注册)
内置 API KeyKEIBI_APIKEY_<名称>authscanner key 随机串
内置 API KeyKEIBI_APIKEY_<名称>_CLAIMSauth{"permissions":["core.read","core.write"]}
刮削TVDB_APIKEYscanner空(用内置默认 Key)
刮削TVDB_PINscanner空
刮削THEMOVIEDB_API_ACCESS_TOKENscanner空(用内置默认)
扫描LIBRARY_ROOTscanner、transcoder(挂载)./video
扫描SCANNER_LIBRARY_ROOTscanner容器内固定 /video
扫描LIBRARY_IGNORE_PATTERNscanner.*/[dD]ownloads?/.*
转码COMPOSE_PROFILEScompose 编排层cpu
转码GOCODER_PRESETtranscoderfast
转码GOCODER_HWACCELtranscoder按 profile 注入(nvidia/vaapi/qsv)
转码GOCODER_VAAPI_RENDERERtranscoder/dev/dri/renderD128
转码GOCODER_QSV_RENDERERtranscoder源码可见(qsv 档)
转码GOCODER_CACHE_ROOT / GOCODER_METADATA_ROOT / GOCODER_SAFE_PATHtranscoder容器内路径
数据库PGUSER/PGPASSWORD/PGDATABASE/PGHOST/PGPORT全部业务服务kyoo/password/kyoo/postgres/5432
数据库POSTGRES_URLauth、scanner空(libpq 整串,可带 sslmode)
数据库PGPASSFILE/PGOPTIONS/PGAPPNAME/PGSSLMODE 等api(libpq 全集)未设置
存储IMAGES_PATHapi./images(compose 覆写 /images)
存储CACHE_ROOTtranscoder(挂载)/tmp/kyoo_cache
存储PROFILE_PICTURE_PATHauth/profile_pictures(容器内)
密钥RSA_PRIVATE_KEY_PATHauth容器内默认路径(首次启动自生成 RSA 密钥对)
密钥JWT_SECRETapicompose 注入
可观测OTEL_EXPORTER_OTLP_ENDPOINT/PROTOCOL、OTEL_LOG_LEVEL、STDOUT_LOG_LEVELauth、api、scanner空/未设置
前端CAST_APPLICATION_IDfront空
OIDCOIDC_GOOGLE_NAME/LOGO/CLIENTID/SECRET/AUTHORIZATION/TOKEN/PROFILE/SCOPE/AUTHMETHODauth全部未设置
回调EXTRA_OIDC_REDIRECT_URLSauth空(compose 追加 kyoo scheme)

💡 技术拓展:「配置注入」在容器化应用里有三种常见形态对比——

形态代表特点
环境变量Kyoo(env_file)12-Factor 风格,无配置文件,改值需重建容器
配置文件挂载Nginx/PostgreSQL改值可 reload,无需重启进程
数据库/控制台配置Plex/Jellyfin有设置页,改值即时生效但难版本化

Kyoo 采用纯环境变量(官方声明无配置文件),好处是 .env 可进版本管理(脱敏后)、坏处是任何改动都要 --force-recreate 重建容器。

五、核心参数分类详解

5.1 入口与身份:PUBLIC_URL / JWT_ISSUER / KYOO_URL

这三个变量共同定义「Kyoo 被谁、从哪访问」,是全栈最容易踩坑的一组。

  • PUBLIC_URL:auth 读它生成对外信息(实测 GET /auth/info 回显 "publicUrl":"http://localhost:8136");compose 又把它传给 api/scanner 的 JWT_ISSUER——JWT 的 iss 声明。改动它 = 使所有已签发 token 失效,且必须让「浏览器实际访问地址」与该值一致,否则 OIDC 回调与前端拼接都会错。
  • JWT_ISSUER:api 校验 JWT 时的期望 issuer。compose 里固定 - JWT_ISSUER=${PUBLIC_URL},一般不单独改。
  • KYOO_URL:scanner 调 api 的地址,compose 默认注入 http://traefik:8901/api(走内部网络经 Traefik 转发,保持认证中间件链生效)。

实测验证 issuer 生效(拿登录 token 解开 payload 可见 iss 字段,节选):

$ TOKEN=$(curl -s -X POST http://localhost:8136/auth/sessions \
    -H 'Content-Type: application/json' \
    -d '{"login":"admin","password":"q1w2e3r4"}' | python3 -c "import json,sys;print(json.load(sys.stdin)['token'])")
$ curl -s http://localhost:8136/auth/jwt -H "Authorization: Bearer $TOKEN" | cut -d. -f2 | base64 -d 2>/dev/null; echo
{"iss":"http://localhost:8136","sub":"...","exp":...}

⚠️ 生产环境把 http://localhost:8136 换成真实域名(如 https://kyoo.example.com)后,除重建 auth/api 外,还要确认反向代理透传 Host 头。

5.2 元数据刮削:TVDB_APIKEY / TVDB_PIN / THEMOVIEDB_API_ACCESS_TOKEN

  • TVDB_APIKEY:TheTVDB v4 API 的 Key。源码 scanner/scanner/providers/thetvdb.py 第 35~45 行实证:Provider 基址硬编码 https://api4.thetvdb.com/v4/,Key 取值逻辑为 os.environ.get("TVDB_APIKEY") or TVDB.DEFAULT_API_KEY——留空也有一把内置默认 Key,且启动期就发起登录请求。实测内网环境 Cannot connect to host api4.thetvdb.com:443 → Application startup failed. Exiting.,scanner 崩溃循环(排障实录见部署指南篇 9.1)。自备 Key 的申请入口:https://thetvdb.com/api-information/signup。
  • TVDB_PIN:TVDB 订阅者 Pin,支持 TVDB 服务器时可填,普通用户留空。
  • THEMOVIEDB_API_ACCESS_TOKEN:TMDB 的 read access token(官方示例注释明确指出去 themoviedb.org/settings/api 复制「read access token」而非普通 api key,这是 TMDB v3/v4 的常见混淆点)。留空用内置默认。

自备 Key 的写法(.env):

TVDB_APIKEY=your-tvdb-key-here
THEMOVIEDB_API_ACCESS_TOKEN=your-tmdb-read-token-here

改后重建 scanner:docker compose up -d --force-recreate scanner。

5.3 账号与权限:四个 claims 变量

Kyoo 的权限模型是「JSON claims 进 JWT」,四个变量分别覆盖四类人群:

变量覆盖人群默认值要点实测依据
FIRST_USER_CLAIMS第一个注册用户users/apikeys/core/scanner 全量权限 + verified=true注册 admin 后查 keibi.users.claims 与该值逐字一致
EXTRA_CLAIMS之后注册的普通用户core.read + core.play,verified=false注册 demo1 后调用 /auth/users 报 Missing permissions: users.read.,证其无管理权限
GUEST_CLAIMS未登录游客core.read,verified=true实测不带任何凭证 GET /api/shows 返回 200 空列表
PROTECTED_CLAIMS保护名单permissions,verified防止 JWT 中这两项被外部改写

游客行为的实测回显(不带 Authorization 调用媒体库接口):

$ curl -s http://localhost:8136/api/shows
{"items":[],"this":"http://127.0.0.1:8136/api/shows","next":null}

改动示例:想让游客完全不能访问(全站强制登录),把 GUEST_CLAIMS 置空:

GUEST_CLAIMS=

⚠️ claims 值必须是合法 JSON 且整行书写;auth 启动时解析失败会直接退出(源码 config.go 对 claims 解析错误 return nil, err)。改完先用 python3 -m json.tool 校验再重启。

DISABLE_REGISTRATION:auth 源码可见读取(os.Getenv("DISABLE_REGISTRATION")),设置任意非空值后关闭开放注册(实测 GET /auth/info 的 allowRegister 会变 false)。

5.4 内置 API Key:KEIBI_APIKEY_<名称> 机制

这是一组「按命名约定发现」的变量,源码 auth/config.go 第 194~212 行实证装载逻辑:

  1. auth 启动时遍历全部环境变量,筛出 KEIBI_APIKEY_ 前缀且不以 _CLAIMS 结尾的项,取后缀作 key 名称;
  2. 再读对应的 KEIBI_APIKEY_<名称>_CLAIMS 作为该 key 的权限(缺失则启动报错 missing claims env var KEIBI_APIKEY_%s_CLAIMS);
  3. 启动后这些 key 直接可查(实测 GET /auth/keys 返回内置的 scanner key):
$ curl -s http://localhost:8136/auth/keys -H "Authorization: Bearer $TOKEN"
{"items":[{"id":"1bf0747a-6b5d-4aaa-82b3-e884e921fa53","name":"scanner","claims":{"permissions":["core.read","core.write"]}}],"this":"/auth/keys","next":null}

自己加一把内置 key(例:给自建脚本一把只读 key):

# .env 追加两行,名称只允许字母(源码约定)
KEIBI_APIKEY_MYSCRIPT=请用openssl-rand-base64-48自行生成
KEIBI_APIKEY_MYSCRIPT_CLAIMS='{"permissions": ["core.read"]}'

随后 docker compose up -d --force-recreate auth 生效,调用方式为请求头 X-Api-Key: <key 值>。

5.5 转码器:GOCODER_* 与 COMPOSE_PROFILES

  • COMPOSE_PROFILES:compose 编排层开关,决定起哪个 transcoder 变体(cpu/vaapi/qsv/nvidia,见部署指南篇 2 节对比表)。改档位后 docker compose up -d 会按 profile 重建。
  • GOCODER_PRESET:ffmpeg x264/x265 preset(ultrafast…veryslow)。默认 fast;官方注释明确「vaapi 硬件档不支持 preset」。
  • GOCODER_HWACCEL:硬件加速类型,由对应 profile 的 compose 覆写注入(nvidia 档 nvidia、vaapi 档 vaapi、qsv 档 qsv),不要手工改。
  • GOCODER_VAAPI_RENDERER / GOCODER_QSV_RENDERER:渲染设备路径,默认 /dev/dri/renderD128(多核显机器可用 ls /dev/dri/ 实查后按设备名指定)。
  • GOCODER_CACHE_ROOT / GOCODER_METADATA_ROOT / GOCODER_SAFE_PATH:transcoder 进程内的缓存/元数据/安全路径基址,容器内固定值,由 compose 的卷挂载对齐(/cache、/metadata),无需改动。

实测当前生效值(transcoder 容器环境):

$ docker compose exec transcoder env | grep GOCODER
GOCODER_PRESET=fast

(cpu 档未注入 HWACCEL 类变量,属预期。)

5.6 扫描与媒体库:LIBRARY_ROOT / LIBRARY_IGNORE_PATTERN / SCANNER_LIBRARY_ROOT

  • LIBRARY_ROOT:compose 用它做宿主媒体目录的 bind mount(${LIBRARY_ROOT}:/video:ro)。相对路径以 docker-compose.yml 所在目录解析(实测 ./video → /opt/kyoo/video)。
  • SCANNER_LIBRARY_ROOT:scanner 进程内实际扫描的容器路径(/video),源码可见;保持挂载点一致即可,不要改。
  • LIBRARY_IGNORE_PATTERN:正则,命中即跳过。默认忽略一切 Downloads 目录;追加倍 sample 关键字的写法:
LIBRARY_IGNORE_PATTERN=.*/[dD]ownloads?/.*|.*/[sS]ample/.*

5.7 数据库连接:PG* 五件套与 POSTGRES_URL

Kyoo 四个业务服务全部使用 libpq 环境变量族连 PostgreSQL(compose 中 postgres 容器用同一组值初始化实例)。五件套默认值与联动关系:

PGUSER=kyoo
PGPASSWORD=password      # 生产环境务必修改(本文示例用 q1w2e3r4)
PGDATABASE=kyoo
PGHOST=postgres          # compose 服务名即容器内主机名
PGPORT=5432
  • POSTGRES_URL:整串连接串优先级最高(auth/scanner 源码可见读取),支持 libpq 全部参数,例如加密连接:postgres://kyoo:密码@postgres:5432/kyoo?sslmode=verify-full&sslrootcert=/path/ca.crt;
  • api 侧还支持 libpq 全集(PGPASSFILE/PGOPTIONS/PGAPPNAME/PGSSLMODE 等,源码 process.env.PG* 枚举实证);
  • compose 的 postgres 服务 healthcheck(pg_isready -U ${PGUSER} -d ${PGDATABASE})与初始化变量(POSTGRES_USER/PASSWORD/DB)都从同一组值派生,改库凭据只需改 .env 一处。

实测验证连通(三 schema 建齐即代表迁移完成):

$ docker exec kyoo-5.2.1-postgres psql -U kyoo -d kyoo -c '\dn'
   Name   |       Owner
---------+-------------------
 gocoder | kyoo
 keibi   | kyoo
 kyoo    | kyoo
 public  | pg_database_owner

5.8 可观测性:OTEL_* 与日志级别

  • OTEL_EXPORTER_OTLP_ENDPOINT / OTEL_EXPORTER_OTLP_PROTOCOL:OpenTelemetry OTLP 上报端点与协议(http/protobuf 或 grpc)。不配置时各服务打印跳过信息——scanner 实测日志原文:[INFO][scanner.otel] OTEL_EXPORTER_OTLP_ENDPOINT not specified, skipping otel provider setup.
  • STDOUT_LOG_LEVEL:auth/scanner 源码可见,控制标准输出日志级别(debug/info/warn/error)。
  • OTEL_SERVICE_NAME / OTEL_LOG_LEVEL:按服务细分的上报名与级别。

家庭部署一般全部留空;要接 Jaeger/Tempo 类后端时按上面两行配置即可。

5.9 密钥路径与杂项

  • RSA_PRIVATE_KEY_PATH:auth 的 JWT 签名私钥路径,首次启动自动生成 RSA 密钥对并落盘;想固定密钥(多实例共享或备份恢复)可挂载文件并指向它。公钥通过 /.well-known/jwks.json 对外发布(实测可访问)。
  • PROFILE_PICTURE_PATH:头像存储路径(容器内 /profile_pictures,与卷对齐)。
  • JWT_SECRET:api 侧的签名校验密钥(compose 注入)。
  • IMAGES_PATH:api 存海报的路径,compose 固定注入 /images(.env 里的 ./images 是宿主侧历史兼容写法)。
  • CAST_APPLICATION_ID:Chromecast 自定义接收器 ID,仅开发调试。
  • KYOO_URL(front 侧):构建期注入的 API 地址,compose 默认 http://api:5000/api。

六、生产配置模板(16GB 内存 / NVMe SSD / 家庭影库 10TB 场景)

适用场景说明:单机家庭部署,媒体 1~5 万文件规模,CPU 软转码为主(无核显直通或未启用),PostgreSQL 与转码缓存同盘 NVMe。以下为完整可用的 .env 模板(凭据类值请按 5.4 节方式自行生成替换):

# ===== 媒体库与存储 =====
LIBRARY_ROOT=/data/media          # 大容量数据盘挂载点
CACHE_ROOT=/data/kyoo-cache       # NVMe:转码缓存
IMAGES_PATH=./images
LIBRARY_IGNORE_PATTERN=.*/[dD]ownloads?/.*|.*/[sS]ample/.*
# ===== 转码 =====
COMPOSE_PROFILES=cpu              # 有 Intel/AMD 核显改 vaapi,N 卡改 nvidia
GOCODER_PRESET=fast               # 软转码建议 fast,硬加速可删
# ===== 对外身份 =====
PUBLIC_URL=https://kyoo.example.com   # 换成真实域名
# ===== 元数据刮削 =====
TVDB_APIKEY=${TVDB_APIKEY}                    # 由部署机环境变量注入,勿入 git
THEMOVIEDB_API_ACCESS_TOKEN=${TMDB_TOKEN}     # 同上
# ===== 账号与权限 =====
EXTRA_CLAIMS='{"permissions": ["core.read", "core.play"], "verified": false}'
FIRST_USER_CLAIMS='{"permissions": ["users.read", "users.write", "users.delete", "apikeys.read", "apikeys.write", "core.read", "core.write", "core.play", "scanner.trigger", "scanner.guess", "scanner.search", "scanner.add"], "verified": true}'
GUEST_CLAIMS=''                   # 家庭内网外全登录(如需游客浏览改回 core.read)
PROTECTED_CLAIMS="permissions,verified"
# ===== 内置 API Key =====
KEIBI_APIKEY_SCANNER=${KEIBI_APIKEY_SCANNER}  # openssl rand -base64 48 生成
KEIBI_APIKEY_SCANNER_CLAIMS='{"permissions": ["core.read", "core.write"]}'
# ===== 数据库 =====
PGUSER=kyoo
PGPASSWORD=${PGPASSWORD}          # openssl rand -base64 24 生成
PGDATABASE=kyoo
PGHOST=postgres
PGPORT=5432
# ===== 可观测(可选) =====
# OTEL_EXPORTER_OTLP_ENDPOINT=http://otel-collector:4317
# OTEL_EXPORTER_OTLP_PROTOCOL=http/protobuf

模板要点解说:

  1. 密钥类(TVDB/TMDB/KEIBI/PGPASSWORD)用 ${VAR} 形态声明、由部署机受控注入(systemd 环境/Docker 秘密管理),.env 本体即可安全纳入版本管理;生成命令 openssl rand -base64 48;
  2. PUBLIC_URL 换域名后必须 docker compose up -d --force-recreate auth api;
  3. 16GB 内存下软转码单路 1080p 无压力;transcoder 是内存大头(ffmpeg 预读),多并发观看建议 32GB 或启用核显档。

七、常见问题

7.1 Q1:改了 .env 但不生效

根因:环境变量在容器创建时固化,docker compose restart 只是重启进程、不会重读 env。解决:docker compose up -d --force-recreate <服务>(重建容器才会重新注入)。验证生效:docker compose exec <服务> env | grep <变量名>。

7.2 Q2:claims 类变量写错导致服务起不来

现象(实测口径):auth 容器反复退出,日志含 claims 解析错误(源码 config.go 解析失败即 return nil, err)。

解决:用 python3 -m json.tool 校验 JSON,注意单引号包裹(防止 shell 吃掉双引号),KEIBI_APIKEY_<名>_CLAIMS 与主键必须成对出现(缺失对应 CLAIMS 变量时启动报 missing claims env var)。

7.3 Q3:改端口后一直跳转旧地址或登录失效

根因:PUBLIC_URL(JWT issuer)与实际访问地址不一致。解决:改 PUBLIC_URL 后重建 auth 与 api(见 5.1),浏览器清缓存重登。

7.4 Q4:KEIBI_APIKEY_ 前缀变量只写了 key 没写 CLAIMS

现象:auth 启动失败。根因:源码要求成对(缺失即 missing claims env var KEIBI_APIKEY_%s_CLAIMS)。解决:补上同名 _CLAIMS JSON。

7.5 Q5:TVDB_APIKEY 留空,scanner 依然要连外网吗

是。源码 thetvdb.py 的 DEFAULT_API_KEY 兜底意味着留空也会在启动期请求 api4.thetvdb.com,内网环境 scanner 无法存活(完整排障实录见《Kyoo 5.2.1 Docker Compose 部署指南》9.1)。自备 Key 只改变身份,不改变「启动期需联网」这一行为。

八、参考链接