OpnForm v2.8.1 配置参数详解

OpnForm v2.8.1 双 .env + compose 三层配置机制实测详解:URL 四元组/密钥/驱动/上传四层链路/TRUSTED_PROXIES/遥测/MCP/品牌化逐项参数、restart 不加载 env 的 down-up 改参闭环与生产配置模板

OpnFormOpnForm表单构建DockerDocker ComposeLaravel2026/11/02

OpnForm v2.8.1 配置参数详解

目标:把 OpnForm v2.8.1 自托管实例的两份 .env、compose 注入层与 nginx 模板层配置讲透——每个核心参数的含义、默认值、修改方法与生效条件,全部结论来自真实环境实测(2026-11-01/02,含改参→重建→验证闭环)。

一、环境信息

  • 宿主:Linux x86_64(内网 IP 192.168.1.172),Docker 29.9.2,Docker Compose v5.6.1
  • OpnForm:v2.8.1(容器内实测 APP_VERSION_DOCKER=2.8.1),Laravel 12.70.1 / PHP 8.3.36
  • 部署目录:/opt/data/quzuo/tmp/opnform/OpnForm,对外端口 8161
  • 配置文件:api/.env(后端)、client/.env(前端)、docker-compose.yml + docker-compose.override.yml(注入层)、docker/nginx.conf(入口模板)
  • 7 服务容器:opnform-api / opnform-api-worker / opnform-api-scheduler / opnform-client / opnform-db / opnform-redis / opnform-ingress
  • 演示账号:g25admin@example.com / G25test@12345
  • 本文全部回显取自已按 《OpnForm v2.8.1 Docker Compose 部署指南》 部署完成的实例

二、前置条件

  1. 一个已完成 setup 的实例(管理员已创建)。验证配置读取通道可用:
cd /opt/data/quzuo/tmp/opnform/OpnForm
docker compose -f docker-compose.yml -f docker-compose.override.yml exec -T api php artisan about

实测输出(节选):Environment=production、Debug Mode=OFF、URL=192.168.1.172:8161、Cache/Queue/Session=redis、Database=pgsql、Logs=errorlog、Mail=log、Config/Events/Routes/Views=CACHED、public/storage=LINKED。

  1. 理解 OpnForm 的三层配置来源(实测确认,这是本文所有"改了不生效"问题的根源):
层来源内容解析时机
① compose ${VAR:-default}宿主 shell 环境变量 / compose 同目录根 .envDB_DATABASE/DB_USERNAME/DB_PASSWORD(默认 forge)、DB_CONNECTION(默认 pgsql)docker compose 解析 YAML 时
② compose environment: 静态块docker-compose.ymlDB_HOST=db、REDIS_HOST=redis、PHP_* 四变量容器创建时注入
③ env_fileapi/.env、client/.env应用密钥、URL 四元组、驱动、限流等容器创建时注入

实测证据:api/.env 里没有任何 DB_* 行(setup-env.sh 生成的 .env.docker 模板不含),但容器内 printenv DB_HOST 返回 db、DB_DATABASE 返回 forge——全部来自 ①②层。官方文档同时注明:env_file 条目只在 Compose 文件解析完成后向容器传值,${...} 的解析用的是 shell/根 .env,两层机制不同。

三、参数查看与修改方式

3.1 查看当前生效值

# 文件层
cat api/.env
cat client/.env
# 容器实际生效层(推荐,能暴露"改了没生效")
docker compose -f docker-compose.yml -f docker-compose.override.yml exec -T api printenv JWT_TTL
# 1440
docker compose -f docker-compose.yml -f docker-compose.override.yml exec -T api printenv DB_HOST
# db

💡 说明:printenv 查的是容器进程真实环境;.env 文件只是它的输入之一。两者不一致 = 你改完还没重建。

3.2 修改与生效:restart 不加载 env,必须 down/up(实测闭环)

官方文档明确"docker compose restart 不会重新加载 env 值",本环境做了逐变量实测闭环验证:

