OpnForm v2.8.1 Docker Compose 部署指南
OpnForm v2.8.1 官方 Docker Compose 七服务部署实测闭环:一键 setup、端口 !override 纠偏、管理员初始化与建表单/提交/CSV 导出 API 闭环、改 env 重建与 ingress 502 排障实录
OpnForm v2.8.1 Docker Compose 部署指南
目标:在真实 Linux 宿主上用官方 Docker Compose 路径部署 OpnForm v2.8.1 自托管实例,完成管理员初始化、建表单、匿名提交、提交列表与 CSV 导出的端到端闭环。全部命令与回显取自 2026-11-01/02 真实环境实测。
⚠️ 验收方式说明:本实验环境无浏览器自动化,页面验收降级为 HTTP 状态码 +
<title>标签 + API 闭环验证(curl 调用的正是前端页面同组使用的 Laravel 路由,服务端行为等价)。编辑器拖拽等纯浏览器交互未做 UI 级验收。
一、环境信息
- 宿主:Linux x86_64(内网 IP
192.168.1.172) - Docker:
29.9.2(docker --version→Docker version 29.9.2, build a82e528) - Docker Compose:
v5.6.1(docker compose version --short→5.6.1) - OpnForm:
v2.8.1(2026-10-29 发布;容器内实测APP_VERSION_DOCKER=2.8.1) - 部署目录:
/opt/data/quzuo/tmp/opnform/OpnForm(v2.8.1 源码 tarball 解压,约 28.8 MiB) - 对外端口:
8161(宿主0.0.0.0:8161->80/tcp;8160 已被其他服务占用,实测改用 8161) - 7 个服务容器:
opnform-api、opnform-api-worker、opnform-api-scheduler、opnform-client、opnform-db、opnform-redis、opnform-ingress - 演示账号(setup 期创建):
g25admin@example.com/G25test@12345 - 实测日期:2026-11-01/02(Asia/Shanghai)
二、镜像选型说明
官方 docker-compose.yml(v2.8.1,133 行)引用 5 个镜像、7 个服务:
| 服务 | 镜像 | 角色 |
|---|---|---|
| api | jhumanj/opnform-api:latest | Laravel 12 API(PHP-FPM,监听 9000) |
| api-worker | jhumanj/opnform-api:latest | 队列消费者,php artisan queue:work |
| api-scheduler | jhumanj/opnform-api:latest | 定时任务,php artisan schedule:work |
| ui | jhumanj/opnform-client:latest | Nuxt SSR 前端(Vue 3 + Nuxt,监听 3000) |
| redis | redis:7 | 缓存 / 队列 / 会话 |
| db | postgres:16 | 主数据库 |
| ingress | nginx:1 | 反向代理入口(唯一发布端口) |
三个 Laravel 服务共享同一镜像锚点(YAML &api-environment),仅 command 不同。
实测版本核对:latest 标签容器内 printenv APP_VERSION_DOCKER 输出 2.8.1,与 GitHub v2.8.1 release(2026-10-29)一致。⚠️ 网络情况注明:本宿主访问 Docker Hub 的 tags API 超时,无法逐 tag 比对,版本钉住依据为容器内 APP_VERSION_DOCKER 实测值;镜像拉取本身走默认渠道成功。若需严格钉版,官方镜像发布同名版本 tag,可将 latest 改为对应 tag。
💡 技术拓展:入口反向代理不止 nginx 一种。OpnForm 官方 compose 内置 nginx,但代码与配置同时预留了 Caddy 集成(路由
caddy/ask-certificate/{secret}、环境变量CADDY_SECRET/CADDY_AUTHORIZED_IPS)。常见选型对比——
代理 特点 适用场景 nginx 官方 compose 内置,模板变量注入,生态最成熟 与官方部署路径保持一致 Caddy 自动签发/续期 HTTPS,OpnForm 有原生联动端点 公网单机快速上 TLS Traefik 服务发现式路由,标签驱动 容器动态调度、多服务网关 本文按官方路径采用内置 nginx ingress,最省事且与文档一致;上 TLS 时可再套一层 Caddy/Traefik 或云 LB。
三、前置条件
- Docker 与 Compose v2。实测回显:
docker --version
# Docker version 29.9.2, build a82e528
docker compose version --short
# 5.6.1
官方脚本 docker-setup.sh 自动探测 docker compose(v2 插件)或 docker-compose(经典版),两者都没有时报错并提示 sudo apt-get install -y docker-compose-plugin。
- 端口空闲。现场
docker ps实测 8149/8152/8157 已被其他项目占用,任务原计划端口 8160 被mobilizon-mobilizon-1(0.0.0.0:8160->4000)占用,因此本部署改用 8161。查占用:
docker ps --format '{{.Names}}\t{{.Ports}}' | grep 816
# 其他项目的映射行(本部署避开)
-
内存。全栈空闲态实测约 411 MiB(
docker stats --no-stream七项合计:client 216.7 / api-scheduler 54.5 / api 49.3 / api-worker 43.2 / db 31.1 / ingress 9.3 / redis 7.1 MiB),2 GB 内存的宿主即可跑通,生产建议 4 GB 以上。 -
脚本行尾(Windows 检出源码时)。官方警告:
api/artisan若被转成 CRLF,容器会卡在 "Waiting for DB to be ready"。Linux 宿主无需处理;Windows 检出后执行sed -i 's/\r$//' api/artisan或dos2unix api/artisan。
四、部署步骤
4.1 获取 v2.8.1 源码
官方推荐 git clone(组织化迁移后仓库为 OpnForm/OpnForm,旧地址 JhumanJ/OpnForm 301 重定向仍可用):
git clone https://github.com/OpnForm/OpnForm.git
cd OpnForm
git checkout v2.8.1
本实测采用 GitHub release 源码 tarball(opnform-v2.8.1.tar.gz,28.8 MiB)解压到 /opt/data/quzuo/tmp/opnform/OpnForm,与 checkout v2.8.1 内容等价。compose 文件、docker/nginx.conf、scripts/ 均随源码携带,缺一不可。
4.2 端口 override(含 !override 纠偏)
官方 compose 的 ingress 固定 80:80。宿主 80 已被占用,需要改端口。实测纠偏:Compose 对 ports 列表默认追加合并,首版 override 只写 - 8161:80 导致 ingress 同时映射 80:80 与 8161:80;必须用 !override 标签整体替换。最终实测文件 /opt/data/quzuo/tmp/opnform/OpnForm/docker-compose.override.yml:
services:
ingress:
ports: !override
- 8161:80
后续所有 compose 命令统一带双文件前缀(本文档内命令均可照抄执行):
docker compose -f docker-compose.yml -f docker-compose.override.yml <子命令>
4.3 运行官方一键安装脚本
cd /opt/data/quzuo/tmp/opnform/OpnForm
chmod +x scripts/docker-setup.sh
./scripts/docker-setup.sh --public-url http://192.168.1.172:8161
--public-url 传浏览器访问的 origin(不带路径与尾斜杠;生产用 HTTPS)。脚本实测行为(EXIT=0):
- 调
setup-env.sh --docker --public-url …:从api/.env.docker、client/.env.docker模板生成两个.env,生成APP_KEY=base64:…、JWT_SECRET、FRONT_API_SECRET/NUXT_API_SECRET共享密钥,并把四元组 URL 写齐; - 拒绝
JWT_SKIP_IP_UA_VALIDATION=true的生产配置(直接exit 1); - 探测到
docker-compose.override.yml自动追加-f; docker compose up -d拉镜像并启动全部服务。
setup.log 关键回显(输出节选(实测首尾),中间为镜像层下载进度):
Starting OpnForm Docker setup...
Setting up environment files...
OpnForm setup detected the --docker flag. Preparing Docker-specific environment...
Creating OpnForm's main .env file from the template...
Creating OpnForm's client .env file from the template...
Configured OpnForm's public URL as http://192.168.1.172:8161.
✅ OpnForm environment setup is now complete. Enjoy building your forms!
Production mode - using docker-compose.yml
Found docker-compose.override.yml - including local overrides
Starting Docker containers...
Image nginx:1 Pulled
Image jhumanj/opnform-api:latest Pulled
Image jhumanj/opnform-client:latest Pulled
Network opnform_default Creating
Volume opnform_postgres-data Creating
Volume opnform_opnform_storage Creating
Volume opnform_redis-data Creating
Container opnform-db Healthy
Container opnform-redis Healthy
Container opnform-api Started
Container opnform-api Healthy
Container opnform-client Started
Container opnform-ingress Started
Production environment setup complete!
Please wait a moment for all services to start
Then visit: http://192.168.1.172:8161
启动顺序由 depends_on + healthcheck 保证:db/redis 先 healthy → api 起 → api healthy → ui 起 → ingress 起,全程约 1 分钟。
4.4 验证服务状态
docker compose -f docker-compose.yml -f docker-compose.override.yml ps
实测回显(7 服务全 healthy):
NAME IMAGE COMMAND SERVICE CREATED STATUS PORTS
opnform-api jhumanj/opnform-api:latest "/usr/local/bin/opnf…" api 9 minutes ago Up 9 minutes (healthy) 9000/tcp
opnform-api-scheduler jhumanj/opnform-api:latest "/usr/local/bin/opnf…" api-scheduler 9 minutes ago Up 9 minutes (healthy) 9000/tcp
opnform-api-worker jhumanj/opnform-api:latest "/usr/local/bin/opnf…" api-worker 9 minutes ago Up 9 minutes (healthy) 9000/tcp
opnform-client jhumanj/opnform-client:latest "docker-entrypoint.s…" ui 9 minutes ago Up 9 minutes (healthy)
opnform-db postgres:16 "docker-entrypoint.s…" db 20 minutes ago Up 20 minutes (healthy) 5432/tcp
opnform-ingress nginx:1 "/docker-entrypoint.…" ingress 18 minutes ago Up 8 minutes (healthy) 0.0.0.0:8161->80/tcp, [::]:8161->80/tcp
opnform-redis redis:7 "docker-entrypoint.s…" redis 20 minutes ago Up 20 minutes (healthy) 6379/tcp
端口列只有 ingress 一行有宿主映射,!override 纠偏生效。自托管专用健康端点实测:
curl -s http://192.168.1.172:8161/api/healthcheck
# {"status":"ok","dependencies":{"database":true,"redis":true}}
💡 说明:
/api/healthcheck路由仅在self_hosted配置下注册(api/routes.phpL54-56),返回体直接报告数据库与 Redis 依赖状态,适合挂拨测。
4.5 初始化管理员(/setup)
访问 http://192.168.1.172:8161,setup 未完成时实测 302 → /setup,页面 <title>Setup - OpnForm - OpnForm</title>。在页面创建管理员,或用 API 等价完成(本实测即此路径):
curl -s -X POST http://192.168.1.172:8161/api/register \
-H 'Content-Type: application/json' \
-d '{"name":"G25 Admin","email":"g25admin@example.com","password":"G25test@12345","password_confirmation":"G25test@12345","hear_about_us":"self-hosted eval"}'
实测两次纠偏:首次 422 The hear_about_us field is required.(自托管注册必填该字符串字段,agree_terms 仅云端要求);补齐后 200,返回 {"token":"eyJ0eXAi…","token_type":"bearer","expires_in":86400,"new_user":true},用户 id=1、plan_tier=pro。
⚠️ 密码策略纠偏:RegisterController 规则为 min:8 + 必须含字母、数字、特殊字符,且 confirmed(必须带 password_confirmation)。演示惯用口令 q1w2e3r4 实测 422 The password format is invalid.(缺特殊字符),故本文档演示账号采用 G25test@12345。
setup 完成后公开注册即关闭(实测再调 /api/register 返回 Registration is not allowed.),后续用户由管理员邀请;免费版自托管实例上限 2 用户。
4.6 端到端功能闭环(登录 → 建表单 → 提交 → 导出)
TOKEN=$(curl -s -X POST http://192.168.1.172:8161/api/login \
-H 'Content-Type: application/json' \
-d '{"email":"g25admin@example.com","password":"G25test@12345","remember":false}' \
| python3 -c 'import json,sys;print(json.load(sys.stdin)["token"])')
实测要点:登录路径是 /api/login(/api/auth/login 404);响应字段名是 token 而非 access_token。
建表单(字段枚举实测纠偏:presentation_style ∈ classic/focused、width ∈ centered/full、size ∈ sm/md/lg,首次 422 即因枚举值非法):
curl -s -X POST http://192.168.1.172:8161/api/open/forms \
-H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' \
-d '{"title":"G25 反馈表单","workspace_id":1,"visibility":"public","type":"form",
"properties":{"presentation_style":"classic","size":"md","width":"centered","theme":"default",
"fields":[{"id":"field-name","name":"Your Name","type":"text","required":true},
{"id":"field-email","name":"Email","type":"email"},
{"id":"field-plan","name":"Plan","type":"select","properties":{"choices":["Free","Pro"]}},
{"id":"field-rating","name":"Rating","type":"rating"}]}}'
# {"type":"success","message":"Form created."} → id=1, slug=g25-spqlvr
公开页与匿名提交:
curl -s http://192.168.1.172:8161/forms/g25-spqlvr | grep -o '<title>[^<]*</title>'
# <title>G25 反馈表单 - OpnForm</title>
curl -s http://192.168.1.172:8161/api/forms/g25-spqlvr/view
# {"type":"success","message":"Form viewed."}
curl -s -X POST http://192.168.1.172:8161/api/forms/g25-spqlvr/answer \
-H 'Content-Type: application/json' \
-d '{"field-name":"张三","field-email":"zhangsan@example.com","field-plan":"Pro","field-rating":4}'
# {"type":"success","message":"Form submission saved.","submission_id":null,…}
⚠️ 提交经队列异步落库:answer 返回时 submission_id 为 null,实测约 5-8 秒后才能在工作台列表看到,属正常行为。
查列表与导出 CSV:
curl -s "http://192.168.1.172:8161/api/open/forms/1/submissions" -H "Authorization: Bearer $TOKEN"
# data 数组 2 条(李四/Free/5、张三/Pro/4,各带 submission_id UUID;分页响应无 total 字段)
curl -s -X POST "http://192.168.1.172:8161/api/open/forms/1/submissions/export" \
-H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' \
-d '{"columns":{"Your Name":true,"Email":true,"Plan":true,"Rating":true},"file_type":"csv"}'
# "id","Your Name","Email","Plan","Rating","created_at" ← 小数据量同步返回 CSV 正文(带 BOM 头)
数据库侧核对(实测 forms=1、form_submissions=2、users=1):
docker compose -f docker-compose.yml -f docker-compose.override.yml exec -T db \
psql -U forge -d forge -tc "select (select count(*) from forms), (select count(*) from form_submissions), (select count(*) from users);"
# 1 | 2 | 1
五、数据持久化说明
compose 声明 3 个命名卷(实测项目前缀 opnform_):
| 卷 | 挂载点 | 内容 | 备份优先级 |
|---|---|---|---|
opnform_postgres-data | db:/var/lib/postgresql/data | 全部业务数据(44 张表) | 必做 |
opnform_opnform_storage | api:/usr/share/nginx/html/storage | 上传附件、表单素材(public/storage LINKED) | 必做 |
opnform_redis-data | redis:/data | 缓存/队列/会话 | 可不备(丢了重新生成) |
宿主侧配置状态文件:api/.env、client/.env(含 APP_KEY/JWT_SECRET 等密钥,丢失会导致会话失效、密文无法解密)、docker-compose.override.yml。备份示例:
docker compose -f docker-compose.yml -f docker-compose.override.yml exec -T db \
pg_dump -U forge forge | gzip > /opt/data/quzuo/tmp/opnform/backup-$(date +%F).sql.gz
⚠️ 注意:卷名带项目前缀,若换目录/换项目名重新 up,Compose 会新建空卷而不是复用旧卷。迁移时先
docker volume ls | grep opnform核对。
六、环境变量表
docker-setup.sh --public-url 一条命令写齐必配四元组(实测值以本环境为例):
| 文件 | 变量 | 实测值 | 说明 |
|---|---|---|---|
| api/.env | APP_URL | http://192.168.1.172:8161 | 后端公开 URL |
| api/.env | FRONT_URL | http://192.168.1.172:8161 | 前端公开 URL |
| client/.env | NUXT_PUBLIC_APP_URL | http://192.168.1.172:8161 | 浏览器侧应用 origin |
| client/.env | NUXT_PUBLIC_API_BASE | http://192.168.1.172:8161/api | 浏览器侧 API base |
脚本同时生成并保留(重跑不覆盖)的密钥:APP_KEY(base64:…加密键)、JWT_SECRET(令牌签名)、FRONT_API_SECRET 与 NUXT_API_SECRET(前后端共享密钥,同值)。系统级真实密钥不要提交到版本库;备份 .env 时按密文管理。
setup 生成的 api/.env 关键运行项实测:APP_ENV=production、APP_DEBUG=false、CACHE_DRIVER/QUEUE_CONNECTION/SESSION_DRIVER=redis、LOG_CHANNEL=errorlog、MAIL_MAILER=log、JWT_TTL=1440、JWT_SKIP_IP_UA_VALIDATION=false、PUBLIC_UPLOADS_RATE_LIMIT_PER_MINUTE=30、PUBLIC_UPLOADS_RATE_LIMIT_PER_HOUR=300。
client/.env 还有一个脚本未写、模板自带的内部变量:NUXT_PRIVATE_API_BASE=http://ingress/api——SSR 服务端调用走 compose 网络内的 ingress,而非绕公网 origin。
⚠️ 实测确认 api/.env 中没有任何 DB_* 行:数据库连接完全由 compose environment 注入(DB_HOST=db、REDIS_HOST=redis、DB_DATABASE/DB_USERNAME/DB_PASSWORD=${…:-forge}、DB_CONNECTION=pgsql),容器内 printenv 实测与 compose 变量默认值 forge 一致。改数据库口令应在宿主 shell 或根目录 .env 设置 DB_PASSWORD 等变量(Compose 解析 ${…} 用的是 shell/根 .env,env_file 只负责向容器注入,两层机制不同)。
七、配置参数说明
与部署直接相关的 compose 内参数如下(本表已覆盖部署所需的全部取值):
| 变量 | 位置 | 实测值 | 影响 |
|---|---|---|---|
PHP_MEMORY_LIMIT | api 系 environment | 1G | 单进程内存上限 |
PHP_MAX_EXECUTION_TIME | api 系 environment | 600 | 长任务(导出)超时 |
PHP_UPLOAD_MAX_FILESIZE / PHP_POST_MAX_SIZE | api 系 environment | 64M | 上传大小上限 |
NGINX_MAX_BODY_SIZE | ingress environment | 64m | 经模板注入 client_max_body_size,需 ≥ PHP 上传限制 |
JWT_TTL | api/.env | 1440(分钟=24h) | 登录令牌有效期,实测 expires_in: 86400 |
OPNFORM_ANONYMOUS_TELEMETRY_DISABLED | api/.env | 默认未设置 | 置 true 关闭匿名遥测(仅 production+self_hosted 激活遥测) |
四层上传限制要一起对齐:nginx 64m = PHP 64M,而应用层 PUBLIC_UPLOADS_MAX_FILE_SIZE 默认 50000000(50 MB)——实际匿名附件上限取最小者 50 MB。
八、配置文件挂载
| 宿主文件 | 容器路径 | 用途 |
|---|---|---|
./api/.env | api 系 env_file | 后端全部配置 |
./client/.env | ui env_file | 前端配置 |
./docker/nginx.conf | ingress:/etc/nginx/templates/default.conf.template | 入口路由模板 |
nginx 模板用官方镜像的 envsubst 机制渲染,${NGINX_MAX_BODY_SIZE} 即由 compose environment 注入。实测模板核心路由(节选):
map $request_uri $api_uri {
~^/api(/.*$) $1;
default $request_uri;
}
server {
listen 80;
client_max_body_size ${NGINX_MAX_BODY_SIZE};
location / {
proxy_pass http://opnform-client:3000; # 页面与静态资源 → Nuxt SSR
}
location ^~ /api/_nuxt_icon/ {
proxy_pass http://opnform-client:3000; # 图标例外:仍回前端
}
location ~/(api|open|local\/temp|forms\/assets)/ {
try_files $uri $uri/ /index.php$is_args$args; # → Laravel
}
location ~ \.php$ {
fastcgi_pass opnform-api:9000;
fastcgi_param REQUEST_URI $api_uri; # 剥掉 /api 前缀再进 Laravel
}
}
解读:/api/* 经 fastcgi 进 Laravel 前由 map 剥前缀;/api/_nuxt_icon/ 被 ^~ 抢先规则送回前端——若自定义反代漏掉这条,管理后台图标会 404(官方 FAQ 场景)。Synology Container Manager 部署时须保持 api/.env、client/.env、docker/nginx.conf 相对目录结构完整(官方文档明示,nginx.conf 要挂成文件而非目录)。
九、等价 docker run
Compose 与 docker run 参数映射(供理解,不建议手敲 7 个容器——depends_on/healthcheck 网络编排是官方路径的核心价值):
| Compose 字段 | docker run 等价 |
|---|---|
image: postgres:16 | docker run -d --name opnform-db -e POSTGRES_DB=forge -e POSTGRES_USER=forge -e POSTGRES_PASSWORD=*** -v opnform_postgres-data:/var/lib/postgresql/data postgres:16 |
ports: - 8161:80 | docker run -d --name opnform-ingress -p 8161:80 -v $PWD/docker/nginx.conf:/etc/nginx/templates/default.conf.template -e NGINX_MAX_BODY_SIZE=64m nginx:1 |
env_file: ./api/.env | docker run --env-file ./api/.env … |
environment: DB_HOST: db | -e DB_HOST=db |
volumes: opnform_storage:…:rw | -v opnform_opnform_storage:/usr/share/nginx/html/storage |
command: ["php","artisan","queue:work"] | 镜像默认 entrypoint 后追加 php artisan queue:work |
network(默认网络) | docker network create opnform_default 后各容器 --network opnform_default |
十、常用运维命令
统一前缀 docker compose -f docker-compose.yml -f docker-compose.override.yml(下文简写 DC,在部署目录内执行):
DC ps # 服务与健康状态
DC logs -f api # 跟踪某服务日志(LOG_CHANNEL=errorlog → stdout)
DC exec -T api php artisan about # 运行时全景(见 10.1)
DC pull && DC up -d # 更新镜像并滚动重建(官方维护路径)
DC down # 整栈停止并删除容器(卷保留)
实测纠偏:改 .env 后 restart 不生效。docker compose restart api 后容器内 printenv OPNFORM_ANONYMOUS_TELEMETRY_DISABLED 仍返回 rc=1(未加载新行);必须 DC down api && DC up -d 重建容器才加载 env_file 新值(Compose v5.6.1 实测 down 可带服务名,仅移除该服务容器;伴随的 Network opnform_default Resource is still in use 警告无害)。api/api-worker/api-scheduler 共享同一 env_file,改一次参数三个服务都要重建。
实测新发现:重建 api/ui 后 ingress 会 502。nginx 启动时解析并缓存上游容器 IP,--force-recreate api 换 IP 后仍打旧地址,POST /api/login 实测返回 502 Bad Gateway。修复一条命令:
DC restart ingress
# 之后 /forms/g25-spqlvr title 恢复 "G25 反馈表单 - OpnForm"、/api/login 恢复 200
凡重建过 api 或 ui,顺手 restart ingress(nginx 配置未变时 restart 安全,无 env 加载问题)。
10.1 运行时确认(artisan about 实测节选)
Application Name ................................................... OpnForm
Laravel Version .................................................... 12.70.1
PHP Version ......................................................... 8.3.36
Environment ..................................................... production
Debug Mode ............................................................. OFF
URL ..................................................... 192.168.1.172:8161
Cache .............................................................. CACHED
Database ............................................................. pgsql
Queue ................................................................ redis
Session .............................................................. redis
public/storage ...................................................... LINKED
七项 drivers/缓存状态与 compose 注入一致,可作为部署后的验收基线。调度器健康检查(api-scheduler healthcheck 同款命令):
DC exec -T api php artisan app:scheduler-status --mode=check --max-minutes=3
# Scheduler is healthy. Last ran: 32 seconds ago
十一、常见问题
11.1 注册接口 422:hear_about_us 必填
自托管 /api/register 必须携带字符串字段 hear_about_us(实测错误原文 The hear_about_us field is required.);agree_terms 仅云端要求。
11.2 建表单 422:presentation_style/width/size 枚举
合法值实测为 presentation_style ∈ classic/focused、width ∈ centered/full、size ∈ sm/md/lg,传 UI 里见过的其他值会被拒。
11.3 提交成功但列表里没有
POST /api/forms/{slug}/answer 异步落库(Queue=redis,api-worker 消费),实测延迟 5-8 秒;若持续不见,查 DC logs api-worker 与 DC exec -T api php artisan about 的 Queue driver。
11.4 改 .env 不生效
见十、:restart 不加载 env_file 新值,必须 down <svc> + up -d;全栈改动用 DC down && DC up -d。
11.5 重建 api 后 502 Bad Gateway
nginx 缓存旧上游 IP,DC restart ingress 即恢复(实测闭环,见十、)。
11.6 容器卡在 "Waiting for DB to be ready"
官方已知问题:api/artisan 被 Windows 转成 CRLF 行尾。sed -i 's/\r$//' api/artisan 后重建(官方文档 docker.mdx 排障节)。
11.7 ingress 同时监听 80 和 8161
override 未加 !override 时 ports 为追加合并(实测踩坑),按 4.2 文件形态修正后 DC up -d ingress 重建。
11.8 setup 完成后无法再注册新用户
设计如此:自托管 setup 结束即关闭公开注册(实测 Registration is not allowed.),用管理员邀请;免费版实例上限 2 用户,更多用户需 Enterprise license。
十二、参考链接
- 官方 Docker 部署文档:https://docs.opnform.com/deployment/docker
- 环境变量总览:https://docs.opnform.com/configuration/environment-variables
- GitHub 仓库(v2.8.1):https://github.com/OpnForm/OpnForm
- API 镜像:https://hub.docker.com/r/jhumanj/opnform-api | 前端镜像:https://hub.docker.com/r/jhumanj/opnform-client
- 站内同类部署参考:《HeyForm Docker Compose 部署指南》、《Formbricks Docker Compose 部署指南》、《Bitpoll Docker Compose 部署指南》