ZITADEL v4.19.5 配置参数详解

ZITADEL v4.19.5 配置参数详解:defaults.yaml/--config 文件/环境变量/命令行 flag 四级来源与优先级实测(逐键合并验证)、CLI 子命令与 start flag 全集、ExternalDomain/ExternalPort/ExternalSecure 三件套与 Host 路由实验、日志级别与 DSN 口令错误实录、DefaultInstance 初始化参数、Masterkey 与缓存/Login UI 参数,全部回显来自 2026-10-18 实测。

ZITADELZITADELIAMOIDC2026/10/18

ZITADEL v4.19.5 配置参数详解

目标:逐项讲清 ZITADEL v4.19.5 的配置体系——四个配置来源与优先级、命令行子命令与 flag、服务网络/外部视角三件套、日志级别、数据库 DSN、首次初始化与默认实例、加密主密钥、缓存与登录 UI 参数,每个关键参数配 2026-10-18 的真实实验回显。参数的部署组合背景见《ZITADEL Docker Compose 部署指南》,调 API 验证配置效果见《ZITADEL v4.19.5 API 使用详解》。

一、环境信息

项目值
服务器(容器模拟真实服务器)IP 192.168.146.128,主机名 ops,网卡 ens33(出口路由验证 ip route get 192.168.1.62 → via 192.168.146.2 dev ens33)
操作系统Ubuntu 22.04.4 LTS(内核 6.8.0-138-generic)
ZITADEL 版本v4.19.5(2026-10-18 GitHub Releases 确认的最新稳定版,镜像 ghcr.io/zitadel/zitadel:v4.19.5)
运行栈《ZITADEL Docker Compose 部署指南》部署的持久实例:Traefik 8113→80 → API 8080 + Login 3000 → PostgreSQL 17.10,网络 zitadel(10.89.38.0/24)
实验用辅助实例zt-config-test(端口 18113)、zt-config-test2(端口 18114):共享 zitadel 网络与主库、独立进程,用于 config 文件与环境变量优先级实验,容器按规范保留
实验数据源镜像内 /app/zitadel 二进制 --help 实测输出;官方 v4.19.5 cmd/defaults.yaml(全 1562 行,本篇所有「默认值」均注明其行号区间)
初始管理员admin / q1w2e3r4(登录名 admin@zitadel.localhost)
Masterkey实验值 q1w2e3r4q1w2e3r4q1w2e3r4q1w2e3r4(32 字符,生产必须换)

本篇实测约定:所有 docker run/docker compose 命令仅用于复现实验;对运行中的主栈只做「改环境变量 → 重启容器 → 验证 → 还原」的闭环,不改数据库内容。

二、配置体系总览

2.1 四个配置来源与优先级

ZITADEL 的配置收敛顺序(从低到高,全部经 2026-10-18 实测验证):

优先级来源说明实测证据
0defaults.yaml(内置默认)编译进二进制的全量默认值,1562 行,是所有参数的「最终兜底」官方 v4.19.5 源码 cmd/defaults.yaml,不改配置时 Log.Level、Port 等全部取此值
1--config 配置文件--config /path/config.yaml,可多次出现(先加载后覆盖)2.5 节实验:文件里 Port: 8081 生效,18113 端口 healthz 200
2环境变量ZITADEL_ 前缀 + 参数路径大写下划线化,逐条覆盖同名配置键2.5 节实验:env ZITADEL_PORT=8082 压过文件 Port: 8081,进程监听 8082
3命令行 flag--tlsMode、--masterkey 等,帮助文本明示会覆盖配置文件start --help 原文:"this flag will overwrite externalSecure and tls.enabled in configs files"

💡 与常见 Go 服务的差异:viper 类框架通常是「env 整体优先」;ZITADEL 是逐键合并——env 只覆盖它声明的那个键,文件里其余键仍然生效。所以「文件里写好全量配置、env 只做个别覆写」是官方推荐姿势(官方 compose 正是这么做的:defaults.yaml 兜底 + env 只传 20 来个关键键)。

