OpnForm v2.8.1 常用 CLI 命令与工具详解
OpnForm v2.8.1 自托管实例的 CLI 工具链实战:docker compose 编排、artisan 诊断/缓存/队列、psql 与 redis-cli 直连、pg_dump 备份与 curl 健康探测,全部命令与回显取自真实部署实例实测。
OpnForm v2.8.1 常用 CLI 命令与工具详解
目标:把 OpnForm v2.8.1 自托管实例日常运维要用的 CLI 工具链——Docker Compose 编排命令、Laravel
artisan管理命令、psql/redis-cli直连工具、pg_dump备份与 curl 健康探测——逐条讲清用法、参数与真实回显。所有命令均在 2026-11-01/02 部署完成的真实实例上实测执行。
一、环境信息
- 宿主:Linux x86_64(内网 IP
192.168.1.172),Docker29.9.2(Docker version 29.9.2, build a82e528),Docker Composev5.6.1 - OpnForm:
v2.8.1,Laravel Framework12.70.1(artisan --version实测),PHP8.3.36,PostgreSQL16.15,Redis7 - 部署目录:
/opt/data/quzuo/tmp/opnform/OpnForm,对外端口8161 - 7 服务:
api/api-worker/api-scheduler(同一镜像jhumanj/opnform-api:latest)、ui(jhumanj/opnform-client:latest)、db(postgres:16)、redis(redis:7)、ingress(nginx:1) - artisan 在容器内的路径:
/usr/share/nginx/html/artisan(healthcheck 即写全路径) - 演示账号:
g25admin@example.com/G25test@12345 - 实例状态基线:forms=1(slug
g25-spqlvr)、form_submissions=2、users=1(psql 实测)
本文所有 compose 命令统一使用双文件前缀(override 文件把入口端口钉在 8161):
cd /opt/data/quzuo/tmp/opnform/OpnForm
docker compose -f docker-compose.yml -f docker-compose.override.yml <子命令>
二、工具概览
| 工具 | 入口 | 职责 |
|---|---|---|
| docker compose | 宿主,部署目录内 | 起停/重建/日志/exec 七服务 |
| php artisan | exec -T api php artisan <cmd> | 运行时诊断、迁移、缓存、队列、调度器状态 |
| psql / pg_isready | exec -T db psql / exec -T db pg_isready | 数据核对、连接检查、绕过 artisan 的库级查询 |
| redis-cli | exec -T redis redis-cli <cmd> | 缓存/队列/会话侧排查 |
| pg_dump | exec -T db pg_dump <db> | 逻辑备份 |
| curl | 宿主 | /api/healthcheck 与 API 冒烟 |
表中入口列省略了公共前缀
docker compose -f docker-compose.yml -f docker-compose.override.yml(见第一章);正文所有命令均给出完整形式,可直接照抄执行。
💡 技术拓展:OpnForm 备份不止 pg_dump 一条路。对比——
渠道 覆盖 特点 pg_dump 逻辑备份 数据库 44 张表 跨版本可移植、可单表恢复;不含上传附件 数据卷快照/cp postgres-data + opnform_storage 全量但绑定存储驱动与同版本恢复 PostgreSQL 流复制 数据库实时副本 高可用级,单实例自托管一般不需要 本方案采用 pg_dump + 单独打包
opnform_storage卷的组合(见 4.6),附件目录不可漏。
三、前置条件
- 实例已按 《OpnForm v2.8.1 Docker Compose 部署指南》 部署且 setup 完成。
- 七服务 healthy(实测基线,见 4.1 的
ps回显)。 exec建议带-T(禁用 TTY 分配):本文所有实测回显均以-T采集,管道/脚本环境下不加-T可能报the input device is not a TTY。
四、各工具详解
4.1 docker compose 编排命令
ps——状态总览:
docker compose -f docker-compose.yml -f docker-compose.override.yml ps
实测回显(7 服务全 healthy,仅 ingress 有宿主端口):
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
解读:STATUS 列的 (healthy) 来自 compose 各服务 healthcheck——api 用 php artisan about、worker 用 pgrep -f 'php artisan queue:work'、scheduler 用 artisan app:scheduler-status --mode=check --max-minutes=3、ui 用 wget --spider -q http://localhost:3000/login、db 用 pg_isready、redis 用 redis-cli ping、ingress 用 nginx -t && curl -f http://localhost/。排障时先定位哪个服务 unhealthy,再按对应 healthcheck 命令手工复现。
logs——日志跟踪:
docker compose -f docker-compose.yml -f docker-compose.override.yml logs --tail=5 api
实测回显:
opnform-api | 172.21.0.8 - 01/Nov/2026:20:25:36 +0000 "POST /index.php" 422
opnform-api | 172.21.0.8 - 01/Nov/2026:20:26:06 +0000 "POST /index.php" 422
opnform-api | 172.21.0.8 - 01/Nov/2026:20:26:06 +0000 "POST /index.php" 422
opnform-api | 172.21.0.8 - 01/Nov/2026:20:26:12 +0000 "POST /index.php" 400
opnform-api | 172.21.0.8 - 01/Nov/2026:20:26:12 +0000 "POST /index.php" 422
解读:LOG_CHANNEL=errorlog 使 Laravel 请求日志走 PHP error_log → 容器 stdout;来源 IP 172.21.0.8 是 ingress 容器、请求路径记为 /index.php 是 fastcgi 转发的结果(原始 URI 由 REQUEST_URI 参数传入)。422 行对应本文写作期间的参数纠偏实验请求,属预期。logs -f <svc> 实时跟踪。
down/up——单服务重建(改 env 唯一生效路径):
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
实测:Compose v5.6.1 接受 down 带服务名,仅停止并移除该服务容器;伴随输出 Network opnform_default Resource is still in use 为无害警告(网络被其余服务占用,删不掉属正常)。改 api/.env 后 restart api 实测不加载新值(容器内 printenv 仍 rc=1),必须走本对命令;api-worker/api-scheduler 共享同一 env_file,应一并重建。重建 api/ui 后补一条 docker compose -f docker-compose.yml -f docker-compose.override.yml restart ingress,规避 nginx 缓存旧上游 IP 导致的 502(实测闭环)。
pull + up -d——官方更新路径:
docker compose -f docker-compose.yml -f docker-compose.override.yml pull
docker compose -f docker-compose.yml -f docker-compose.override.yml up -d
官方维护文档(docker.mdx)给出的升级两步:先 pull 新镜像,再 up -d 只重建镜像有变化的服务。用 latest 标签时建议更新前先在容器内记录 printenv APP_VERSION_DOCKER(本环境实测 2.8.1),更新后复查确认版本推进。
4.2 artisan 运行时诊断
artisan 命令统一通过 exec 进入 api 容器执行(完整前缀如下,本文所有 artisan 命令均可照抄):
docker compose -f docker-compose.yml -f docker-compose.override.yml exec -T api php artisan <命令>
about——全景体检(api healthcheck 同款):
Application Name ................................................... OpnForm
Laravel Version .................................................... 12.70.1
PHP Version ......................................................... 8.3.36
Environment ..................................................... production
Debug Mode ............................................................. OFF
URL ..................................................... 192.168.1.172:8161
Maintenance Mode ....................................................... OFF
Config / Events / Routes / Views ................................. CACHED
Cache / Queue / Session .............................................. redis
Database ............................................................. pgsql
Logs .............................................................. errorlog
Mail ................................................................... log
public/storage ...................................................... LINKED
输出节选(实测首尾,完整回显含 Composer/Sentry 段)。要点:Debug Mode=OFF 是生产硬指标;Mail=log 表示邮件不外发(见 《配置参数详解》 5.10 与 FAQ 7.4);Sentry 段 Data Collection=NOT SET / Enabled=MISSING DSN 说明未配置错误上报属正常默认。
--version:
docker compose -f docker-compose.yml -f docker-compose.override.yml exec -T api php artisan --version
# Laravel Framework 12.70.1
migrate:status——迁移核对:
docker compose -f docker-compose.yml -f docker-compose.override.yml exec -T api php artisan migrate:status
实测输出节选(实测首尾):
Migration name .............................................. Batch / Status
2014_10_12_000000_create_users_table ............................... [1] Ran
2014_10_12_100000_create_password_resets_table ..................... [1] Ran
2016_06_01_000001_create_oauth_auth_codes_table .................... [1] Ran
…
2026_10_22_000000_add_agent_form_draft_version_history ............. [1] Ran
全部 [1] Ran:setup 期一次性跑完全部迁移、批次号=1、无 Pending。升级镜像后若出现 Pending,由 api 容器入口脚本自动补跑;人工核对用本命令。
db:show / db:table——库级概览(含镜像缺陷实测):
docker compose -f docker-compose.yml -f docker-compose.override.yml exec -T api php artisan db:show
实测回显(输出节选(实测首尾)——摘要段完整,尾部为崩溃报错原文):
PostgreSQL ................................. 16.15 (Debian 16.15-1.pgdg13+2)
Connection ........................................................... pgsql
Database ............................................................. forge
Host .................................................................... db
Port .................................................................. 5432
Username ............................................................. forge
Open Connections ......................................................... 6
Tables .................................................................. 44
In Number.php line 453:
The "intl" PHP extension is required to use the [format] method.
⚠️ 实测发现:官方 api 镜像未装 PHP intl 扩展,db:show/db:table 在格式化表体积时必崩(db:table forms 同样先输出 Columns ... 67 后同错)。摘要段仍可用;需要逐表数据时改用 psql(4.5)。
4.3 artisan 缓存与配置管理
四条命令实测回显(前后成套执行,最后重新 config:cache 恢复基线):
docker compose -f docker-compose.yml -f docker-compose.override.yml exec -T api php artisan config:cache
# INFO Configuration cached successfully.
docker compose -f docker-compose.yml -f docker-compose.override.yml exec -T api php artisan config:clear
# INFO Configuration cache cleared successfully.
docker compose -f docker-compose.yml -f docker-compose.override.yml exec -T api php artisan route:clear
# INFO Route cache cleared successfully.
docker compose -f docker-compose.yml -f docker-compose.override.yml exec -T api php artisan cache:clear
# INFO Application cache cleared successfully.
docker compose -f docker-compose.yml -f docker-compose.override.yml exec -T api php artisan config:cache # 恢复:about 的 Config=CACHED 基线
# INFO Configuration cached successfully.
用途区分:config:cache 把 .env+config 编译为缓存(about 里 Config=CACHED 即此态),改 .env 后必须重建容器再跑才有意义;cache:clear 清的是应用数据缓存(redis db),官方维护文档把它列为前端异常/设置不刷新时的第一动作;route:clear 清路由缓存。storage:link 幂等验证:
docker compose -f docker-compose.yml -f docker-compose.override.yml exec -T api php artisan storage:link
# ERROR The [public/storage] link already exists.
报错原文即"已链接",与 about 的 public/storage=LINKED 互证,无需处理。
4.4 artisan 队列与调度器
queue:work:常驻进程由 api-worker 服务承担(compose command: ["php","artisan","queue:work"]),不要在 api 里手工再起第二个(会抢任务)。验证 worker 活着用 healthcheck 同款命令:
docker compose -f docker-compose.yml -f docker-compose.override.yml exec -T api-worker pgrep -f 'php artisan queue:work'
# 1
回显 1 为进程 PID(容器内主进程)。提交落库依赖它:匿名 answer 返回 submission_id:null 属正常异步,约 5-8 秒(实测)后可见;持续不可见先查这里,再看 logs api-worker。
schedule:work 与 app:scheduler-status:api-scheduler 常驻 php artisan schedule:work。OpnForm 自定义命令 app:scheduler-status 记录/检查调度器心跳(artisan list 实测描述:"Records or checks the scheduler last run timestamp, conditional on self-hosted mode."):
docker compose -f docker-compose.yml -f docker-compose.override.yml exec -T api php artisan app:scheduler-status --mode=check --max-minutes=3
# Scheduler is healthy. Last ran: 32 seconds ago
rc=0。这正是 api-scheduler healthcheck 的判据:调度器超过 3 分钟没跑即 unhealthy。
4.5 psql 与 redis-cli 直连
pg_isready(db healthcheck 同款):
docker compose -f docker-compose.yml -f docker-compose.override.yml exec -T db pg_isready
# /var/run/postgresql:5432 - accepting connections
psql 数据核对(口令 forge 由 compose ①层注入,见《配置参数详解》5.3):
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
与 API 侧闭环结果一致(1 表单 / 2 提交 / 1 用户)。db:table 崩溃时的表结构替代查询——psql 的 \d forms 实测:67 列(与 db:table forms 崩溃前打印的 Columns ... 67 互证),关键列 properties json not null、visibility 默认 public、presentation_style 默认 classic、size 默认 md、width 默认 centered(与建表单 API 的枚举校验一一对应);索引 forms_pkey / forms_slug_index / forms_workspace_id_index,外键 creator_id → users.id(CASCADE)。
redis-cli(redis healthcheck 同款):
docker compose -f docker-compose.yml -f docker-compose.override.yml exec -T redis redis-cli ping
# PONG
队列积压排查:redis-cli llen queues:default(Laravel redis 队列的默认列表键)实测回显 0;redis-cli --scan --pattern 'queues*' 实测返回空——当前没有任何 queues:* 键(llen 对不存在的键同样返回 0,两者互证无积压)。有积压时 llen 给出等待任务数,配合 logs api-worker 定位消费端。
4.6 pg_dump 逻辑备份
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
实测产物:backup-test.sql.gz 14001 字节(空库+2 提交规模)。恢复:gunzip -c 文件 | docker compose -f docker-compose.yml -f docker-compose.override.yml exec -T db psql -U forge -d forge。附件卷单独打包:
docker run --rm -v opnform_opnform_storage:/data -v /opt/data/quzuo/tmp/opnform:/backup alpine \
tar czf /backup/storage-$(date +%F).tar.gz -C /data .
⚠️ 注意:卷名带项目前缀
opnform_(setup.log 实测Volume opnform_opnform_storage Creating),换目录部署会新建空卷,备份前先docker volume ls | grep opnform核对。
4.7 curl 健康探测与 API 冒烟
自托管专用健康端点(仅 self_hosted 注册,api/routes.php L54-56):
curl -s http://192.168.1.172:8161/api/healthcheck
# {"status":"ok","dependencies":{"database":true,"redis":true}}
适合拨测:一次请求同时验证 ingress→api→pgsql→redis 全链路。冒烟三连(实测):
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/login -H 'Content-Type: application/json' \
-d '{"email":"g25admin@example.com","password":"G25test@12345","remember":false}' | head -c 60
# {"token":"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJod
要点:登录路径 /api/login(/api/auth/login 实测 404);响应字段名 token 而非 access_token;expires_in:86400 对应 JWT_TTL=1440 分钟。
4.8 artisan 命令清单速查
artisan list 实测节选(本文档涉及项):
Laravel Framework 12.70.1
about Display basic information about your application
app:scheduler-status Records or checks the scheduler last run timestamp, conditional on self-hosted mode.
cache:clear Flush the application cache
config:cache Create a cache file for faster configuration loading
db:monitor Monitor the number of connections on the specified database
db:seed Seed the database with records
db:show Display information about the given database
db:table Display information about the given database table
db:wipe Drop all tables, views, and types
migrate Run the database migrations
migrate:fresh / migrate:install / migrate:refresh / migrate:reset / migrate:rollback
⚠️ 注意:
db:wipe、migrate:fresh、migrate:reset会清空/重建全部数据,生产环境禁用;db:monitor可循环观察连接数(db:show实测 Open Connections=6)。
五、注意事项
- exec 一律
-T:非交互环境(脚本、管道)不加-T可能因 TTY 分配失败;-T下回显可直接入文档入日志。 - 三个 api 服务共享镜像与 env_file:
artisan命令在哪个容器执行结果等价,但长驻进程(queue:work/schedule:work)只在 worker/scheduler 里跑;改 api/.env 后三个服务一起 down/up,避免配置漂移(实测三容器 printenv 同步生效)。 - 重建 api/ui 后 restart ingress:nginx 缓存上游 IP,不重启会 502(实测闭环,见 4.1)。
- db:show/db:table 崩溃是镜像缺 intl 扩展:摘要段可用,明细走 psql;不要误判为数据库故障。
- Windows 检出源码注意 LF:
api/artisan变 CRLF 会让容器卡 "Waiting for DB to be ready",修复sed -i 's/\r$//' api/artisan(官方排障)。 down单服务的网络警告无害:Network opnform_default Resource is still in use不影响该服务重建。
六、常见问题
6.1 db:show 报 "The intl PHP extension is required"
官方 api 镜像已知限制(实测),命令已输出库版本/表数摘要后在体积格式化处崩溃。替代:exec -T db psql -U forge -d forge -c "\dt" 或 -c "select count(*) from <表>"。
6.2 提交一直不落库
顺序排查:exec -T api-worker pgrep -f 'php artisan queue:work'(实测回显 PID)→ logs api-worker → 在 api 容器执行 php artisan about(完整前缀见 4.2)确认 Queue=redis → exec -T redis redis-cli ping(PONG)。队列驱动 redis 时 worker 挂了提交永远不可见。
6.3 api-scheduler 显示 unhealthy
healthcheck 判据是 app:scheduler-status --mode=check --max-minutes=3(超 3 分钟未跑即失败)。手工执行实测 Scheduler is healthy. Last ran: 32 seconds ago;若报 stale,logs api-scheduler 看 schedule:work 是否异常,必要时按 4.1 重建该服务。
6.4 改完 .env 用 restart 无效
restart 不加载 env_file 新值(实测 printenv rc=1),必须 down <svc> && up -d,随后 restart ingress。详见《配置参数详解》3.2 的闭环实验。
6.5 前端页面异常/设置不刷新
官方维护路径:exec -T api php artisan cache:clear(实测 INFO Application cache cleared successfully.),必要时 ui 服务 down ui && up -d ui。
七、参考链接
- 官方 Docker 部署与维护命令:https://docs.opnform.com/deployment/docker
- 官方环境变量文档:https://docs.opnform.com/configuration/environment-variables
- Laravel Artisan 官方文档:https://laravel.com/docs/12.x/artisan
- 站内配套:《OpnForm v2.8.1 Docker Compose 部署指南》、《OpnForm v2.8.1 配置参数详解》
- 同类 CLI 参考:《HeyForm 常用 CLI 命令与工具详解》、《Formbricks 常用 CLI 命令与工具详解》、《Bitpoll 常用 CLI 命令与工具详解》