# 基线:变量未设置
docker compose -f docker-compose.yml -f docker-compose.override.yml exec -T api printenv OPNFORM_ANONYMOUS_TELEMETRY_DISABLED
# (无输出,rc=1)

echo 'OPNFORM_ANONYMOUS_TELEMETRY_DISABLED=true' >> api/.env

# 纠偏实验:restart 后仍读不到
docker compose -f docker-compose.yml -f docker-compose.override.yml restart api
docker compose -f docker-compose.yml -f docker-compose.override.yml exec -T api printenv OPNFORM_ANONYMOUS_TELEMETRY_DISABLED
# (无输出,rc=1)——实测证实 restart 不加载 env_file 新值

# 正确姿势:down 单服务 + up 重建(Compose v5.6.1 实测 down 可带服务名)
docker compose -f docker-compose.yml -f docker-compose.override.yml down api
docker compose -f docker-compose.yml -f docker-compose.override.yml up -d
docker compose -f docker-compose.yml -f docker-compose.override.yml exec -T api printenv OPNFORM_ANONYMOUS_TELEMETRY_DISABLED
# true

三个连带要点(均为实测):

  1. down api 伴随的 Network opnform_default Resource is still in use 警告无害(网络仍被其他服务使用,Compose 尝试删除失败而已);
  2. api/api-worker/api-scheduler 共享同一 env_file 锚点,改一次 api/.env 三个服务都要重建才能消除配置漂移——实测 up -d 后三者 printenv 同步变为 true;
  3. 重建 api 或 ui 后必须 restart ingress:nginx 启动时解析并缓存上游容器 IP,重建换 IP 后 POST /api/login 实测 502 Bad Gateway;docker compose -f docker-compose.yml -f docker-compose.override.yml restart ingress 后恢复 200。

3.3 密钥的生成与保留

setup-env.sh 生成规则(读脚本实测):APP_KEY=base64: + openssl rand -base64 32;JWT_SECRET、FRONT_API_SECRET/NUXT_API_SECRET 为 tr -dc A-Za-z0-9 </dev/urandom | head -c 40 的 40 位字母数字串;FRONT_API_SECRET 与 NUXT_API_SECRET 写入同一共享密钥。重跑 docker-setup.sh 时已有 .env 的密钥保留不重新生成(脚本按"值非空则跳过"处理),只更新 URL 四元组。

四、参数总览

api/.env.example 共约 120 个变量、client/.env.example 14 个,按用途分组如下(★=自托管生产常需触碰):

组代表变量默认值(实测/文档)
URL 四元组★APP_URL FRONT_URL NUXT_PUBLIC_APP_URL NUXT_PUBLIC_API_BASEhttp://localhost,setup 用 --public-url 一条写齐
密钥★APP_KEY JWT_SECRET FRONT_API_SECRET/NUXT_API_SECRET自动生成,重跑保留
驱动★CACHE_DRIVER QUEUE_CONNECTION SESSION_DRIVER DB_CONNECTIONdocker 模板=redis×3、pgsql
数据库注入★DB_HOST DB_PORT DB_DATABASE DB_USERNAME DB_PASSWORDcompose 层:db/5432/forge×3
上传链★PUBLIC_UPLOADS_MAX_FILE_SIZE PUBLIC_UPLOADS_RATE_LIMIT_PER_MINUTE/HOUR PHP_UPLOAD_MAX_FILESIZE PHP_POST_MAX_SIZE PHP_MEMORY_LIMIT PHP_MAX_EXECUTION_TIME NGINX_MAX_BODY_SIZE50000000 / 30 / 300 / 64M / 1G / 600 / 64m
认证令牌★JWT_TTL JWT_REMEMBER_TTL JWT_SKIP_IP_UA_VALIDATION OAUTH_ENABLED OAUTH_ACCESS_TOKEN_TTL OAUTH_REFRESH_TOKEN_TTL_DAYS1440 / 43200 / false / true / 10080 / 30
反代★TRUSTED_PROXIES空(禁 *)
遥测★OPNFORM_ANONYMOUS_TELEMETRY_DISABLED未设置=遥测开
MCP/AIMCP_ENABLED MCP_RATE_LIMIT_* MCP_OAUTH_REDIRECT_DOMAINS OPEN_AI_API_KEYfalse / 120,3000 / 官方 allowlist / 空
品牌化NUXT_PUBLIC_SELF_HOSTED_NAME/LOGO_URL/PRIVACY_POLICY_URL/TERMS_URL NUXT_PUBLIC_ROOT_REDIRECT_URL名称默认 OpnForm
用户与许可ADMIN_EMAILS MODERATOR_EMAILS TEMPLATE_EDITOR_EMAILS SHOW_OFFICIAL_TEMPLATES LICENSE_API_ENDPOINT空 / 空 / 空 / true / https://api.opnform.com
验证码/集成H_CAPTCHA_* RE_CAPTCHA_* GOOGLE_CLIENT_ID/SECRET SLACK_BOT_TOKEN TELEGRAM_BOT_*空
邮件MAIL_MAILER MAIL_HOST MAIL_FROM_ADDRESSdocker 模板=log(不发真邮件)