2.2 环境变量命名规则

  • 规则:ZITADEL_ + 配置路径段大写、以 _ 连接。例如 defaults.yaml 的 Log.Level → ZITADEL_LOG_LEVEL;DefaultInstance.Org.Human.UserName → ZITADEL_DEFAULTINSTANCE_ORG_HUMAN_USERNAME(defaults.yaml 每行行尾注释都标了对应 env 名,查 env 名直接看这个文件最快)。
  • 双前缀兼容:defaults.yaml 的顶层段叫 DefaultInstance(对应 ZITADEL_DEFAULTINSTANCE_*),但官方 compose 与文档大量使用 ZITADEL_FIRSTINSTANCE_*。实测两者都生效(部署实录:ZITADEL_FIRSTINSTANCE_ORG_HUMAN_USERNAME 成功把初始用户从默认 zitadel-admin 改成 admin;ZITADEL_DEFAULTINSTANCE_PASSWORDCOMPLEXITYPOLICY_* 成功改写了初始密码策略),新部署建议统一用 DEFAULTINSTANCE_ 前缀与当前源码保持一致。
  • 非 ZITADEL_ 前缀的例外:Login UI(Next.js 服务)的变量不带该前缀,如 ZITADEL_API_URL、NEXT_PUBLIC_BASE_PATH、ZITADEL_SESSION_COOKIE_SECRET——它们作用于 login 容器进程,见第八章。

2.3 defaults.yaml 关键段索引

全文 1562 行的顶层段(grep ^[A-Z] 实查):

段作用行号(v4.19.5)
Log日志级别与格式1-16
Port / ExternalPort / ExternalDomain / ExternalSecure / TLS / InstanceHostHeaders网络与外部视角18-30 附近
Database数据库连接(当前仅 postgres 子段)40-130 附近
EncryptionKeys库内敏感字段加密密钥配置中段
OIDC / SAML协议端默认(token 生命周期等)649-720 附近
DefaultInstance首实例全量:组织/管理员/策略/特性1145-1562
SystemAPI / Login / Caches / Telemetry / Projections 等各子系统分散

2.4 配置文件怎么找

生产部署写自定义 config.yaml 时无需从零手写:官方仓库 cmd/defaults.yaml 就是全量注释模板(本篇引用即此文件),本地起步做法是下载后只改需要覆盖的键:

curl -x http://192.168.1.62:7897 -fsSLO \
  https://raw.githubusercontent.com/zitadel/zitadel/v4.19.5/cmd/defaults.yaml

(实测 200,1562 行。)运行时给 start --config ./defaults.yaml --config ./my-overrides.yaml 即可叠多个文件。

三、命令行与子命令

3.1 顶层命令与版本

docker run --rm ghcr.io/zitadel/zitadel:v4.19.5 --help

实测回显(全文照抄):

 _____  ___   _____      _      ____    _____   _
/ ____|/ _ \ |  __ \    / \    |  _ \ / ____| | |
| |    | |_| | |  | |  / _ \   | |_) | |      | |
| |___ |  _  | |  | | / ___ \  |  _ <| |____  | |____
 \_____|_| |_|_|  |_|/_/   \_\ |_| \_\\_____| |______|

Civilized Microservice Wizard

Usage:
  zitadel [command]

Available Commands:
  completion        Generate the autocompletion script for the specified shell
  help              Help about any command
  init              Initialize ZITADEL
  keys              Manage keys
  mirror            Mirrors the instance
  ready             Checks if ZITADEL is ready
  start             Starts ZITADEL
  start-from-init   Starts ZITADEL with the first instance initialized
  version           Print the version of ZITADEL

Flags:
      --config strings   path to config file to overwrite the default configuration
  -h, --help             help for zitadel
      --masterkey string masterkey for encrypting and decrypting (use at your own risk)
      --masterkeyFile string path to file with the masterkey in it (use at your own risk)
      --token string     path to token file for service account (used by mirror, ready and start commands)

