4ga Boards 3.3.13 配置参数详解
4ga Boards v3.3.13 全量配置参数详解:必填三项(BASE_URL/DATABASE_URL/SECRET_KEY)与运行、限流、首建、上传、导入、图像、日志、SSO、通知九组变量源码实查默认值,令牌 365 天/登录限流 5 次/日志级别过滤真实实测,附生产模板与常见问题(2026-10-22 实测)。
4ga Boards 3.3.13 配置参数详解
目标:系统梳理 4ga Boards v3.3.13 服务端的全部配置参数——必填项、默认值、取值约束、生效方式,并对关键参数(令牌有效期、登录限流、日志级别、初始管理员)给出真实行为实测。参数定义均实查自 v3.3.13 源码
server/config/与server/db/seeds/default.js(2026-10-22),实测回显采集自 Docker Compose 栈(见 《4ga Boards 3.3.13 Docker Compose 部署指南》)。组件背景与安装方式见 《4ga Boards 3.3.13 介绍与选型指南》 与 《Ubuntu 22.04 安装 4ga Boards 3.3.13 指南》。
一、环境信息
本文参数实查与实测环境:
- 实查对象:4ga Boards v3.3.13 官方源码(commit bff02e86954db545c0bb5835bbdea7cdf7740695,tag v3.3.13),重点文件:
server/config/custom.js(应用自定义配置中枢,绝大多数参数在此读取)server/config/env/production.js(生产模式 Sails 配置:BASE_URL决定 WebSocket 合法 origin、TRUST_PROXY、日志器挂载)server/config/session.js(SECRET_KEY→ session secret,同时是 JWT 签名密钥)server/config/datastores.js与server/db/knexfile.js(DATABASE_URL)server/config/notifications.js(通知服务四件套)server/utils/logger.js(LOG_LEVEL默认值与日志格式)server/db/seeds/default.js(DEFAULT_ADMIN_*与DEFAULT_*注册类参数,仅首次建库生效)
- 实测环境:Ubuntu 22.04 宿主机上的 Docker 29.8.1 + Compose v5.5.1,运行 4ga Boards 3.3.13 官方镜像(应用监听 1337,宿主映射 8132)+ PostgreSQL 18 + Redis 8;查询日期 2026-10-22。
- 版本说明:v3.3.13 为官方最新稳定版(GitHub Releases,2026-07-15 发布),本文全部默认值以该版本源码为准。
二、前置条件
阅读与验证本文参数需要:
- 一套已运行的 4ga Boards v3.3.13 实例。没有现成实例时:
- Docker Compose 方式:见 《4ga Boards 3.3.13 Docker Compose 部署指南》;
- 源码手动安装方式:见 《Ubuntu 22.04 安装 4ga Boards 3.3.13 指南》。
- 已知 PostgreSQL 连接串与实例对外访问地址(两者是必填参数,见第五章)。
- 修改参数需要重启应用进程才能生效(Docker 方式重建容器,systemd 方式
systemctl restart)。
三、参数查看与修改方式
3.1 参数的读取优先级
4ga Boards 服务端配置只有一层环境变量:启动时从进程环境读取(process.env.*),没有独立配置文件解析器。两种主流注入方式:
| 部署方式 | 注入位置 | 生效方式 |
|---|---|---|
| 官方镜像 + Compose | docker-compose.yml 的 environment: 段(或 docker compose up 时的 shell 环境变量) | docker compose up -d 重建应用容器 |
| 官方镜像 + docker run | docker run -e VAR=value ... | 重新 docker run |
| 源码手动安装 | 源码目录 server/.env(服务端入口通过 dotenv 加载) | systemctl restart 或重启 start.sh |
⚠️ 注意:v3.3.13 源码中
process.env.X || 默认值是唯一默认值机制,.env文件里的值与 Composeenvironment:没有优先级合并问题——镜像版不读.env(文件不在镜像工作目录),源码版只读server/.env。同一实例只会有一种注入源。
3.2 查看当前生效值
Docker 方式直接查看容器进程环境:
docker exec <应用容器名> sh -c 'env | grep -E "^(BASE_URL|DATABASE_URL|TOKEN_EXPIRES_IN|LOG_LEVEL)=" '
输入(本文实测栈,应用容器名 4ga-boards-3313-stack-4gaBoards-1):
docker exec 4ga-boards-3313-stack-4gaBoards-1 sh -c 'env | grep -E "^(BASE_URL|DATABASE_URL|TOKEN_EXPIRES_IN|LOG_LEVEL)="'
输出:
BASE_URL=http://localhost:8132
DATABASE_URL=postgresql://postgres:q1w2e3r4@db/4gaBoards
TOKEN_EXPIRES_IN=365
说明:
LOG_LEVEL未出现在输出中,表示该实例未显式设置此变量,此时默认值warn(生产模式)在代码中生效——「未设置」与「设置为默认值」等效。
源码方式查看 server/.env 即可:
grep -E '^[A-Z]' /opt/4gaBoards/src/server/.env
3.3 修改参数与生效验证
以修改令牌有效期为 30 天(Docker Compose 方式)为例:
- 编辑
docker-compose.yml,在应用服务environment:段加一行TOKEN_EXPIRES_IN: 30; - 重建应用容器:
docker compose up -d(只有应用服务配置变化时会重建应用容器); - 重新登录获取新令牌并验证(验证方法见第六章 6.3 节实测)。
源码方式:编辑 /opt/4gaBoards/src/server/.env 后 systemctl restart 4gaboards。
⚠️ 重要:
DEFAULT_ADMIN_*、DEFAULT_*REGISTRATION*等「首建类」参数只在数据库首次初始化时读取(见 6.4 节),对已有数据库永远不会重新生效;其余「运行类」参数每次重启都会重新读取。
四、参数总览
下表按功能分组列出 v3.3.13 全部环境变量参数(默认值实查自源码;「—」表示无默认值)。详细行为与实测见第五章。
4.1 必填参数(生产环境缺失无法运行)
| 变量 | 默认值 | 作用 |
|---|---|---|
BASE_URL | —(缺失启动即崩) | 对外访问地址;决定 WebSocket 合法 origin、附件/头像/SSO 回调等全部 URL |
DATABASE_URL | —(缺失启动即崩) | PostgreSQL 连接串,如 postgresql://用户:密码@主机:5432/库名 |
SECRET_KEY | —(缺失令牌不可用) | session secret 与 JWT 签名密钥;更换后全部已登录令牌失效 |
4.2 基础运行
| 变量 | 默认值 | 作用 |
|---|---|---|
NODE_ENV | (开发模式行为) | 生产部署必须 production;影响日志默认级别与格式、通知定时任务节奏 |
PORT | 1337 | HTTP 监听端口(Sails 默认,亦可用 --port 参数覆盖) |
TZ | 宿主/容器时区 | 日志时间戳时区(源码版建议显式设置) |
TRUST_PROXY | 未设(false) | 反向代理场景设任意非空值(如 1),使 X-Forwarded-* 生效,客户端 IP 取真实 IP |
CLIENT_URL | 生产=BASE_URL;开发=http://localhost:3000 | 前端访问地址(前后端分离部署时单独指定) |
INSTANCE_NAME | 4gaboards.com | 实例名称(可观测性与部分对外标识用) |
4.3 认证与登录限流
| 变量 | 默认值 | 作用 |
|---|---|---|
TOKEN_EXPIRES_IN | 365 | 登录令牌有效期,单位天(非数字时回退 365) |
AUTH_RATE_LIMIT_ENABLED | true | 登录限流总开关(仅显式 false 关闭) |
AUTH_RATE_LIMIT_MAX_ATTEMPTS | 5 | 窗口内允许的失败尝试次数(最小 1) |
AUTH_RATE_LIMIT_WINDOW_MS | 60000 | 限流窗口毫秒数(代码强制下限 60000,设更小值无效) |
4.4 首建类参数(仅数据库首次初始化时生效)
| 变量 | 默认值 | 作用 |
|---|---|---|
DEFAULT_ADMIN_USERNAME | demo | 初始管理员用户名 |
DEFAULT_ADMIN_EMAIL | demo@demo.demo | 初始管理员邮箱 |
DEFAULT_ADMIN_NAME | Demo Demo | 初始管理员显示名 |
DEFAULT_ADMIN_PASSWORD | demo | 初始管理员密码 |
DEFAULT_REGISTRATION_ENABLED | true | 开放注册总开关(显式 false 关闭) |
DEFAULT_LOCAL_REGISTRATION_ENABLED | true | 本地账号注册开关 |
DEFAULT_SSO_REGISTRATION_ENABLED | true | SSO 注册开关 |
DEFAULT_PROJECT_CREATION_ALL | true | 所有用户可建项目开关(false 仅管理员可建) |
DEFAULT_SYNC_SSO_DATA_ON_AUTH | false | 登录时同步 SSO 资料(显式 true 开启) |
DEFAULT_SYNC_SSO_ADMIN_ON_AUTH | false | 登录时同步 SSO 管理员身份(显式 true 开启) |
DEFAULT_ALLOWED_REGISTER_DOMAINS | 空(不限制) | 注册邮箱域名白名单,分号分隔,如 a.com;b.com |
4.5 上传限流
| 变量 | 默认值 | 作用 |
|---|---|---|
UPLOAD_RATE_LIMIT_ENABLED | true | 上传限流总开关(仅显式 false 关闭) |
UPLOAD_RATE_LIMIT_MAX_ATTEMPTS | 30 | 窗口内允许的上传请求数(最小 1) |
UPLOAD_RATE_LIMIT_WINDOW_MS | 60000 | 上传限流窗口毫秒数(下限 1000) |
UPLOAD_RATE_LIMIT_STORE | memory | 计数存储:memory(单实例)或 redis(多实例共享) |
UPLOAD_RATE_LIMIT_REDIS_URL | —(store=redis 时必填) | Redis 连接串,如 redis://:密码@redis:6379/0 |
UPLOAD_RATE_LIMIT_REDIS_CONNECT_TIMEOUT_MS | 500 | Redis 连接超时毫秒(下限 100) |
UPLOAD_RATE_LIMIT_KEY_PREFIX | rl:upload | Redis 计数键前缀(多实例隔离时修改) |
4.6 文件大小上限(单位:字节)
| 变量 | 默认值 | 作用 |
|---|---|---|
ATTACHMENT_MAX_BYTES | 26214400(25 MiB) | 单个附件上传上限 |
AVATAR_MAX_BYTES | 26214400(25 MiB) | 用户头像上传上限 |
PROJECT_BACKGROUND_IMAGE_MAX_BYTES | 26214400(25 MiB) | 项目背景图上传上限 |
BOARD_IMPORT_MAX_BYTES | 104857600(100 MiB) | 看板导入压缩包上限 |
BOARD_IMPORT_MAX_COMPRESSED_BYTES | 104857600(100 MiB) | 导入包内单个压缩文件上限 |
BOARD_IMPORT_MAX_UNCOMPRESSED_BYTES | 524288000(500 MiB) | 导入包解压后总量上限 |
BOARD_IMPORT_MAX_ENTRIES | 5000 | 导入包内条目数上限 |
BOARD_IMPORT_MAX_EXTRACTION_MS | 30000 | 解压耗时上限毫秒(下限 1000) |
4.7 图像处理(sharp)
| 变量 | 默认值 | 作用 |
|---|---|---|
SHARP_MAX_INPUT_PIXELS | 40000000 | 单张图片最大输入像素数 |
SHARP_CONCURRENCY | 2 | 图像处理并发线程数 |
SHARP_CACHE_MEMORY_MB | 50 | 图像缓存内存 MB |
SHARP_CACHE_ITEMS | 100 | 图像缓存条目数 |
SHARP_CACHE_FILES | 20 | 图像缓存文件数 |
4.8 日志
| 变量 | 默认值 | 作用 |
|---|---|---|
LOG_LEVEL | 生产 warn;非生产 info | 应用日志最低输出级别(winston:error/warn/info/verbose/silly) |
4.9 单点登录(SSO,四组变量各自齐备后自动启用)
| 变量 | 作用 |
|---|---|
GOOGLE_CLIENT_ID + GOOGLE_CLIENT_SECRET | Google 登录(两者齐备启用) |
GITHUB_CLIENT_ID + GITHUB_CLIENT_SECRET | GitHub 登录(两者齐备启用) |
MICROSOFT_CLIENT_ID + MICROSOFT_CLIENT_SECRET | Microsoft 登录(两者齐备启用) |
OIDC_CLIENT_ID + OIDC_CLIENT_SECRET + OIDC_STATE_SECRET + (OIDC_AUTH_URL+OIDC_TOKEN_URL+OIDC_USERINFO_URL 或 OIDC_ISSUER_URL) | 通用 OIDC 登录:六个授权端点变量齐备启用;仅提供 OIDC_ISSUER_URL 时自动推导三个端点 |
OIDC_ENABLED_METHODS | 启用的 OIDC 登录方式 hint,逗号分隔 |
OIDC_DISABLE_HINT_<METHOD> | 设 true 禁用单个 OIDC 方式(如 OIDC_DISABLE_HINT_GOOGLE) |
OIDC_SKIP_ACCOUNT_SELECTION / OIDC_SKIP_ACCOUNT_SELECTION_HINT_<METHOD> | 设 true 跳过账号选择页(Microsoft 方式对应 prompt=login) |
SSO 回调地址由
BASE_URL自动推导:<BASE_URL>/auth/google、<BASE_URL>/auth/github、<BASE_URL>/auth/microsoft、<BASE_URL>/auth/oidc,在 IdP 侧登记回调时须与此一致。
4.10 通知与可观测性
| 变量 | 默认值 | 作用 |
|---|---|---|
NOTIFICATIONS_HOST_URL | 生产固定 https://notifications.4gaboards.com | 官方通知服务地址(与下三项齐备才启用通知服务) |
NOTIFICATIONS_CLIENT_ID / NOTIFICATIONS_CLIENT_SECRET | — | 官方通知服务凭据 |
MAIL_SERVICE_INBOUND_EMAIL | — | 官方邮件服务入站邮箱 |
SYSTEM_NOTIFICATIONS_DISABLED | false | 显式 true 关闭系统通知(离线/内网部署建议关闭) |
DEMO_MODE | false | 显式 true 开启演示模式 |
METRICS_ENABLED | false | 显式 true 开启指标端点 |
HYPERDX_ENABLED / HYPERDX_API_KEY / HYPERDX_INSTANCE_NAME / HYPERDX_TRACE_PROPAGATION_TARGETS | — | HyperDX 可观测性接入 |
OTEL_URL / OTEL_URL_FORMAT | — / http/protobuf | OpenTelemetry 上报地址与格式 |
ANDROID_PACKAGE_NAME / ANDROID_SHA256_FINGERPRINT | com.ga4boards.app / 官方指纹 | 移动端 App 校验信息(自签名分发时修改) |
另有一组硬编码常量(非环境变量,改配置无法调整):看板位置间隔
positionGap=65535、密码强度要求requiredPasswordStrength=2、列表缓存cacheMaxAge=900秒、动作/评论分页actionsLimit=commentsLimit=50。
五、必填参数详解
5.1 BASE_URL——一切 URL 的基准
BASE_URL 是整个实例的对外地址(含协议、域名/IP、端口),生产配置下被 5 处直接消费(源码 config/env/production.js、config/custom.js):
- WebSocket 合法 origin:
onlyAllowOrigins: [new url.URL(process.env.BASE_URL).origin]——浏览器 WebSocket 握手 origin 与其不符会被拒绝(前端页面能打开但实时更新失效的典型根因); - 附件、头像、项目背景图、看板导出的访问 URL 前缀;
- 四组 SSO 回调地址基准;
CLIENT_URL未显式设置时的前端地址。
实测验证:本文实测栈 BASE_URL=http://localhost:8132,登录接口返回的令牌可正常建立 WebSocket(实时卡片更新正常);若改为 http://127.0.0.1:8132 访问同一实例,浏览器 origin 变为 http://127.0.0.1:8132,与配置的 localhost origin 不匹配,实时更新将静默失败。生产对外域名一经使用不宜再改(附件 URL 已按旧域名写入库中记录)。
⚠️
BASE_URL缺失时生产模式启动直接抛TypeError(new url.URL(undefined)),进程退出——这也是「容器起来又立刻退出」排障的第一检查项。
5.2 DATABASE_URL——数据库连接串
标准格式 postgresql://用户:密码@主机:5432/库名。被服务端(config/datastores.js)与迁移/初始化脚本(db/knexfile.js)同时读取,两者必须一致。实测栈取值:
DATABASE_URL=postgresql://postgres:q1w2e3r4@db/4gaBoards
排障参考(B2 部署指南 FAQ 同源问题):主机名错或 PostgreSQL 未就绪时报 ECONNREFUSED 5432;密码错报 password authentication failed for user。PostgreSQL 侧密码仅在数据目录首次初始化时生效,后续改环境变量不生效(需进库改角色密码)。
5.3 SECRET_KEY——签名密钥
SECRET_KEY 同时承担两个角色(源码 config/session.js → sails.config.session.secret,api/helpers/utils/create-token.js → jwt.sign(..., sails.config.session.secret)):
- session cookie 签名;
- 登录令牌(JWT)签名密钥。
生产要求:随机长字符串(≥64 位)。更换即全员下线:旧令牌签名验证失败,所有用户需重新登录(也是「强制全员登出」的正规手段)。实测栈值形如 7f3a9c1d...(64 位十六进制),生成方式任选其一:
openssl rand -hex 32 # 64 位十六进制
head -c 48 /dev/urandom | base64 # 64 位 base64
六、关键参数实测
以下实测均在 2026-10-22 于 3.3.13 官方镜像栈(BASE_URL=http://localhost:8132,初始管理员 admin/q1w2e3r4)完成,可直接复现。
6.1 TOKEN_EXPIRES_IN:默认 365 天逐秒验证
登录获取令牌并解码 JWT 的 iat/exp 字段:
TOKEN=$(curl -s -X POST http://localhost:8132/api/access-tokens -H 'Content-Type: application/json' -d '{"emailOrUsername":"admin","password":"q1w2e3r4"}' | python3 -c 'import sys,json;print(json.load(sys.stdin)["item"])')
echo "${TOKEN:0:50}..."
输出:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6IjJlZTYzNDA5LTQ3NTEtNDNhZC05YWM2LTg0ZWJhZjdmYTY5NCJ9.eyJpYXQiOjE3OTI2ODc0OTQsInN1YiI6IjE4OTE1OTI0OTM1NDQyNDQyMzAiLCJleHAiOjE4MjQyMjM0OTR9.Nwh9doL0SiMk7z3325hlTB6vi4fwKDjDa5D1KO6rGe0
解码载荷(payload 为 JWT 第二段 base64url):
python3 - "$TOKEN" <<'EOF'
import sys, json, base64, datetime
tok = sys.argv[1]
payload = tok.split('.')[1]
payload += '=' * (-len(payload) % 4)
p = json.loads(base64.urlsafe_b64decode(payload))
iat, exp = p['iat'], p['exp']
print('iat:', datetime.datetime.utcfromtimestamp(iat).isoformat() + 'Z')
print('exp:', datetime.datetime.utcfromtimestamp(exp).isoformat() + 'Z')
print('有效期(秒):', exp - iat, '=', (exp - iat) / 86400, '天')
print('payload 其他字段:', {k: v for k, v in p.items() if k not in ('iat', 'exp')})
EOF
输出:
iat: 2026-10-22T16:45:01Z
exp: 2027-10-22T16:45:01Z
有效期(秒): 31536000 = 365.0 天
payload 其他字段: {'sub': '1891592493544244230'}
结论:默认 TOKEN_EXPIRES_IN=365 生效,exp = iat + 365×86400 与源码公式一致。设为 30 天后同样方法验证 exp-iat = 2592000 秒即认为生效。
6.2 AUTH_RATE_LIMIT:默认 5 次失败即锁定
用脚本连续 6 次错误密码登录(每轮记录状态码与响应体),再试正确密码:
for i in 1 2 3 4 5 6; do printf '第 %d 次: ' $i
curl -s -o /dev/null -w '%{http_code} ' -X POST http://localhost:8132/api/access-tokens \
-H 'Content-Type: application/json' -d '{"emailOrUsername":"admin","password":"wrongpass"}'
curl -s -X POST http://localhost:8132/api/access-tokens \
-H 'Content-Type: application/json' -d '{"emailOrUsername":"admin","password":"wrongpass"}'
echo; sleep 1
done
echo '== 窗口内正确密码也受限 =='
curl -s -o /dev/null -w 'HTTP %{http_code}\n' -X POST http://localhost:8132/api/access-tokens \
-H 'Content-Type: application/json' -d '{"emailOrUsername":"admin","password":"q1w2e3r4"}'
输出:
第 1 次: 401 {"code":"E_UNAUTHORIZED","message":"Invalid username or password"}
第 2 次: 401 {"code":"E_UNAUTHORIZED","message":"Invalid username or password"}
第 3 次: 401 {"code":"E_TOO_MANY_REQUESTS","message":"tooManyFailedAttempts","tooManyFailedAttempts":"Too many failed attempts - Please try again later."}
第 4 次: 429 {"code":"E_TOO_MANY_REQUESTS","message":"tooManyFailedAttempts","tooManyFailedAttempts":"Too many failed attempts - Please try again later."}
第 5 次: 429 {"code":"E_TOO_MANY_REQUESTS","message":"tooManyFailedAttempts","tooManyFailedAttempts":"Too many failed attempts - Please try again later."}
第 6 次: 429 {"code":"E_TOO_MANY_REQUESTS","message":"tooManyFailedAttempts","tooManyFailedAttempts":"Too many failed attempts - Please try again later."}
== 窗口内正确密码也受限 ==
HTTP 429
说明:脚本每轮发两次请求(一次取状态码、一次取响应体),限流按失败尝试累计计数——第 1–5 次失败依次累计,第 5 次失败达上限(响应 401 +
E_TOO_MANY_REQUESTS),第 6 次起全部 429。对应服务端日志:
2026-10-22 16:45:08 [WARN] Invalid password! (IP: 10.89.72.1)
2026-10-22 16:45:08 [WARN] Invalid password! (IP: 10.89.72.1)
2026-10-22 16:45:09 [WARN] Invalid password! (IP: 10.89.72.1)
2026-10-22 16:45:09 [WARN] Invalid password! (IP: 10.89.72.1)
2026-10-22 16:45:11 [WARN] Auth rate limit exceeded! (IP: 10.89.72.1)
2026-10-22 16:45:12 [WARN] Auth rate limit exceeded! (IP: 10.89.72.1)
...
60 秒窗口过后重试正确密码:
sleep 60
curl -s -o /dev/null -w 'HTTP %{http_code}\n' -X POST http://localhost:8132/api/access-tokens -H 'Content-Type: application/json' -d '{"emailOrUsername":"admin","password":"q1w2e3r4"}'
输出:
HTTP 200
结论:默认 maxAttempts=5、windowMs=60000 行为与源码一致——窗口内正确密码也被拒(防爆破的预期设计),窗口过后自动解锁,无需重启。
6.3 LOG_LEVEL:应用日志过滤生效,框架日志不受控
默认(未设 LOG_LEVEL,生产模式等效 warn)下应用日志只有 WARN 及以上(见 6.2 节 [WARN] 行),启动期 sails 框架另有 debug: 前缀提示。将 LOG_LEVEL: error 写入应用容器环境并重建后,重复 6.2 节的错误登录:
docker compose logs 4gaBoards --since 1m | grep -c 'WARN'
输出:
0
而框架级 debug: 行(如 onlyAllowOrigins 提示)仍然出现。结论:
LOG_LEVEL过滤的是 4ga Boards 应用自身日志(winston,格式YYYY-MM-DD HH:mm:ss [LEVEL] 消息,同时写控制台与logs/4gaBoards.log文件);- sails 框架自身的
debug:提示不经该变量过滤——排障时可利用这一点保留框架线索; - 需要完整请求级日志时设
LOG_LEVEL=info或verbose;生产追求安静用默认warn。
6.4 首建类参数:仅首次初始化生效
DEFAULT_ADMIN_* 生效实测(compose 首启时显式覆盖为 admin/q1w2e3r4)已在 《4ga Boards 3.3.13 Docker Compose 部署指南》 第五章验证:登录接口以该账号密码成功换取令牌。生效机制实查(server/db/init.js + db/seeds/default.js):
// db/init.js(节选)
const isExists = await knex.schema.hasTable(knexfile.migrations.tableName);
await knex.migrate.latest();
if (!isExists) {
await knex.seed.run(); // 仅当迁移表不存在(全新库)才执行种子
}
即:种子脚本只在数据库从零建立时读取 DEFAULT_* 系列变量。已运行的实例修改这些变量并重启,管理员账号与注册开关不会变化——已存在的账号请走界面管理或直接操作数据库。全新部署(删卷重建/新库)前把这些变量一次配好,是唯一正确的使用姿势。
七、生产配置模板
7.1 Docker Compose 模板(中小团队 50 人以内)
资源规格:应用容器实测常驻内存约 230 MB,PostgreSQL 空库约 60 MB;建议 2 vCPU / 4 GB 内存 / 20 GB 磁盘起步(磁盘按附件量另计,默认单附件 25 MB)。
name: 4ga-boards-prod-stack
services:
db:
image: postgres:18-alpine
restart: unless-stopped
environment:
POSTGRES_DB: 4gaBoards
POSTGRES_PASSWORD: <数据库密码> # 首次初始化生效,此后修改需进库
volumes:
- db-data:/var/lib/postgresql/data
healthcheck:
test: ['CMD-SHELL', 'pg_isready -U postgres']
interval: 10s
timeout: 5s
retries: 5
4gaBoards:
image: ghcr.io/rargames/4gaboards:3.3.13
restart: unless-stopped
depends_on:
db:
condition: service_healthy
ports:
- '1337:1337'
environment:
NODE_ENV: production
BASE_URL: https://boards.example.com # 必填:对外地址,改域名即改这里
SECRET_KEY: <openssl rand -hex 32 生成> # 必填:更换即全员登出
DATABASE_URL: postgresql://postgres:<数据库密码>@db:5432/4gaBoards
TZ: Asia/Shanghai
# —— 可选加固 ——
DEFAULT_ADMIN_USERNAME: admin # 首建类:仅首次生效
DEFAULT_ADMIN_PASSWORD: <强口令>
DEFAULT_REGISTRATION_ENABLED: 'false' # 关闭开放注册
SYSTEM_NOTIFICATIONS_DISABLED: 'true' # 内网/离线部署关闭官方通知
LOG_LEVEL: warn
volumes:
db-data:
Redis 仅在「上传限流计数跨实例共享 / 多副本部署」时需要,单实例用默认
memory存储即可,无需部署。
7.2 源码手动安装模板(server/.env)
NODE_ENV=production
BASE_URL=https://boards.example.com
SECRET_KEY=<openssl rand -hex 32 生成>
DATABASE_URL=postgresql://boards:<数据库密码>@localhost:5432/4gaBoards
TZ=Asia/Shanghai
LOG_LEVEL=warn
完整源码安装流程(Node 24 构建、systemd 托管)见 《Ubuntu 22.04 安装 4ga Boards 3.3.13 指南》。
7.3 常见场景速查
| 场景 | 关键参数 | 备注 |
|---|---|---|
| 换域名/端口 | BASE_URL | 同步改反向代理与 IdP 回调登记 |
| 强制全员重新登录 | 换 SECRET_KEY | 旧令牌全部失效 |
| 关闭自注册、管理员建号 | DEFAULT_REGISTRATION_ENABLED: 'false' | 首建类,新库前设置 |
| 防爆破加固 | AUTH_RATE_LIMIT_MAX_ATTEMPTS(默认 5) | 窗口时长有 60 秒下限 |
| 大附件需求 | ATTACHMENT_MAX_BYTES | 注意反向代理 client_max_body_size 同步调大 |
| 多实例负载均衡 | UPLOAD_RATE_LIMIT_STORE=redis + UPLOAD_RATE_LIMIT_REDIS_URL | 登录限流计数为实例内存态,多副本时每实例独立计数 |
| 内网离线部署 | SYSTEM_NOTIFICATIONS_DISABLED: 'true' | 避免反复请求官方通知服务 |
| 接入 OIDC | OIDC_* 六件套或 OIDC_ISSUER_URL 一件套 | 回调 <BASE_URL>/auth/oidc |
八、常见问题
Q1:修改 DEFAULT_ADMIN_PASSWORD 后重启,管理员密码没变?
首建类参数只在数据库首次初始化的种子阶段读取(见 6.4 节实测)。已有库改密码:管理员登录界面改,或管理员 API 改;忘记密码且无其他管理员时,用 PostgreSQL 直连更新 users 表对应字段(操作前先备份,备份命令见 《4ga Boards 3.3.13 常用 CLI 命令与工具详解》)。
Q2:AUTH_RATE_LIMIT_WINDOW_MS 设了 30000(30 秒)不生效?
源码对窗口时长强制下限 60 秒(Math.max(parseInt(..., 10) || 60 * 1000, 60 * 1000)),小于 60000 的值一律按 60000 处理。要更长的锁定时间可以设大(如 300000 = 5 分钟),要更短则无效。
Q3:页面能打开,但卡片/列表不实时刷新?
BASE_URL 与浏览器实际访问地址的 origin 不一致所致(WebSocket 握手被 onlyAllowOrigins 拒绝)。保证用户浏览器地址栏 origin 与 BASE_URL 完全一致(协议、域名、端口都算),或经反向代理透传后保持同源。
Q4:LOG_LEVEL=error 了为什么日志里还有 debug: 开头的行?
那些行来自 Sails 框架内置日志,不走应用级 LOG_LEVEL 过滤(见 6.3 节实测)。应用自身日志已按 error 过滤(WARN 计数为 0)。
Q5:SECRET_KEY 可以留空用默认吗?
不可以。v3.3.13 没有默认值,缺失时 session secret 为 undefined,登录令牌签发直接失败。必填三件套(BASE_URL/DATABASE_URL/SECRET_KEY)缺一不可。
Q6:附件上限调大后上传仍报错?
除 ATTACHMENT_MAX_BYTES 外,链路上的反向代理(Nginx client_max_body_size)与 BOARD_IMPORT_MAX_*(仅影响导入功能)是独立限制,需逐段核对。另注意上传接口受 UPLOAD_RATE_LIMIT_* 限流(默认 60 秒 30 次),批量上传时超限会得到 429。
九、参考链接
- 官方 Docker 变量文档:https://docs.4gaboards.com/docs/dev/install/docker-vars/
- 官方手动安装变量文档:https://docs.4gaboards.com/docs/dev/install/manual-vars/
- 源码配置目录(本文默认值实查来源):https://github.com/RARgames/4gaBoards/tree/v3.3.13/server/config
- CVE-2026-41419(<3.3.5 路径穿越,看板导入,
BOARD_IMPORT_*上限即相关加固面):https://github.com/RARgames/4gaBoards/security/advisories - 本专栏相关篇目:《4ga Boards 3.3.13 介绍与选型指南》、《Ubuntu 22.04 安装 4ga Boards 3.3.13 指南》、《4ga Boards 3.3.13 Docker Compose 部署指南》、《4ga Boards 3.3.13 常用 CLI 命令与工具详解》