解读:真正需要人工决策的只有 ★ 组;其余留空即安全默认。MAIL_MAILER=log 意味着表单通知邮件只写日志不外发,上生产要么配 SMTP 要么接受通知静默。

五、核心参数分类详解

5.1 公开 URL 四元组

必配且必须一致(生产禁 localhost):

变量文件实测值作用对象
APP_URLapi/.envhttp://192.168.1.172:8161Laravel 生成链接/回调
FRONT_URLapi/.envhttp://192.168.1.172:8161后端拼前端跳转
NUXT_PUBLIC_APP_URLclient/.envhttp://192.168.1.172:8161浏览器侧应用 origin
NUXT_PUBLIC_API_BASEclient/.envhttp://192.168.1.172:8161/api浏览器侧 API base

artisan about 的 URL 行实测回显 192.168.1.172:8161,即 APP_URL 去协议后的呈现,可作为验证点。另有一个模板自带、setup 不写的变量:NUXT_PRIVATE_API_BASE=http://ingress/api——Nuxt SSR 在服务端发起的 API 调用走 compose 内部网络直达 ingress,不绕公网;改公网 URL 时它保持不动。

5.2 密钥与共享密钥

  • APP_KEY:Laravel 加密键(base64: 前缀 + 32 字节随机)。丢失则已加密数据不可解、全部会话失效,必须随 .env 一起备份。
  • JWT_SECRET:登录令牌签名键。实测登录响应 {"token":"eyJ0eXAi…","token_type":"bearer","expires_in":86400}。
  • FRONT_API_SECRET(api 侧)= NUXT_API_SECRET(client 侧):前后端内部调用共享密钥,setup-env.sh 保证同值。
  • JWT_SKIP_IP_UA_VALIDATION:把令牌与客户端 IP/UA 绑定校验关掉。官方脚本对生产配置直接拒绝:docker-setup.sh 检测到 true 即 exit 1(读脚本实测);仅 docker-compose.dev.yml 开发场景自动设 true。

💡 技术拓展:OpnForm 有两套令牌体系。第一方登录用 JWT(tymon/jwt-auth 风格,JWT_TTL 控制);MCP/OAuth 开放集成用 Laravel Passport OAuth 2.1(OAUTH_* 变量、oauth_* 数据表实测存在)。对比——

体系载体适用
JWT自签名令牌,无状态自家前后端会话
Passport OAuth 2.1授权码+访问/刷新令牌,有状态第三方客户端、MCP agent

本文环境实测:OAUTH_ENABLED 默认 true(为 MCP 预留),但 MCP_ENABLED=false,对外 OAuth 面未激活。

5.3 数据库与 Redis(compose 注入层)