Use "zitadel [command] --help" for more information about a command.

注:banner 字符块为照抄原文;中文注释行为本篇添加。版本输出(version 子命令)在 --help 尾部亦有版本行:zitadel version v4.19.5 (CLI)——与镜像 tag 一致。

六个业务子命令职责速查:

子命令职责典型用法
init只做初始化(建表/首实例),不启动服务预配置镜像场景
start启动服务(库必须已初始化)常规运行
start-from-init初始化 + 启动一步到位(幂等)官方 compose 默认
setup执行 schema/steps 迁移升级后手动补迁移
mirror实例间数据镜像(SaaS 分发)--system-auth-token 场景
ready探活(compose healthcheck 内部即 /app/zitadel ready)健康检查
keys密钥管理keys generate --cert ... 自签 TLS 证书

3.2 start 子命令的 flag 全集

docker run --rm ghcr.io/zitadel/zitadel:v4.19.5 start --help

实测回显(照抄 flags 段):

Flags:
      --config strings                 path to config file to overwrite the default configuration
  -h, --help                           help for zitadel
      --masterkey string               masterkey for encrypting and decrypting (use at your own risk)
      --masterkeyFile string           path to file with the masterkey in it (use at your own risk)
      --token string                   path to token file for service account (used by mirror, ready and start commands)
      --port uint16                    port to bind addr to (default: 8080)
      --externalPort uint16            external port ZITADEL will be exposed (default: 8080)
      --externalDomain string          domain ZITADEL will be exposed
      --externalSecure                 ZITADEL will be exposed on https
      --tlsMode string                 toggle TLS mode (0=disabled, 1=external, 2=enabled), this flag will overwrite externalSecure and tls.enabled in configs files (default: "0")
      --multiInstance                  start multi instance (default: false)
      --initBackend                    starts ZITADEL and initializes a backend database (default: false)

要点:--tlsMode 的数字语义(0/1/2)只在这里给全;它同时覆盖 ExternalSecure 与 TLS.Enabled 两个配置键——命令行优先级最高的直接体现。

四、服务网络与外部视角参数

4.1 参数组定义

这一组是 ZITADEL 最「反直觉」也最重要的配置:进程监听端口与对外呈现地址是解耦的。

参数defaults.yaml 键env默认值作用
监听端口PortZITADEL_PORT8080进程实际 bind 的端口(容器内固定 8080)
对外端口ExternalPortZITADEL_EXTERNALPORT8080签发 issuer/redirect 时使用的端口
对外域名ExternalDomainZITADEL_EXTERNALDOMAINlocalhost实例注册域名,必须与请求 Host 头一致
对外协议ExternalSecureZITADEL_EXTERNALSECUREtruetrue 时签发 https:// 的 URL
进程 TLSTLS.Enabled 等ZITADEL_TLS_ENABLEDtrue进程内是否直接终结 TLS(默认要求证书)
实例路由头InstanceHostHeadersZITADEL_INSTANCEHOSTHEADERS空多实例时从哪些请求头取路由域名

部署实录(《ZITADEL Docker Compose 部署指南》第七章)已经给出「三件套一致」的正面效果:.env 里 ZITADEL_DOMAIN=localhost / ZITADEL_EXTERNALPORT=8113 / ZITADEL_EXTERNALSECURE=false,签发的 discovery 就是:

"issuer": "http://localhost:8113"

(实测回显,scheme/http + 域名/localhost + 端口/8113 三者全对上。)

4.2 优先级实验:环境变量 > 配置文件

构造一个只改 Port 与 Log.Level 的 config 文件:

Port: 8081
Log:
  Level: debug

实验 A——只用文件(挂载 /config.yaml,映射宿主 18113→容器 8081):

