启动、配置与事实来源
这一页解决一个很容易混淆的问题:改了环境变量、管理后台或数据库后,Sub2API 到底会听谁的,以及改动什么时候生效。
先记住三个结论:
ADMIN_EMAIL和ADMIN_PASSWORD只用于首次创建管理员,不是持续覆盖数据库的登录配置。- PostgreSQL 是用户、账号、分组、订单和后台设置等业务数据的事实来源。
- YAML/环境变量主要控制进程启动和基础设施;Redis 与进程内存保存缓存、锁、并发和临时状态。
启动状态机
入口位于 backend/cmd/server/main.go,启动路径不是始终相同:
server --version ───────────────▶ 输出版本后退出
server --setup ─────────────────▶ CLI 设置向导
普通启动
├─ NeedsSetup = true
│ ├─ AUTO_SETUP=true ──────▶ 从环境变量自动安装 ─▶ 正常服务
│ └─ AUTO_SETUP=false ─────▶ Web 设置服务 ──────▶ 安装后重启
└─ NeedsSetup = false ────────▶ 加载完整配置 ──────▶ 正常服务NeedsSetup() 只检查数据目录中的两个本地文件:
config.yaml是否存在。.installed安装锁是否存在。
只要其中任意一个存在,系统就不会重新进入初始化。它不会仅凭“数据库里已有用户”判断已安装。
这意味着生产环境必须持久化 DATA_DIR。如果应用数据卷丢失,但仍连接原来的 PostgreSQL,实例会重新走安装流程;代码会因为数据库已有用户而跳过管理员创建,但仍可能重写本地配置。固定的 JWT_SECRET 也必须由部署系统保存,不能依赖每次自动生成。
Auto Setup 实际做什么
AUTO_SETUP=true 时,backend/internal/setup/setup.go 会依次:
- 从环境变量组装 PostgreSQL、Redis、管理员、Server、JWT 和时区配置。
- 测试 PostgreSQL;目标数据库不存在时尝试创建。
- 测试 Redis。
- 执行数据库迁移。
- 判断是否需要创建管理员。
- 写入权限为
0600的config.yaml。 - 写入权限为
0400的.installed。 - 继续启动正式服务。
管理员创建还有额外保护:
| 数据库状态 | 结果 |
|---|---|
| 没有任何用户,也没有管理员 | 创建 ADMIN_EMAIL 对应的管理员 |
| 已有管理员 | 跳过管理员初始化 |
| 已有普通用户但没有管理员 | 为避免覆盖既有数据,仍跳过自动创建 |
ADMIN_PASSWORD 为空时,安装过程生成一次性随机密码并输出到启动日志。该密码不会再次显示。
为什么改 ADMIN_PASSWORD 不能重置密码
登录路径读取 users.password_hash,使用 bcrypt 校验用户提交的密码。初始化完成后:
ADMIN_PASSWORD 环境变量
│
└─ 仅首次安装时参与 SetPassword()
│
▼
users.password_hash(PostgreSQL)
│
▼
后续每次登录因此重启容器或修改平台变量不会更新现有管理员。正常方式是在后台修改密码或执行受控的数据库恢复操作。密码变更会改变 JWT 的 token version 指纹,使旧访问令牌失效。
排查登录时至少确认:
SELECT id, email, role, status, deleted_at
FROM users
WHERE role = 'admin';不要把环境变量里显示的明文当成当前登录密码,也不要把明文密码直接写入 password_hash。
启动配置优先级
正常配置由 Viper 加载,优先级是:
环境变量
↓ 覆盖
config.yaml
↓ 覆盖
程序默认值环境变量名由配置路径转成大写并用下划线连接,例如:
database.max_open_conns → DATABASE_MAX_OPEN_CONNS
gateway.max_body_size → GATEWAY_MAX_BODY_SIZE
jwt.secret → JWT_SECRET配置文件按以下目录查找:
DATA_DIR指定目录。/app/data。- 当前目录。
./config。/etc/sub2api。
这里的“环境变量覆盖 YAML”只针对同一个启动配置键。它不代表环境变量可以覆盖 PostgreSQL 中的用户、账号或订单。
五类状态分别归谁
| 状态类型 | 事实来源 | 示例 | 丢失/修改后的行为 |
|---|---|---|---|
| 进程启动配置 | 环境变量或 config.yaml | DB 地址、Redis、JWT、连接池、超时 | 多数需要重启进程 |
| 持久业务数据 | PostgreSQL 业务表 | 用户、密码哈希、账号、分组、订单、用量 | 页面和网关最终都以 DB 为准 |
| 动态系统设置 | PostgreSQL settings | 注册、支付、站点、OAuth、调度策略 | 部分按请求读取,部分刷新本地缓存 |
| 分布式运行状态 | Redis | 并发、限流、粘性、刷新锁、队列 | 通常有 TTL,可重建性因功能而异 |
| 单实例运行状态 | 进程内存 | L1 缓存、HTTP/WS 连接池、worker 队列 | 重启后丢失并重建 |
本地 data/ 还可能保存配置、定价文件、日志和自定义模板。它不是 PostgreSQL 的替代品,但仍属于备份范围。
管理后台设置怎样生效
管理后台的系统设置由 SettingService 写入 PostgreSQL,而不是反写 .env 或 YAML。更新成功后,服务会刷新若干当前进程缓存,并触发前端 HTML 配置缓存、CSP frame source 等本地回调。
不同设置的读取方式不同:
- 一些功能在请求时直接读取
settings。 - 一些设置有 TTL 缓存或 singleflight。
- 少数设置会同步更新当前进程的原子值。
- 支付 Provider Registry、Web Search Manager 等对象需要显式重建。
所以不能笼统地说“后台保存后所有副本立刻生效”。单实例通常立即或在下一次读取生效;多实例必须确认该设置是否有共享失效机制、TTL 或重启要求。高风险支付、鉴权和调度设置变更后,应逐副本验证。
改哪里最合适
| 需求 | 正确入口 | 是否重启 |
|---|---|---|
| 修改数据库/Redis 地址 | 部署环境变量或 YAML | 是 |
| 修改 JWT/TOTP 加密密钥 | Secret 管理系统 | 是,并评估历史数据/会话影响 |
| 修改管理员登录密码 | 用户资料/管理员用户接口;紧急时受控 DB 恢复 | 否 |
| 添加上游 API Key | Account 业务数据 | 否 |
| 修改站点名称、注册、支付开关 | 管理后台 Settings | 通常否,但要验证多实例 |
| 修改连接池、请求体、网关超时 | 环境变量或 YAML | 是 |
| 清除账号限流/错误 | 专用账号恢复接口 | 否 |
| 清空 Redis | 只用于明确的故障恢复 | 会影响全局运行状态,不是普通配置动作 |
Secret 的生命周期
| Secret | 保存位置 | 轮换影响 |
|---|---|---|
JWT_SECRET | 启动配置 | 现有访问/刷新会话失效;所有副本必须一致 |
TOTP_ENCRYPTION_KEY | 启动配置 | 错误轮换会导致既有 TOTP secret 无法解密 |
| PostgreSQL/Redis 密码 | 部署 Secret | 需要协调服务端与应用滚动切换 |
| 上游 API Key/OAuth token | PostgreSQL Account 凭证 | 要失效 token/调度缓存并做真实请求测试 |
| 支付 Provider Secret | PostgreSQL Provider 配置 | 影响回调验签与历史订单查询 |
| SMTP/OAuth Client Secret | PostgreSQL Settings 或启动配置 | 需要验证对应登录/邮件流程 |
Secret 不应出现在文档、工单、截图和普通日志中。轮换前先确认旧数据是否依赖该密钥解密,而不仅是验证新请求。
开发新配置项时
新增配置前先决定它属于哪类:
- 启动配置:影响基础设施、连接池、协议底座,适合
config.Config。 - 动态业务设置:管理员需要在线修改,适合
settings+SettingService。 - 领域实体字段:只属于某个 Account/Group/User,放对应 schema。
- 临时运行状态:需要 TTL、跨实例协调时放 Redis。
实现时同时补齐:默认值、校验、环境变量映射、后台 DTO、脱敏、缓存失效、多实例传播、测试和部署文档。不要让同一个键同时在 YAML 和 settings 中各自生效,却没有明确覆盖规则。
变更后的验证
- 在目标实例打印或通过安全的诊断接口确认最终配置,不打印 Secret。
- 验证 PostgreSQL 和 Redis 实际连接目标。
- 对后台设置检查数据库值以及每个副本的行为。
- 对认证变更重新登录,并验证旧 Token 是否按预期失效。
- 对上游凭证执行 Account Test 和真实 Group 请求。
- 对支付、计费或调度设置保留回滚值,并观察错误与审计日志。
部署参数全集见配置方式与关键参数,生产修改步骤见变更、升级、备份与恢复。