docker-compose.yml 实测注入:api 系 DB_HOST=db、REDIS_HOST=redis、DB_CONNECTION=${DB_CONNECTION:-pgsql}、DB_DATABASE/DB_USERNAME/DB_PASSWORD=${…:-forge};db 服务 POSTGRES_DB/USER/PASSWORD=${…:-forge} 与 api 侧同源——改库口令只需在宿主设一次 DB_PASSWORD 环境变量(或根 .env),两侧同时生效。

artisan db:show 实测确认连接参数:PostgreSQL 16.15 (Debian 16.15-1.pgdg13+2)、Database=forge、Host=db、Port=5432、Username=forge、Tables=44(该命令打印完摘要后会因镜像缺 intl 扩展而崩溃,属官方镜像已知限制,不影响配置生效)。

💡 技术拓展:DB_CONNECTION 存在多后端可选。官方 compose 钉死 postgres:16,但 tech-stack 文档声明支持 MySQL/MariaDB,README 迁移说明提及 MySQL/SQLite 走标准索引迁移。对比——

驱动支持度说明
pgsql官方 compose 默认,实测通过唯一开箱即用路径
mysql/mariadb框架支持需自建 compose 换 db 服务
sqlite仅开发/测试生产不建议

本方案采用默认 pgsql:与官方镜像、迁移脚本(CREATE INDEX CONCURRENTLY 为 PG 专属写法)一致性最高。

💡 技术拓展:QUEUE_CONNECTION/CACHE_DRIVER/SESSION_DRIVER 三驱动在 Laravel 里可选多种实现。对比——

驱动特点适用
sync进程内同步执行,无 worker开发调试(api/.env.example 默认值)
redis独立队列+高速缓存,需 redis 与 worker 进程生产标配(docker 模板默认)
database队列表落库,零额外中间件低量任务、不想跑 redis

本环境实测三驱动全 redis:提交落库因此是异步的(answer 返回 submission_id:null,约 5-8 秒后可见),依赖 api-worker 存活。

5.4 认证与令牌生命周期

  • JWT_TTL=1440(分钟,docker 模板值;.env.example 通用模板为 10080):实测登录响应 expires_in: 86400 秒与之吻合;Set-Cookie OpnForm_session Max-Age=7200 为会话 cookie 独立参数。
  • JWT_REMEMBER_TTL=43200(30 天):勾选 remember 时的令牌寿命。
  • OAUTH_ACCESS_TOKEN_TTL=10080(7 天)、OAUTH_REFRESH_TOKEN_TTL_DAYS=30:Passport 令牌,不影响第一方 JWT。

5.5 上传大小与限流(四层链路)

匿名附件从浏览器到落盘要过四道闸,实测取值:

层变量值位置
nginxNGINX_MAX_BODY_SIZE64mcompose ingress environment → 模板 client_max_body_size
PHPPHP_UPLOAD_MAX_FILESIZE / PHP_POST_MAX_SIZE64M / 64Mcompose api 系 environment(另 PHP_MEMORY_LIMIT=1G、PHP_MAX_EXECUTION_TIME=600)
应用PUBLIC_UPLOADS_MAX_FILE_SIZE50000000(50 MB)api/.env.example 默认
限流PUBLIC_UPLOADS_RATE_LIMIT_PER_MINUTE/HOUR30 / 300setup 写入 api/.env(实测在文件内)

解读:实际匿名上传上限取最小者 50 MB(应用层);要放大需三层同时调并重建容器。表单素材(logo/封面)另有独立 5 MB 限制(官方文档)。

5.6 TRUSTED_PROXIES(反代真实 IP)

前置 Caddy/Traefik/云 LB 时,在 api/.env 设反代连接来源的 IP 或 CIDR(官方示例形态:TRUSTED_PROXIES=192.0.2.10,2001:db8:1234::/48)。nginx 模板注释与官方文档双重强调:禁 *——否则直连客户端伪造 X-Forwarded-For 即可绕过按 IP 的限流(OIDC、公开上传等)。直连 ingress 部署则留空。修改后按 3.2 流程 down/up 重建 api 系。