docker run -d --name zt-config-test --network zitadel -p 18113:8081 \
  -v /tmp/zitadel-test-config.yaml:/config.yaml:ro \
  -e ZITADEL_DATABASE_POSTGRES_DSN='postgresql://postgres:postgres@postgres:5432/zitadel?sslmode=disable' \
  ghcr.io/zitadel/zitadel:v4.19.5 start \
  --masterkey q1w2e3r4q1w2e3r4q1w2e3r4q1w2e3r4 --config /config.yaml \
  --tlsMode disabled --externalDomain localhost --externalPort 8113

实测回显:

time=2026-10-18T14:47:12.621Z level=INFO msg="structured logger configured" config_level=DEBUG format=text
  _____  ___   _____      _      ____    _____   _
ok HTTP 200        # curl http://localhost:18113/debug/healthz

文件里的 Port: 8081(监听 8081,宿主 18113 探活 200)与 Log.Level: debug(日志 config_level=DEBUG)同时生效,证明 config 文件覆盖内置默认。

实验 B——文件之上再压环境变量(ZITADEL_PORT=8082,映射 18114→8082,config 文件不变仍是 8081):

docker run -d --name zt-config-test2 --network zitadel -p 18114:8082 \
  -v /tmp/zitadel-test-config.yaml:/config.yaml:ro \
  -e ZITADEL_PORT=8082 \
  -e ZITADEL_DATABASE_POSTGRES_DSN='postgresql://postgres:postgres@postgres:5432/zitadel?sslmode=disable' \
  ghcr.io/zitadel/zitadel:v4.19.5 start \
  --masterkey q1w2e3r4q1w2e3r4q1w2e3r4q1w2e3r4 --config /config.yaml \
  --tlsMode disabled --externalDomain localhost --externalPort 8113

实测回显:

ok HTTP 200        # curl http://localhost:18114/debug/healthz → env 的 8082 生效
time=2026-10-18T14:47:29.746Z level=INFO msg="server is listening" stream=runtime version=v4.19.5 address=[::]:8082

结论:环境变量优先于 config 文件(监听端口随 env 变成 8082),而文件里未被 env 覆盖的 Log.Level: debug 仍生效(该实例日志同样 config_level=DEBUG)——逐键合并行为得到直接验证。

4.3 ExternalDomain 与 Host 头(错误配置行为实录)

ExternalDomain 参与实例路由:请求 Host 头必须与注册域名一致,否则 404。用未注册域名直打 API 容器(绕过反代)复现:

docker run --rm --network zitadel curlimages/curl -s \
  -H "Host: unregistered.example.com" \
  http://zitadel-api:8080/.well-known/openid-configuration -w "\nHTTP %{http_code}\n"

实测回显:

unable to set instance using origin &{unregistered.example.com  http} (ExternalDomain is localhost): ID=QUERY-1kIjX Message=Instance not found. Make sure you got the domain right. Check out https://zitadel.com/docs/apis/introduction#domains

HTTP 404

排障结论:改 ExternalDomain 只影响新请求的路由与已签发 URL 的展示;已初始化实例的域名注册在库中,运行中改 env 不会让旧域名消失(也不会自动加新域名),变更域名要用管理 API 的 Domain 接口或重置实例。

五、日志与可观测性参数

5.1 Log 段

defaults.yaml 第 1-16 行(默认值原文):

Log:
  Level: info # ZITADEL_LOG_LEVEL
  Formatter:
    Format: text # ZITADEL_LOG_FORMATTER_FORMAT

可选 Level:debug、info、warn、error;Formatter.Format 可选 text/json(生产接日志平台建议 json)。日志为 slog 结构化格式,每行自带 level=/msg=/stream= version= 字段。

实验:运行中把主栈日志调到 debug(overlay 注入 ZITADEL_LOG_LEVEL: debug 后 up -d --wait 滚动重建 api 容器):

docker logs --since 1m zitadel-v4-19-5-api 2>&1 | grep -c "level=DEBUG"

实测回显:2,样本行:

