Habitica v5.52.0 配置参数详解
Habitica v5.52.0 配置体系逐项实测详解:nconf 三级加载优先级、28 键最小可运行集、BASE_URL 301 重定向、WEB_CONCURRENCY 集群、限流 429、SESSION_SECRET_KEY hex 硬约束、BullMQ 邮件队列与 Cron 保护开关,含最小配置三连崩排障。
Habitica v5.52.0 配置参数详解
目标:逐项讲清 Habitica v5.52.0 的配置体系——config.json 的加载机制与优先级、最小可运行参数集(含缺失即崩溃的加载期硬读取键)、数据库/缓存/Web 行为/进程集群/限流/邮件队列/Cron 各域参数的语义与实测行为。全部结论基于 Ubuntu 22.04 服务器上的 v5.52.0 实测(源码交叉印证,来源与查询日期在各节标注),安装前置步骤见本专栏安装指南篇。
一、环境信息
本篇实测环境与取证口径:
- 操作系统:Ubuntu 22.04.5 LTS(x86_64);Habitica v5.52.0(git tag 源码,commit 12091ca)
- 服务形态:systemd 托管,入口
/opt/habitica/website/transpiled-babel/index.js(NODE_ENV=production) - 依赖组件:Node.js v20.20.2 / MongoDB v7.0.45(单节点副本集 rs)/ Redis v8.10.3
- 配置文件:
/opt/habitica/config.json(由config.json.example改写) - 服务地址:
http://10.89.71.10:3000(本机内网 IP,读者替换) - 演示账号:
habadmin/q1w2e3r4 - 参数行为取证:v5.52.0 源码实查(
website/server/libs/setupNconf.js、libs/config.js、middlewares/redirects.js、middlewares/rateLimiter.js、middlewares/maintenanceMode.js、libs/worker.js、libs/email.js、libs/cron.js、libs/encryption.js,查询日期 2026-10-28)+ 服务器实测回显
💡 说明:文中标注「实测」的行为均为上述环境在 2026-10-28 的可复现结果;源码行号为 v5.52.0 tag 实查位置,升级后可能漂移。
二、配置加载机制与优先级
2.1 加载入口与文件定位
Habitica 的全部运行参数收敛于一个 JSON 文件:仓库根的 config.json。加载逻辑在 website/server/libs/setupNconf.js(v5.52.0 源码实查):
const PATH_TO_CONFIG = join(resolve(__dirname, '../../../config.json'));
export default function setupNconf (file, nconfInstance = nconfDefault) {
const configFile = file || PATH_TO_CONFIG;
nconfInstance
.argv()
.env()
.file('user', configFile);
nconfInstance.set('IS_PROD', nconfInstance.get('NODE_ENV') === 'production');
nconfInstance.set('IS_DEV', nconfInstance.get('NODE_ENV') === 'development');
nconfInstance.set('IS_TEST', nconfInstance.get('NODE_ENV') === 'test');
process.env.CONTENT_SWITCHOVER_TIME_OFFSET = nconfInstance.get('CONTENT_SWITCHOVER_TIME_OFFSET') || 0;
}
三个要点:
- 优先级为 命令行参数 > 环境变量 > config.json(nconf 的
.argv().env().file()链式注册顺序即优先级从高到低); IS_PROD/IS_DEV/IS_TEST是派生键,由NODE_ENV计算后写回 nconf,全服务端统一读取——NODE_ENV同时还控制入口文件是否挂载@babel/register(index.js首行判断process.env.NODE_ENV !== 'production'),因此生产部署必须双通道生效:config.json 写"NODE_ENV": "production"且 systemd 单元带Environment=NODE_ENV=production;- 配置文件路径按入口文件位置回溯三级定位,从
website/transpiled-babel/libs/回溯到仓库根的config.json——替换入口位置会导致找不到配置。
2.2 优先级实测:环境变量覆盖 config.json
实测方法:config.json 写 "MAINTENANCE_MODE": "false"、"IGNORE_REDIRECT": "false",再以环境变量方式同时注入两个键的 true 值启动:
sudo systemctl stop habitica-web
su habitica -c 'cd /opt/habitica && NODE_ENV=production MAINTENANCE_MODE=true IGNORE_REDIRECT=true nohup node website/transpiled-babel/index.js > /tmp/maint-test.log 2>&1 &'
sleep 15
curl -s -o /dev/null -w 'GET / HTTP:%{http_code}\n' http://127.0.0.1:3000/
curl -s http://127.0.0.1:3000/api/v3/status
grep -c 'Connected with Mongoose' /tmp/maint-test.log
实测回显:
GET / HTTP:503
{"error":"Maintenance","message":"Server offline for maintenance."}
0
config.json 明明写 false,运行行为却按 true 执行(首页 503 维护页、API 返回维护 JSON),证明环境变量优先于 config.json。同一组回显还顺带证明了 MAINTENANCE_MODE=true 的两个附带行为:全站 503 与跳过 MongoDB 连接(日志中 Connected with Mongoose 计数为 0)。这一机制是 systemd 托管场景做临时开关的标准手法——不改配置文件,直接在单元文件加 Environment= 覆盖。
三、最小可运行配置集
v5.52.0 的 config.json.example 有 90+ 个键,但多数是第三方集成的占位值。实测逐项验证出「缺一个就起不来」的加载期硬读取键与核心运行键共 28 个,以下为实测通过的最小集(分类说明见后续各节):
| 分类 | 键 | 实测值 | 作用 |
|---|---|---|---|
| 基础 | PORT | 3000 | HTTP 监听端口(server.js 中 app.set('port', nconf.get('PORT'))) |
| 基础 | NODE_ENV | production | 运行模式,派生 IS_PROD/IS_DEV/IS_TEST |
| 基础 | BASE_URL | http://10.89.71.10:3000 | 站点规范地址,重定向/邮件链接均基于它 |
| 数据库 | NODE_DB_URI | mongodb://localhost:27017/habitica?replicaSet=rs&directConnection=true | 主库连接串 |
| 数据库 | TEST_DB_URI | mongodb://localhost:27017/habitica-test?replicaSet=rs&directConnection=true | 测试库连接串(IS_TEST 时替代主库) |
| 数据库 | MONGODB_POOL_SIZE | "10" | 连接池上限(maxPoolSize) |
| 缓存 | REDIS_HOST / REDIS_PORT / REDIS_PASSWORD | 127.0.0.1 / "6379" / "" | Redis 连接参数(限流、会话、队列共用) |
| 队列 | WORKER_REDIS_URL | redis://127.0.0.1:6379 | BullMQ 任务队列连接串,缺失邮件类接口直接 500 |
| 会话 | SESSION_SECRET | 任意强随机串 | 会话签名密钥 |
| 会话 | SESSION_SECRET_KEY | 64 位十六进制 | AES-256-GCM 加密密钥(密码重置码等),必须 hex |
| 进程 | WEB_CONCURRENCY | 1 | cluster worker 数(0 或缺省 = 单进程不启用 cluster) |
| 邮件 | EMAIL_SERVER_URL / EMAIL_SERVER_AUTH_USER / EMAIL_SERVER_AUTH_PASSWORD | 占位即可 | 邮件投递 worker 调用的上游接口 |
| 邮件 | ADMIN_EMAIL / FLAG_REPORT_EMAIL | 有效邮箱 | 管理员邮箱;后者缺失启动崩溃(split 硬读取) |
| Cron | MAINTENANCE_MODE / CRON_SAFE_MODE / CRON_SEMI_SAFE_MODE | "false" | 维护模式与 Cron 保护开关 |
| 限流 | RATE_LIMITER_ENABLED | "false"(生产建议 true) | API 限流总开关 |
| 日志 | DISABLE_REQUEST_LOGGING | "true" | 关闭请求级日志 |
| Web | IGNORE_REDIRECT | "false" | 生产 BASE_URL 强制重定向开关 |
| 支付 | PAYPAL_MODE / PAYPAL_CLIENT_ID / PAYPAL_CLIENT_SECRET | sandbox + 占位 | 缺失启动崩溃(paypal-sdk configure 校验) |
| 登录 | GOOGLE_CLIENT_ID / GOOGLE_CLIENT_SECRET | 占位 | 缺失启动崩溃(passport 策略注册期) |
⚠️ 排障实录(缺失即崩溃的三个键,安装篇首次启动实测命中):
PAYPAL_MODE缺失 → worker 启动即抛Error: Mode must be "sandbox" or "live"(node_modules/paypal-rest-sdk/lib/api.js:26),cluster 主进程不断重拉 worker,日志循环出现worker:xxxx disconnect! new worker:yyyy fork;FLAG_REPORT_EMAIL缺失 →TypeError: Cannot read properties of undefined (reading 'split'),出错点libs/challenges/reporting.js:16——模块加载期对nconf.get('FLAG_REPORT_EMAIL')直接.split(',');GOOGLE_CLIENT_ID/SECRET缺失 → passport 构造异常(passport-google-oauth20/lib/strategy.js:52,注册点libs/setupPassport.js:16)。三处都是 require 阶段的硬读取,任何一个未命中都会让服务陷入「worker 反复崩溃重启」,且生产默认无控制台日志、极易误判。自托管部署建议先照抄安装篇的最小集,再逐域加参数。
四、数据库与缓存参数
4.1 NODE_DB_URI:副本集是硬要求
官方示例连接串为 mongodb://localhost:27017/habitica-dev?replicaSet=rs&directConnection=true&readPreference=secondary(config.json.example 实查),官方编排文件中数据库以 --replSet rs 参数启动。自托管单机照抄该形态即可,三个参数的作用:
replicaSet=rs:声明副本集名,Habitica 依赖副本集特性的写入路径(事务与变更流);directConnection=true:跳过驱动对副本集成员的自动发现,直连指定节点(单机部署必需,多副本时可去掉);readPreference=secondary:官方开发配置带了从节点读偏好,单节点副本集上主节点即唯一成员,实测可省略(本篇实测连接串未携带,服务正常)。
数据库名(连接串 path 部分)按需自定义,首次启动时 mongoose 自动建库建集合。
4.2 MONGODB_POOL_SIZE:连接池上限实测
源码映射(libs/mongoose.js:18-19 实查):
if (MIN_POOL_SIZE) mongooseOptions.minPoolSize = Number(MONGODB_MIN_POOL_SIZE);
if (POOL_SIZE) mongooseOptions.maxPoolSize = Number(POOL_SIZE);
即 MONGODB_POOL_SIZE 直接映射 mongoose maxPoolSize(另有 MONGODB_MIN_POOL_SIZE 映射 minPoolSize、MONGODB_SOCKET_TIMEOUT 映射 socketTimeoutMS,均非必填)。连接按需惰性建立,池上限决定「最忙时最多建多少条」。实测对比(同流程:改配置重启 → 首页与 API 各请求一次 → mongosh 查 serverStatus):
| MONGODB_POOL_SIZE | mongosh db.serverStatus().connections.current |
|---|---|
"2" | 13 |
"10" | 19 |
可见池上限放大后服务端可见连接数随之上升(数字含 mongosh 自身 1 条与监控连接,取同流程差值看趋势:上限从 2 提到 10,实际建立的连接明显增多)。单机自托管默认 10 足够;小内存机器可降到 2-4 限制内存占用。
4.3 REDIS_HOST / REDIS_PORT / REDIS_PASSWORD
三键供两个客户端使用:限流中间件(middlewares/rateLimiter.js:22-24 实查读取三键建立 ioredis 连接)与开发态会话等场景。Redis 无密码时 REDIS_PASSWORD 留空字符串即可——客户端仅在密码真值时发送 AUTH(libs/redis.js:10-12 实查:if (connectionOptions.password) 才挂 password)。生产建议开启 Redis requirepass 并同步三键。
五、Web 行为与重定向参数
5.1 BASE_URL 与生产强制重定向(实测)
middlewares/redirects.js 的 forceHabitica 中间件(v5.52.0 源码实查):
function forceHabitica (req, res, next) {
if (IS_PROD && !IGNORE_REDIRECT && req.hostname !== BASE_URL_HOST && nonApiUrl(req) && req.method === 'GET') {
return res.redirect(301, BASE_URL + req.url);
}
return next();
}
触发条件五个全部满足才重定向:生产模式(IS_PROD)、未关闭重定向(!IGNORE_REDIRECT)、请求主机名与 BASE_URL 主机不一致、非 API 路径(URL 不含 /api/)、GET 方法。实测全链路(BASE_URL=http://10.89.71.10:3000):
curl -s -D- -o /dev/null http://127.0.0.1:3000/ | head -1
curl -s -D- -o /dev/null http://127.0.0.1:3000/ | grep -i location
curl -s -o /dev/null -w 'api GET HTTP:%{http_code}\n' http://127.0.0.1:3000/api/v3/status
curl -s -I -o /dev/null -w 'HEAD HTTP:%{http_code}\n' http://127.0.0.1:3000/
curl -s -o /dev/null -w 'GET BASE_URL HTTP:%{http_code}\n' http://10.89.71.10:3000/
HTTP/1.1 301 Moved Permanently
Location: http://10.89.71.10:3000/
api GET HTTP:200
HEAD HTTP:200
GET BASE_URL HTTP:200
结论与使用建议:主机名不一致的首页 GET 请求 301 到 BASE_URL(Location 头实测指向配置地址);API 请求与 HEAD 请求豁免;用 BASE_URL 本身访问则 200 直达。BASE_URL 必须与用户实际访问地址一致(协议/域名/IP/端口),反代场景填对外域名。内网调试想免重定向,把 IGNORE_REDIRECT 设 "true"。
5.2 IGNORE_REDIRECT:关闭强制重定向(实测)
config.json 保持 "IGNORE_REDIRECT": "false" 不动,仅以环境变量 IGNORE_REDIRECT=true 重启后实测:
curl -s -o /dev/null -w 'GET 127.0.0.1 HTTP:%{http_code}\n' http://127.0.0.1:3000/
curl -s -o /dev/null -w 'GET BASE_URL HTTP:%{http_code}\n' http://10.89.71.10:3000/
GET 127.0.0.1 HTTP:200
GET BASE_URL HTTP:200
与 5.1 节的 301 形成对照组:同一请求,开关打开后 127.0.0.1:3000 直接 200。相关键 TRUSTED_DOMAINS(逗号分隔的可信域名清单,供跨域信任判断)、SKIP_SSL_CHECK_KEY(携带该 key 的请求跳过 HTTPS 强制检查,用于反代终止 TLS 的调试场景)按需保留默认。
5.3 请求日志参数
DISABLE_REQUEST_LOGGING(示例默认 true):关闭每个请求的访问日志行;LOG_REQUESTS_EXCESSIVE_MODE 与 SLOW_REQUEST_THRESHOLD(毫秒)用于超时请求的额外记录。自托管单机建议保持 DISABLE_REQUEST_LOGGING: "true"(配合第六节的生产日志策略,避免噪音)。
六、进程、集群与维护模式参数
6.1 WEB_CONCURRENCY:cluster worker 数(实测)
进程模型(index.js + libs/config.js 源码实查):
const CORES = Number(nconf.get('WEB_CONCURRENCY')) || 0;
const ENABLE_CLUSTER = CORES !== 0 && cluster.isMaster && (IS_DEV || IS_PROD);
WEB_CONCURRENCY 为正整数时主进程 fork 对应数量 worker(worker 崩溃自动重拉),为 0 或缺省时单进程直跑。实测 WEB_CONCURRENCY=3(systemd 单元 drop-in 注入 Environment=WEB_CONCURRENCY=3):
ps -ef | grep 'transpiled-babel' | grep -v grep
habitica 8915 1 0 07:45 ? /usr/bin/node /opt/habitica/website/transpiled-babel/index.js
habitica 8923 8915 5 07:45 ? /usr/bin/node /opt/habitica/website/transpiled-babel/index.js
habitica 8924 8915 5 07:45 ? /usr/bin/node /opt/habitica/website/transpiled-babel/index.js
habitica 8925 8915 5 07:45 ? /usr/bin/node /opt/habitica/website/transpiled-babel/index.js
curl -s http://10.89.71.10:3000/api/v3/status
{"success":true,"data":{"status":"up"},"appVersion":"5.52.0"}
1 个主进程(PPID 1)+ 3 个 worker(PPID 8915),多 worker 下 API 正常。单机 2 核以内建议保持 1;CPU 富余且并发高时可提升。注意改该键要配合内存评估——每 worker 常驻 150MB 级。
6.2 MAINTENANCE_MODE:维护模式(实测)
设为 "true" 后(2.2 节同一次实测),行为三件套:
- 全站 503:HTML 请求渲染维护页(
views/static/maintenance),API 请求返回 JSON——实测curl http://127.0.0.1:3000/api/v3/status得{"error":"Maintenance","message":"Server offline for maintenance."}; - 启动不连库:
libs/mongoose.js:27实查if (MAINTENANCE_MODE !== 'true')才执行mongoose.connect,实测日志中Connected with Mongoose计数为 0; - 可选配
MAINTENANCE_START/MAINTENANCE_END展示维护时间窗。
适用场景:数据库迁移、大版本升级时把应用置为维护态,用户侧得到明确维护页而非报错。
6.3 ENABLE_CONSOLE_LOGS_IN_PROD:生产控制台日志
生产模式 winston 默认无任何 Console transport(libs/logger.js:52 实查 if (IS_PROD) 分支内再判断该键),表现是 journald 里几乎看不到应用日志、且 winston 会打 [winston] Attempt to write logs with no transports 提示。实测:默认配置下 journalctl -u habitica-web 仅有 systemd 生命周期行;在 systemd 单元追加 Environment=ENABLE_CONSOLE_LOGS_IN_PROD=true 并重启后,文本与 JSON 双格式日志进入 journald。该键属临时排障开关,长期开启会产生大量噪音,正式运行建议接 LOGGLY_TOKEN/LOGGLY_SUBDOMAIN 或保持关闭。
七、安全与会话参数
7.1 SESSION_SECRET 与 SESSION_SECRET_KEY(关键差异实测)
两个键极易混淆,语义完全不同:
SESSION_SECRET:普通会话签名密钥,任意强随机字符串即可,泄露只影响会话伪造风险;SESSION_SECRET_KEY:AES-256-GCM 对称加密密钥,源码(libs/encryption.js:16-17实查)按 hex 解码:
const SESSION_SECRET_KEY = nconf.get('SESSION_SECRET_KEY');
const key = Buffer.from(SESSION_SECRET_KEY, 'hex');
密钥算法要求 32 字节,即必须提供 64 位十六进制字符。实测反面案例:把 SESSION_SECRET_KEY 填成普通字符串(非 hex),服务能正常启动、日常 API 全部正常,但触发密码重置时服务端 encrypt() 在 createCipheriv 抛错,接口返回 500:
{"success":false,"error":"InternalServerError","message":"An unexpected error occurred."}
将 SESSION_SECRET_KEY 改为 64 位 hex(如 0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef)并重启后复测:
{"success":true,"data":{},"message":"If we have your email or username on file, instructions for setting a new password have been sent..."}
生成方式:openssl rand -hex 32。这是一个「平时无感、用时才炸」的隐蔽配置点,务必在首次部署时写对。
7.2 SITE_HTTP_AUTH_*:站点级 HTTP Basic 认证
SITE_HTTP_AUTH_ENABLED(true 时全站挂 Basic 认证)、SITE_HTTP_AUTH_USERNAMES 与 SITE_HTTP_AUTH_PASSWORDS(逗号分隔多组)。适用于内网试用、演示环境加一层门禁。本篇实测未启用,保持 false。
7.3 限流参数(RATE_LIMITER_*,429 实测)
参数全集与默认值(middlewares/rateLimiter.js:25-29 源码实查):
| 键 | 默认值 | 作用 |
|---|---|---|
RATE_LIMITER_ENABLED | false | 限流总开关(=== 'true' 才启用) |
RATE_LIMITER_BASE_POINTS | 30 | 基础桶容量(次) |
RATE_LIMITER_BASE_DURATION | 60 | 桶周期(秒),按 User ID 或 IP 计 |
RATE_LIMITER_REGISTRATION_COST | 10 | 注册接口单次扣点 |
RATE_LIMITER_LOGIN_COST | 10 | 登录接口单次扣点 |
RATE_LIMITER_IP_COST | 5 | 未认证请求按 IP 单次扣点 |
RATE_LIMITER_V4_POINTS | 200 | v4 API 独立桶容量 |
实测:设 RATE_LIMITER_ENABLED: "true" 重启后连续请求 /api/v4/status(未认证,按 IP 每次扣 5 点):
前 8 次全部 200,响应头实测:
X-RateLimit-Limit: 200
X-RateLimit-Remaining: 160
X-RateLimit-Reset: Wed Oct 28 2026 08:03:06 GMT+0000 (Coordinated Universal Time)
200 点桶、单请求扣 5 点(200 - 8×5 = 160,严丝合缝)。继续压测至桶耗尽,实测回显:
200 200 200 200 200 200 200 429 429 429
429 响应头实测:
X-RateLimit-Limit: 200
X-RateLimit-Remaining: 0
(桶内余量不足时还携带 Retry-After 头,值为窗口重置秒数。)限流的 Redis 键前缀 api(keyPrefix),可通扫观察。公网部署强烈建议开启;本篇实验完毕已将开关还原为 false。
八、邮件与任务队列参数
8.1 邮件链路架构
Habitica 的邮件是异步队列模型(libs/email.js + libs/worker.js 源码实查):
- Web 进程在
IS_PROD时把邮件任务投递进 BullMQ 队列(email.js:150:if (IS_PROD && mailingInfoArray.length > 0) return worker.sendJob('email', {...})); - 队列建立在 Redis 上,连接串取
WORKER_REDIS_URL(worker.js:11实查,未配置则根本不创建队列对象); - 真正发送邮件的是独立的邮件 worker(官方 habitica-workers 项目):它消费队列,把任务 POST 到
EMAIL_SERVER_URL(带EMAIL_SERVER_AUTH_USER/PASSWORD基本认证)完成投递。
自托管单机若只跑 Web 进程,邮件任务会滞留 Redis 队列——接口层不报错,但邮件不会发出。这是自托管邮件功能「成功却收不到」的架构性原因。
8.2 WORKER_REDIS_URL:缺失即 500(实测)
未配置该键时,sendJob('email') 因队列对象不存在直接 Promise.reject(new Error('Queue email does not exist'))(worker.js:38-40 实查),调用链上的密码重置接口实测 500。补 "WORKER_REDIS_URL": "redis://127.0.0.1:6379" 重启后复测:
curl -s -X POST http://10.89.71.10:3000/api/v4/user/reset-password \
-H 'Content-Type: application/json' -d '{"email":"admin@example.com"}'
redis-cli llen bull:emails:wait
{"success":true,"data":{},"message":"If we have your email or username on file, instructions for setting a new password have been sent..."}
1
接口 200,队列 bull:emails:wait 出现 1 条待消费任务。任务载荷实测(Redis hash):
name: "reset-password"
data: {"emailType":"reset-password","to":[{"name":"habadmin","email":"admin@example.com",...}],"variables":[{"name":"BASE_URL","content":"http://10.89.71.10:3000"},{"name":"PASSWORD_RESET_LINK","content":"http://..."}]}
链接域名取自 BASE_URL,用户端收到的重置链接可直接打开。另有 WORKER_REDIS_USERNAME/WORKER_REDIS_PASSWORD/WORKER_REDIS_KEY_PREFIX 支持队列 Redis 的认证与前缀隔离。生产部署两条路径:跑官方邮件 worker 消费队列(需自建符合 EMAIL_SERVER_URL 协议的投递端),或接受「队列滞留」并在应用层关闭邮件类入口。本篇实测止于队列层,投递端未搭建,如实说明。
九、Cron 与内容运营参数
9.1 CRON_SAFE_MODE / CRON_SEMI_SAFE_MODE:Cron 保护开关
Habitica 的每日结算(cron)在用户首次访问或定时触发时结算前一日 Dailies:未完成的 Dailies 扣血、累积 Boss 伤害。两个保护开关改变结算行为(libs/cron.js v5.52.0 源码实查,行号为 253 与 277 附近):
CRON_SAFE_MODE: "true":未完成 Dailies 不扣血(if (CRON_SAFE_MODE) { dailyChecked += 1 } else { perfect = false; ... scoreTask(direction: 'down', ...) }),Mana 按全额回满,且跳过对已终止订阅用户的清理逻辑(cron.js:179);调试数值系统或迁移数据时使用;CRON_SEMI_SAFE_MODE: "true":照常扣血但不累积 Boss 任务伤害(if (!CRON_SEMI_SAFE_MODE) { user.party.quest.progress.down += delta ... }),用于队伍任务期避免成员因现实原因漏打卡被团灭。
两键均为字符串 "true"/"false"。说明:两键的行为差异取自源码级分析,跨天 cron 结算需真实跨越自然日复测,本篇实验周期内未做跨日实测,特此如实说明。相关键 CRON_SEMI_SAFE_MODE 之外还有 ACCOUNT_MIN_CHAT_AGE(聊天防灌水)等运营键,按需取用。
9.2 CONTENT_SWITCHOVER_TIME_OFFSET 与 TIME_TRAVEL_ENABLED
CONTENT_SWITCHOVER_TIME_OFFSET(默认8):内容更新(新活动、新商店物品)的时区偏移,8 即东八区零点切换;setupNconf 会把它写回process.env供公共模块使用(2.1 节源码可见);TIME_TRAVEL_ENABLED(默认false):允许伪造系统时间调试 Cron 与周期逻辑,仅调试用;DEBUG_ENABLED(默认false):调试态辅助开关。
十、第三方集成占位键分级说明
config.json.example 中其余键按「缺省后果」分三级管理:
| 级别 | 键族 | 说明 |
|---|---|---|
| 启动必需(占位即可) | PAYPAL_MODE/CLIENT_ID/CLIENT_SECRET、GOOGLE_CLIENT_ID/SECRET | 加载期硬读取,缺了崩溃,自托管不接支付/谷歌登录可保留占位值 |
| 功能开关型 | FACEBOOK_KEY/SECRET、APPLE_AUTH_*、STRIPE_*、AMAZON_PAYMENTS_*、PAYPAL_BILLING_PLANS_* | 社交登录与订阅支付,不接则对应功能不可用,不影响启动 |
| 可选观测型 | LOGGLY_*、GA_ID、AMPLITUDE_*、SLACK_URL、S3_*、PUSH_CONFIGS_* | 日志/统计/通知/推送集成,全部可留默认占位 |
💡 技术拓展:第三方登录在服务端的形态是 passport 策略注册(如 7.1 节崩溃三的 passport-google-oauth20),占位值能让策略注册成功,但用户实际点击「Google 登录」时会跳到占位 client_id 对应的无效 OAuth 页面——因此「能启动」与「能用」是两回事,需要真实启用时再填真实凭据。这也是许多自托管应用「示例配置必须整份抄」的原因:占位不是装饰,是启动依赖。
十一、常见配置排障实录汇总
Q1:worker 反复崩溃重启(worker:xxxx disconnect! new worker:yyyy fork 循环)?
按第三节「三连崩」逐键核对:PAYPAL_MODE、FLAG_REPORT_EMAIL、GOOGLE_CLIENT_ID/SECRET。临时加 Environment=ENABLE_CONSOLE_LOGS_IN_PROD=true 看完整堆栈。
Q2:首页访问 301 跳到别处?
生产模式 BASE_URL 强制重定向(5.1 节实测),确认访问地址与 BASE_URL 一致,或临时 IGNORE_REDIRECT: "true"。
Q3:密码重置接口 500?
两个已知根因:SESSION_SECRET_KEY 非 64 位 hex(7.1 节实测修复前后对照);WORKER_REDIS_URL 缺失导致队列不存在(8.2 节实测)。按顺序排查。
Q4:邮件「发送成功」却收不到?
架构性原因:任务滞留 bull:emails:wait 队列,无邮件 worker 消费(8.1 节)。redis-cli llen bull:emails:wait 可确认积压。
Q5:改了 config.json 不生效?
优先级问题:环境变量 > config.json(2.2 节实测)。检查 systemd 单元与 drop-in(/etc/systemd/system/habitica-web.service.d/override.conf)中的 Environment= 是否覆盖了同名键,改完 systemctl daemon-reload && systemctl restart habitica-web。
Q6:限流误伤正常使用?
按第七节参数表调大 RATE_LIMITER_V4_POINTS 或 RATE_LIMITER_BASE_POINTS;确认 RATE_LIMITER_ENABLED 当前值(=== 'true' 才生效)。
十二、参考链接
- 配置键全集与官方示例:v5.52.0 仓库
config.json.example;加载机制website/server/libs/setupNconf.js - 邮件 worker 与投递端协议:官方 habitica-workers 项目(BullMQ 队列消费 +
EMAIL_SERVER_URL投递) - 站内配套阅读:本专栏《Ubuntu 22.04 安装 Habitica v5.52.0 指南》(安装全流程与最小配置集出处)、《Habitica 介绍与选型指南》(产品定位与游戏化机制认知篇)、《Habitica v5.52.0 常用 CLI 命令与工具详解》(运维命令与 API 实操);同类配置体系对照:《Beaver Habit Tracker v0.10.0 配置参数详解》、《OpenHabitTracker 1.2.5 配置参数详解》