5.7 匿名遥测

OPNFORM_ANONYMOUS_TELEMETRY_DISABLED=true 关闭。激活条件(官方文档+实测核对):APP_ENV=production 且自托管(SELF_HOSTED=true),开发环境自动禁用。采集面:功能使用计数、匿名实例 UUID、表单类型分布;不含表单内容、提交数据、用户邮箱。3.2 节已实测验证该变量从"未设置"到"true"的完整改参闭环。

5.8 MCP 与 AI 代理

自托管默认 MCP_ENABLED=false(.env.example 注释与官方文档一致)。启用后限流参数实测默认:MCP_RATE_LIMIT_PER_MINUTE=120、MCP_RATE_LIMIT_PER_HOUR=3000、MCP_SUBMISSION_EXPORTS_PER_MINUTE=5/HOUR=30、FORM_SUMMARY_RATE_LIMIT_PER_MINUTE=30;回调白名单 MCP_OAUTH_REDIRECT_DOMAINS(chatgpt.com/claude.ai/loopback 等)、原生 scheme 白名单 MCP_OAUTH_CUSTOM_SCHEMES=chatgpt,claude,cursor,vscode。启用前置:公网 HTTPS + Passport 密钥(PASSPORT_PRIVATE_KEY/PUBLIC_KEY,serverless 部署必须钉住)。AI 建表单独依赖 OPEN_AI_API_KEY(默认空=功能不可用)。

5.9 品牌化与前端变量

NUXT_PUBLIC_SELF_HOSTED_NAME(默认 OpnForm)、NUXT_PUBLIC_SELF_HOSTED_LOGO_URL、NUXT_PUBLIC_SELF_HOSTED_PRIVACY_POLICY_URL、NUXT_PUBLIC_SELF_HOSTED_TERMS_URL、NUXT_PUBLIC_ROOT_REDIRECT_URL(把欢迎页/未知路径 301 到你的站点,表单与应用页不受影响)。

品牌名生效位置做了实测:client/.env 追加 NUXT_PUBLIC_SELF_HOSTED_NAME=G25Brand → down ui + up -d ui 后容器内 printenv 返回 G25Brand;/login 页 HTML 出现 G25Brand(grep 命中 1 处),但公开表单页 <title> 不变(仍 G25 反馈表单 - OpnForm)——品牌名只作用于欢迎页/导航,表单页标题走表单自身 title。回退实验:删除该行重建后变量消失,7 服务恢复 healthy。