time=2026-10-18T14:46:46.966Z level=INFO msg="structured logger configured" config_level=DEBUG format=text
time=2026-10-18T14:46:47.138Z level=DEBUG msg="trigger iteration" stream=runtime version=v4.19.5 name=repeatable_fill_fields_for_instance_domains iteration=0

第一行是「配置自证」:config_level=DEBUG 表示新级别已被加载;第二行显示 DEBUG 级别下能看到投影触发器(repeatable_*)这类内部细节——排查投影不更新时非常有用。实验后还原为默认 info(不做还原会把事件流日志刷屏)。

5.2 Instrumentation / Telemetry(转述默认值)

defaults.yaml 相关默认(查询日实查其行尾 env 注释):Instrumentation.ServiceName: zitadel-api、trace exporter type 默认 none、Telemetry.Enabled: true(匿名使用统计上报,自托管可通过 ZITADEL_TELEMETRY_ENABLED=false 关闭)。官方 compose 未传 Telemetry 变量——内网部署建议显式关闭。

六、数据库连接参数

6.1 两种写法

Database.postgres 段支持两种互斥写法(二选一):

写法一:DSN 单串(官方 compose 采用)

ZITADEL_DATABASE_POSTGRES_DSN=postgresql://postgres:postgres@postgres:5432/zitadel?sslmode=disable

DSN 格式:postgresql://<user>:<password>@<host>:<port>/<database>?<options>。常用 options:sslmode(disable/require/verify-full,生产建议 verify-full)、pool_max_conns(连接池上限)。

写法二:分字段(defaults.yaml 42-60 行原文,键名照抄)

  postgres:
    Host: localhost # ZITADEL_DATABASE_POSTGRES_HOST
    Port: 5432 # ZITADEL_DATABASE_POSTGRES_PORT
    Database: zitadel # ZITADEL_DATABASE_POSTGRES_DATABASE
    MaxOpenConns: 5 # ZITADEL_DATABASE_POSTGRES_MAXOPENCONNS
    MaxIdleConns: 5 # ZITADEL_DATABASE_POSTGRES_MAXIDLECONNS
    MaxConnLifetime: 1h # ZITADEL_DATABASE_POSTGRES_MAXCONNLIFETIME
    MaxConnIdleTime: 5m # ZITADEL_DATABASE_POSTGRES_MAXCONNIDLETIME
    Options: # ZITADEL_DATABASE_POSTGRES_OPTIONS
    User:
      Username: zitadel # ZITADEL_DATABASE_POSTGRES_USER_USERNAME
      Password: # ZITADEL_DATABASE_POSTGRES_USER_PASSWORD
      SSL:
        Mode: disable # ZITADEL_DATABASE_POSTGRES_USER_SSL_MODE
        RootCert: # ZITADEL_DATABASE_POSTGRES_USER_SSL_ROOTCERT
        Cert: # ZITADEL_DATABASE_POSTGRES_USER_SSL_CERT
        Key: # ZITADEL_DATABASE_POSTGRES_USER_SSL_KEY
    Admin:
      Username: postgres # ZITADEL_DATABASE_POSTGRES_ADMIN_USERNAME
      Password: # ZITADEL_DATABASE_POSTGRES_ADMIN_PASSWORD
      SSL:
        Mode: disable # ZITADEL_DATABASE_POSTGRES_ADMIN_SSL_MODE
        ...

要点:分字段模式下有两套凭据——User(应用运行账号)与 Admin(初始化/迁移用的管理员账号);官方 .env.example 注释强调「DSN 指定的用户必须已存在,进程不会创建用户」。默认值 Host=localhost/Port=5432,容器部署必须显式给 DSN 或覆盖 Host。

6.2 错误口令实验

DSN 口令错误时的启动失败(实测原文,docker run 一条带错 DSN 的 start):

Error: cannot start DB client for queries: failed to connect to `user=postgres database=zitadel`: 10.89.38.2:5432 (postgres): failed SASL auth: FATAL: password authentication failed for user "postgres" (SQLSTATE 28P01)

排障信息量:报错回显了 DSN 解析结果(user/database/host:port),SQLSTATE 28P01 是 PG 标准的口令错误码;连接目标 IP 10.89.38.2 即 postgres 容器——网络通、认证失败,改 DSN 口令即可。若错误是 no such host 则是主机名错(FAQ 同源问题:容器名必须与网络别名一致)。

七、首次初始化与默认实例参数(DefaultInstance)

DefaultInstance 段(defaults.yaml 1145-1562 行)定义首实例初始化时写入库的整套默认:组织名、管理员账号、各策略、特性开关。它只在首次初始化生效(实例化之后走管理 API 改),这是排查「改了配置没效果」的头号知识点。

7.1 初始管理员(DefaultInstance.Org.Human.*)

defaults.yaml 1155-1172 行默认值(照抄关键键):

    Human:
      # for example zitadel-admin in org `My Org` on domain.tld -> zitadel-admin@my-org.domain.tld
      UserName: zitadel-admin # ZITADEL_DEFAULTINSTANCE_ORG_HUMAN_USERNAME
      FirstName: ZITADEL # ZITADEL_DEFAULTINSTANCE_ORG_HUMAN_FIRSTNAME
      LastName: Admin # ZITADEL_DEFAULTINSTANCE_ORG_HUMAN_LASTNAME
      Email:
        Address: # ZITADEL_DEFAULTINSTANCE_ORG_HUMAN_EMAIL_ADDRESS
        Verified: false # ZITADEL_DEFAULTINSTANCE_ORG_HUMAN_EMAIL_VERIFIED
      Password: # ZITADEL_DEFAULTINSTANCE_ORG_HUMAN_PASSWORD

默认产出:登录名 zitadel-admin@zitadel.localhost、显示名 ZITADEL Admin、密码未设(首次登录需走初始化流程)。本系列部署实测改为 admin/q1w2e3r4 + 邮箱已验证(overlay 的六个 env),最终库内登录名集合:

 admin@zitadel.localhost
 login-client

(psql SELECT login_name FROM projections.login_names3; 实测回显——login-client 是官方 compose 的 FirstInstance.LoginClient 固定动作创建的机器账号,供 Login UI 使用。)

另有两个 compose 级开关(defaults.yaml 对应键为 FirstInstance.Org.Human.PasswordChangeRequired,部署篇已验证):PasswordChangeRequired: false 取消首登强制改密;LoginClientPatPath: /zitadel/bootstrap/login-client.pat 决定 login-client PAT 的落盘位置。

7.2 初始密码策略(PasswordComplexityPolicy)

defaults.yaml 1269-1274 行默认值(照抄):

  PasswordComplexityPolicy:
    MinLength: 8 # ZITADEL_DEFAULTINSTANCE_PASSWORDCOMPLEXITYPOLICY_MINLENGTH
    HasLowercase: true # ZITADEL_DEFAULTINSTANCE_PASSWORDCOMPLEXITYPOLICY_HASLOWERCASE
    HasUppercase: true # ZITADEL_DEFAULTINSTANCE_PASSWORDCOMPLEXITYPOLICY_HASUPPERCASE
    HasNumber: true # ZITADEL_DEFAULTINSTANCE_PASSWORDCOMPLEXITYPOLICY_HASNUMBER
    HasSymbol: true # ZITADEL_DEFAULTINSTANCE_PASSWORDCOMPLEXITYPOLICY_HASSYMBOL

默认要求 8 位+小写+大写+数字+符号。部署篇实测:直接用 q1w2e3r4(无大写无符号)初始化会失败,必须同时给两个开关:

ZITADEL_DEFAULTINSTANCE_PASSWORDCOMPLEXITYPOLICY_HASUPPERCASE: "false"
ZITADEL_DEFAULTINSTANCE_PASSWORDCOMPLEXITYPOLICY_HASSYMBOL: "false"