5.10 用户、许可与模板

  • ADMIN_EMAILS/MODERATOR_EMAILS/TEMPLATE_EDITOR_EMAILS:逗号分隔邮箱直接授予对应角色;EXTRA_PRO_USERS_EMAILS 追加 Pro 配额。
  • SHOW_OFFICIAL_TEMPLATES(默认 true):设 false 隐藏官方模板库(纯内网合规场景常用)。
  • LICENSE_API_ENDPOINT(默认 https://api.opnform.com):Enterprise 许可校验云端点;自托管免费版上限 2 用户(实测 setup 后注册关闭,plan_tier=pro 但受实例上限约束),更多用户与高级特性需激活 Enterprise license(Settings → License 路由实测存在于 api/routes.php)。

六、生产配置模板

适用画像:公网域名 forms.example.com、前置反代终结 TLS、8 GB 内存、50 GB SSD、单实例自托管(≤2 用户免费档或已购 Enterprise)。

api/.env(密钥行由 setup 自动生成,此处占位并给出注入方式):

APP_NAME="OpnForm"
APP_ENV=production
APP_KEY=${APP_KEY}              # 由 ./scripts/docker-setup.sh 生成; 备份后原样保留
APP_DEBUG=false
APP_URL=https://forms.example.com
FRONT_URL=https://forms.example.com
LOG_CHANNEL=errorlog
CACHE_DRIVER=redis
QUEUE_CONNECTION=redis
SESSION_DRIVER=redis
MAIL_MAILER=smtp                 # 生产改 smtp, 配套 MAIL_HOST/PORT/USERNAME/PASSWORD/FROM_ADDRESS
MAIL_HOST=smtp.example.com
MAIL_PORT=587
MAIL_USERNAME=${SMTP_USER}       # 从密管系统注入: export SMTP_USER=...
MAIL_PASSWORD=${SMTP_PASS}       # export SMTP_PASS=...
MAIL_ENCRYPTION=tls
MAIL_FROM_ADDRESS=form@example.com
MAIL_FROM_NAME="OpnForm"
JWT_TTL=1440
JWT_SECRET=${JWT_SECRET}         # setup 生成, 勿手填弱值
JWT_SKIP_IP_UA_VALIDATION=false
FRONT_API_SECRET=${FRONT_API_SECRET}
PUBLIC_UPLOADS_MAX_FILE_SIZE=50000000
PUBLIC_UPLOADS_RATE_LIMIT_PER_MINUTE=30
PUBLIC_UPLOADS_RATE_LIMIT_PER_HOUR=300
TRUSTED_PROXIES=10.0.0.5         # 你的反代真实来源 IP/CIDR, 严禁 *
OPNFORM_ANONYMOUS_TELEMETRY_DISABLED=true
MCP_ENABLED=false
SHOW_OFFICIAL_TEMPLATES=false

client/.env:

NUXT_PUBLIC_APP_URL=https://forms.example.com
NUXT_PUBLIC_API_BASE=https://forms.example.com/api
NUXT_PRIVATE_API_BASE=http://ingress/api
NUXT_API_SECRET=${FRONT_API_SECRET}   # 与 api 侧同值, setup 自动对齐
NUXT_PUBLIC_SELF_HOSTED_NAME=MyCorp Forms
NUXT_PUBLIC_ENV=production

数据库口令(宿主根 .env,与 compose 同目录,供 ①层解析):

DB_DATABASE=opnform
DB_USERNAME=opnform
DB_PASSWORD=${DB_PASS}           # export DB_PASS=... 或写入该文件实际值

⚠️ 注意:${VAR} 仅出现在系统级真实密钥的书写规范中(同值注入方式已注明);三文件写完后按 3.2 流程 down && up -d 全量重建,并 restart ingress。

七、常见问题

7.1 改了 .env 没生效

restart 不加载 env_file 新值(3.2 实测 rc=1),必须 down <svc> && up -d;涉及 api/.env 时 api/api-worker/api-scheduler 三个服务一起重建。

7.2 重建 api 后整站 502

nginx 缓存旧上游 IP,docker compose -f docker-compose.yml -f docker-compose.override.yml restart ingress 恢复(实测闭环)。

7.3 想改数据库口令却改了 api/.env

api/.env 里没有 DB_* 行(实测);口令在 compose ①层 ${DB_PASSWORD:-forge},应在宿主 shell 或 compose 同目录根 .env 设置,同时重建 db 与 api 系(已有数据卷内口令不会自动变更,需进 psql ALTER USER)。

7.4 表单通知邮件没收到

docker 模板默认 MAIL_MAILER=log,邮件只写日志。按第六节模板改 smtp 并重建。

7.5 品牌名改了但表单页标题没变

NUXT_PUBLIC_SELF_HOSTED_NAME 只影响欢迎页/导航(5.9 实测);表单页 <title> 由表单 title 决定,属预期行为。

7.6 注册新用户被拒

setup 完成后公开注册关闭(实测 Registration is not allowed.),用管理员邀请;免费实例上限 2 用户,属许可约束而非配置项。

7.7 TRUSTED_PROXIES 能设 * 吗

不能。官方文档与 nginx 模板注释双重禁止:* 让任意直连客户端伪造 IP、绕过按 IP 限流。留空=直连部署,填具体反代 IP/CIDR。

八、参考链接

OpnForm v2.8.1 配置参数详解 - Quzuo