💡 技术拓展:密码策略属于「实例级持久配置」——初始化时落库,之后在 Console(Organizations → Policies)或管理 API(/management/v1/policies/password/complexity)调整。与密码/口令持久化相关的通用对比:

方案原理要点
明文存储口令原样入库任何泄露即全量失守,禁用
可逆加密可解密还原需要还原明文(如代填表单)才考虑,密钥管理复杂
单向哈希只存摘要(如 bcrypt/argon2id)业界标准;验证时重新哈希比对
加盐哈希每口令随机盐 + 慢哈希抗彩虹表/离线爆破,ZITADEL 属此列

ZITADEL 采用加盐慢哈希存储口令,配合 MinLength/字符类策略与 PasswordAgePolicy(过期提醒天数,默认 0=不过期)构成纵深防御。

7.3 特性开关与 OIDC 默认(Features / OIDC)

defaults.yaml 1480 行起 Features.LoginV2.Required: true——v4 起标准 OIDC 授权跳转强制走 Login V2。这正是部署篇结论「只有 API 容器没有 Login 容器时 /ui/v2/login 404、完整流程不可用」的配置根源;纯 API 用法需在实例特性里关掉该开关。相关三个 URL 模板(官方 compose 已注入完整外部地址):

OIDC:
  DefaultLoginURLV2: "/ui/v2/login/login?authRequest=" # ZITADEL_OIDC_DEFAULTLOGINURLV2
SAML:
  DefaultLoginURLV2: "/ui/v2/login/login?samlRequest=" # ZITADEL_SAML_DEFAULTLOGINURLV2

OIDC 令牌生命周期默认(649-668 行,照抄注释齐全的原文):

  # !!! Changing this after the initial setup will have no impact without a restart !!!
  DefaultAccessTokenLifetime: 12h # ZITADEL_OIDC_DEFAULTACCESSTOKENLIFETIME
  DefaultIdTokenLifetime: 12h # ZITADEL_OIDC_DEFAULTIDTOKENLIFETIME
  # 720h are 30 days, one month
  DefaultRefreshTokenIdleExpiration: 720h # ZITADEL_OIDC_DEFAULTREFRESHTOKENIDLEEXPIRATION
  # 2160h are 90 days, three months
  DefaultRefreshTokenExpiration: 2160h # ZITADEL_OIDC_DEFAULTREFRESHTOKENEXPIRATION

注意源码注释的自我提醒:这类 OIDC 默认改配置后必须重启才生效(与 DefaultInstance 段「初始化后落库」的机制不同——前者是进程行为,后者是实例事件)。token 生命周期的实测效果见《ZITADEL v4.19.5 API 使用详解》。

八、加密主密钥(Masterkey)与 EncryptionKeys

8.1 Masterkey 三种提供方式

启动必填,start --help 与实测错误(FAQ 原文)双向印证:

Error: no master key provided: masterkey must either be provided by file path, value or environment variable
方式写法适用
明文参数--masterkey <32字符> 或 env ZITADEL_MASTERKEY实验/内网,进程参数可见需注意
文件--masterkeyFile /run/secrets/zitadel-masterkey生产,配合 secrets 管理
环境变量ZITADEL_MASTERKEY官方 compose 采用

硬约束:恰好 32 字符(不足报 MasterkeyNeedsToHave32Characters 类错误),首次初始化后不可更换(库内字段以其加密,更换即数据不可解)。丢失即失能——务必入密管并做多份离线备份。

8.2 EncryptionKeys 段(转述)

defaults.yaml 中段定义了每类敏感字段各自的加密密钥配置(EncryptionKeys:用户密钥、OIDC 密钥、SAML 密钥、域验证密钥等),默认全部派生自 masterkey(Type: encryption 指向主密钥)。多副本部署时所有副本 masterkey 必须一致;轮换属高级操作(需 keys 子命令与迁移步骤)。

九、缓存与可选组件参数(Caches / Redis / Login UI)

9.1 Caches 段与 Redis 连接

defaults.yaml 中 Caches 支持多连接器(内存/Redis),对应官方 compose 的五个变量(本部署 .env 取值):

ZITADEL_CACHES_CONNECTORS_REDIS_ENABLED=false   # 是否启用 Redis 缓存连接器
ZITADEL_CACHES_CONNECTORS_REDIS_URL=redis://redis:6379/0
ZITADEL_CACHES_INSTANCE_CONNECTOR=              # 实例缓存用哪个连接器(memory/redis)
ZITADEL_CACHES_MILESTONES_CONNECTOR=
ZITADEL_CACHES_ORGANIZATION_CONNECTOR=

默认(官方 .env.example 同值)全部走进程内 memory 连接器,Redis 属可选优化(compose 里 redis 服务在 cache profile 下,默认不启动)。水平扩展多 API 副本时才建议切 Redis(保证实例缓存一致性)。

9.2 Login UI(Next.js)相关参数

Login 容器的关键变量(非 ZITADEL_ 前缀,官方 compose 原文语义):

变量本部署取值说明
ZITADEL_API_URLhttp://zitadel-api:8080Login 调 API 的内网地址
NEXT_PUBLIC_BASE_PATH/ui/v2/login对外路径前缀(与 Traefik label 对应)
ZITADEL_SERVICE_USER_TOKEN_FILE/zitadel/bootstrap/login-client.pat服务凭证(只读挂载 bootstrap 卷)
ZITADEL_SESSION_COOKIE_SECRET32+ 字符测试值登录会话 Cookie 签名密钥,生产必须换
CUSTOM_REQUEST_HEADERSHost:localhost,X-Forwarded-Proto:http传给 API 的视角头(与三件套联动)

十、本地 HTTP 部署最小配置清单

把全篇收敛成一张「内网 HTTP 试用」最小组合(均为本系列实测生效值):

# ── 外部视角三件套(必须与真实访问入口一致)──
ZITADEL_DOMAIN=localhost              # 请求 Host 头必须等于它
ZITADEL_EXTERNALPORT=8113             # 对外端口(issuer 会带上)
ZITADEL_EXTERNALSECURE=false          # 签发 http:// URL
ZITADEL_TLS_ENABLED=false             # 进程不终结 TLS(等价 --tlsMode disabled)

# ── 数据库(DSN 单串即可,用户必须已存在)──
ZITADEL_DATABASE_POSTGRES_DSN=postgresql://postgres:postgres@postgres:5432/zitadel?sslmode=disable

# ── 初始化一次性参数(仅首启生效,初始化后改了没用)──
ZITADEL_MASTERKEY=<恰好32字符>                       # 初始化后不可换
ZITADEL_FIRSTINSTANCE_ORG_HUMAN_USERNAME=admin      # 初始管理员
ZITADEL_FIRSTINSTANCE_ORG_HUMAN_PASSWORD=q1w2e3r4   # 配合下方两个策略开关
ZITADEL_DEFAULTINSTANCE_PASSWORDCOMPLEXITYPOLICY_HASUPPERCASE=false
ZITADEL_DEFAULTINSTANCE_PASSWORDCOMPLEXITYPOLICY_HASSYMBOL=false

# ── 建议关闭(内网自托管)──
ZITADEL_TELEMETRY_ENABLED=false       # 匿名统计上报

三条铁律(全部有实测佐证):

  1. 对外三件套改在初始化前:域名/端口参与 issuer 签发与实例路由,初始化后中途改需处理库内域名与已签发 URL;
  2. DefaultInstance/FirstInstance 参数只在首启生效:后续走 Console 或管理 API(两层机制的差异见第七章);
  3. env 与文件是逐键合并:文件写全量、env 做个别覆写是最可控的姿势(第四章实验验证)。

参考链接