Docker Compose 部署 Live Helper Chat 4.97v 指南
使用官方 docker-standalone 编排部署 Live Helper Chat 4.97v 的完整实测指南:remdex 官方镜像实查、七服务编排结构、.env 配置、安装向导与 Redis 会话/resque worker/cronjob 全链路验证
Docker Compose 部署 Live Helper Chat 4.97v 指南
目标:使用官方
docker-standalone编排仓,在宿主机上以 Docker Compose 一键拉起 Live Helper Chat 4.97v 全套服务(Nginx + PHP-FPM + cronjob + php-resque + cobrowse + Redis + MariaDB),完成.env配置、Web 安装向导、安装后配置核对,并以管理员登录、Redis 会话、resque worker 消费、cronjob 调度、前后台聊天闭环完成端到端验证。本文所有命令与回显均来自真实部署实测(Docker 29.9.2 / Compose v5.6.1,2026-10-26)。
一、环境信息
| 项目 | 本次实测值 |
|---|---|
| 宿主操作系统 | Debian 12.15 (bookworm) |
| Docker | 29.9.2(docker compose v5.6.1 子命令) |
| Live Helper Chat | 4.97v(GitHub 源码包 + 官方 lhc-php-resque 扩展仓) |
| 编排文件 | docker-standalone 仓 docker-compose-standard.yml |
| Compose 项目名 | lhc-497v-stack |
| 对外访问 | http://<宿主IP>:8081(LHC_PUBLIC_PORT) |
| 数据库暴露 | 仅宿主回环 127.0.0.1:3307(供宿主侧备份用) |
| cobrowse 暴露 | 仅宿主回环 127.0.0.1:31130 |
官方 Docker 部署入口是独立仓库 github.com/LiveHelperChat/docker-standalone,提供 standard(无 NodeJS)与 nodejs 两种编排。本篇按 README 推荐的 standard 版实测,所有服务均使用官方预构建镜像,无需本地 build。
二、官方镜像实查(以 Docker Hub 实查为准)
官方镜像发布在 Docker Hub 的 remdex 个人组织下(注意:不是 livehelperchat 组织——该组织在 Docker Hub 上实测为空,count: 0)。standard 编排实际引用 4 个官方镜像 + 3 个上游公共镜像:
| 镜像 | 用途 | tag | 实测大小 |
|---|---|---|---|
| remdex/livehelperchat-php | PHP-FPM 应用服务 | 仅 latest | 1.67 GB |
| remdex/livehelperchat-php-cronjob | 定时任务服务 | 仅 latest | 1.71 GB |
| remdex/livehelperchat-php-resque | 后台队列 worker | 仅 latest | 约 1.7 GB |
| remdex/livehelperchat-cobrowse | 屏幕共享 NodeJS 服务 | 仅 latest | 1.69 GB |
| nginx:latest | web 反代/静态 | latest | 243 MB |
| redis:alpine | 会话 + 队列后端 | alpine | 约 40 MB |
| mariadb | 数据库 | latest | 约 460 MB |
两个实测结论值得注意:
- 官方四个应用镜像只有 latest tag,没有版本号 tag。应用版本取决于你挂载进去的代码卷(
livehelperchat/lhc_web),镜像本身只是运行环境(php:8.5-fpm 基底 + gd/ldap/imagick/imap/redis 等扩展)。 - php-cronjob 与 php-resque 两个镜像的 Dockerfile 内容几乎完全一致(同样的 php:8.5-fpm 基底与扩展集),真正差异只在镜像内
/etc/cron.d/lhc的计划任务条目:cronjob 镜像内置 15 条 cron.php 任务,resque 镜像内置 3 条 worker 看护任务。
三、编排结构:一个项目七个服务
docker-compose-standard.yml 定义 7 个服务,全部挂在同一个 bridge 网络 code-network:
| 服务 | 镜像 | 挂载的关键卷 | 说明 |
|---|---|---|---|
| web | nginx:latest | 代码卷、nginx 配置 | 唯一对外入口,${LHC_PUBLIC_PORT}:80 |
| php | remdex/…-php | 代码卷、resque 扩展、scripts、php-fpm 覆盖配置 | PHP-FPM,处理全部动态请求 |
| php-cronjob | remdex/…-php-cronjob | 代码卷、resque 扩展、scripts | 常驻 cron -f,跑官方 15 条计划任务 |
| php-resque | remdex/…-php-resque | 代码卷、resque 扩展、scripts、.env 只读挂载 | 队列 worker 看护 |
| cobrowse | remdex/…-cobrowse | 无 | 屏幕共享,31130 端口仅回环 |
| redis | redis:alpine | 无 | db0 存会话,db1 存 resque 队列 |
| db | mariadb | ./dbdata | 数据库,3307 仅回环暴露 |
两个贯穿全部服务的挂载约定:
- 代码卷共享:
./livehelperchat/lhc_web:/code同时挂给 web/php/php-cronjob/php-resque 四个服务,代码只有一份; - 扩展卷:
./lhc-php-resque/lhcphpresque:/code/extension/lhcphpresque把队列扩展挂进应用目录,配合.env里的LHC_RESQUE_*变量工作。
四、准备代码与扩展(install.sh 做了什么)
官方 install.sh 脚本负责准备两个代码目录,它做的每一步都值得在部署前过一遍:
# 1. 克隆主程序(本篇实测用 4.97v 发行包/源码包替代 master)
git clone --branch master https://github.com/LiveHelperChat/livehelperchat.git --depth 10
# 2. 克隆 php-resque 扩展
git clone --branch master https://github.com/LiveHelperChat/lhc-php-resque.git --depth 10
# 3. 把 resque 入口脚本拷进应用根目录
cp lhc-php-resque/lhcphpresque/doc/resque.php livehelperchat/lhc_web
# 4. 生成扩展自身的配置文件
cp lhc-php-resque/lhcphpresque/settings/settings.ini.default.php \
lhc-php-resque/lhcphpresque/settings/settings.ini.php
随后是 4 处 sed 修改,各对应一个行为开关:
| sed 目标 | 修改 | 作用 |
|---|---|---|
| lhcphpresque/settings.ini.php | 'localhost' → 'redis' | 队列扩展连编排内的 redis 服务 |
| lhc_web/settings/settings.ini.default.php | force_virtual_host false → true | URL 不再带 index.php 前缀 |
| 同上 extensions 数组 | 启用 lhcphpresque | 安装时把扩展写进应用配置 |
| 同上 webhooks.worker | 'http' → 'resque' | Webhook 出站改走队列 worker |
实测完成后核对(三处都改到位才算就绪):
grep -n "force_virtual_host\|'lhcphpresque'\|'worker' => 'resque'" \
livehelperchat/lhc_web/settings/settings.ini.default.php
20: 'force_virtual_host' => true,
49: 'lhcphpresque'
99: 'worker' => 'resque',
实测踩坑:GitHub 源码包(约 37 MB)不含 Composer 依赖,直接挂载后首次访问报 500(详见第八节排障一)。要么用官方 Release 页的
4.97v-with-dependencies.tgz(65.6 MB,内置 vendor),要么进 php 容器手工php composer.phar install。从已装好的实例迁移代码时记得把lhc_web/lib/vendor/一起带走。
五、配置 .env
cd docker-standalone
cp .env.default .env
必须核对的关键字段(全文见 .env.default):
| 变量 | 默认值 | 说明 |
|---|---|---|
| LHC_SECRET_HASH | CHANGE_ME_TO_SOMETHING | 必改,应用安装时会原样写入 secrethash,用于签名 |
| LHC_PUBLIC_PORT | 8081 | web 服务对外端口 |
| MYSQL_ROOT_PASSWORD / MYSQL_DATABASE / MYSQL_USER / MYSQL_PASSWORD | lhcroot / lhc / lhc / lhc | 数据库四件套,安装向导里要填的 host 是 db |
| LHC_RESQUE_WORKERS_COUNT | 6 | resque worker 数 |
| LHC_RESQUE_QUEUE | * | 消费的队列名 |
| REDIS_BACKEND / REDIS_BACKEND_DB | redis:6379 / 1 | 队列后端地址与 db 号 |
| LHC_NODE_JS_PORT / REDIS_HOST | 8081 / redis | NodeJS 相关(standard 版可忽略) |
本次实测将 LHC_SECRET_HASH 设为自定随机串,其余保持默认。安装完成后可验证该值确实注入了应用配置:
docker exec lhc-497v-stack-php-1 grep secrethash /code/settings/settings.ini.php
'secrethash' => 'lhc497vstack9f3c81ab27e5',
六、启动与安装向导
6.1 拉镜像并启动
docker compose -f docker-compose-standard.yml pull
docker compose -f docker-compose-standard.yml up -d
实测启动后状态(项目名在 compose 文件里用顶层 name: 显式指定,容器名即 lhc-497v-stack-<服务>-1):
docker compose -f docker-compose-standard.yml ps --format 'table {{.Name}}\t{{.Status}}'
NAME STATUS
lhc-497v-stack-cobrowse-1 Up 10 minutes
lhc-497v-stack-db-1 Up 10 minutes
lhc-497v-stack-php-1 Up 10 minutes
lhc-497v-stack-php-cronjob-1 Up 10 minutes
lhc-497v-stack-php-resque-1 Up About a minute
lhc-497v-stack-redis-1 Up 10 minutes
lhc-497v-stack-web-1 Up 10 minutes
6.2 修正代码目录属主
首次访问前,按官方 README 把代码卷内三个运行时目录的属主交给容器内的 www-data(php:8.5-fpm 官方镜像中该用户为 uid/gid 33,宿主机上直接 chown 33:33):
cd livehelperchat/lhc_web
chown -R 33:33 cache settings var
ls -ld cache settings var
drwxrwxr-x 6 www-data www-data 4096 cache
drwxrwxr-x 2 www-data www-data 4096 settings
drwxrwxr-x 14 www-data www-data 4096 var
6.3 进入安装向导
浏览器访问 http://<宿主IP>:8081/,会自动 302 跳转到安装向导:
GET / -> 302 Location: /site_admin/install/install
注意跳转后的 URL 是 /site_admin/install/install——没有 index.php 前缀,这正是第四节 force_virtual_host => true 的效果。与源码部署(URL 形如 /index.php/site_admin/...)相比,Compose 版的 URL 更短,nginx 配置已内置对应 rewrite。
安装向导共三步:
- 环境检查:实测 22 项全部 Yes(14 个目录写权限 + 7 个 PHP 扩展 + PHP 最低版本);
- 数据库:按
.env填写——Usernamelhc、Passwordlhc、Hostdb(服务名,不是 127.0.0.1)、Port3306、Namelhc; - 初始管理员:admin / 强口令 / 邮箱 / 姓名与部门。
第三步提交后实测返回:
Installation was completed
Installation is complete. You can start by adding users and departments.
6.4 安装结果核对
应用配置在安装瞬间落盘为 settings/settings.ini.php,逐项核对关键值:
docker exec lhc-497v-stack-php-1 sh -c \
"grep -A3 'extensions' /code/settings/settings.ini.php | head -4; \
grep -B1 \"'worker'\" /code/settings/settings.ini.php | head -3; \
grep -A6 \"'db'\" /code/settings/settings.ini.php | head -7"
'extensions' =>
array (
0 => 'lhcphpresque',
),
'enabled' => '1',
'worker' => 'resque',
'db' =>
array (
'host' => 'db',
'user' => 'lhc',
'password' => 'lhc',
'database' => 'lhc',
数据库侧实测建表 156 张,管理员账号已写入:
SELECT COUNT(*) FROM information_schema.tables WHERE table_schema='lhc';
SELECT username FROM lh_users;
tables_cnt
156
username
admin
七、安装后验证:四个维度
7.1 管理后台登录与会话落在 Redis
访问 http://<宿主IP>:8081/site_admin/user/login,用初始管理员登录,进入仪表盘可见 Hello Admin!。
会话存储验证:php-fpm 的池配置(conf/php-fpm/zz-lhc.conf)把 session 指向了 redis,登录后 Redis db0 出现会话键:
docker exec lhc-497v-stack-redis-1 redis-cli -n 0 keys 'PHPREDIS_SESSION*' | head -3
PHPREDIS_SESSION:f0d4296c28cd594d64e5f7c3ae57512b
PHPREDIS_SESSION:19fb88d002a82f91871e8c8bcb544acf
PHPREDIS_SESSION:250ac5b89b33fdbbdce0e60e2bb12f1a
7.2 坐席在线与前台聊天闭环
与源码部署一样,坐席默认离线,前台聊天窗此时显示 Chat is currently unavailable. Please try again later.。在后台把管理员账号置为长期在线(也可用接口):
TOKEN=$(grep -oE "csrf_token = '[a-f0-9]+'" 页面源码 | grep -oE '[a-f0-9]{32}')
curl -b 会话Cookie -H "X-CSRFToken: $TOKEN" \
http://127.0.0.1:8081/site_admin/user/setalwaysonline/true
{"error":false}
之后前台 /index.php/chat/chatwidget(无 virtual host 时)或 /chat/chatwidget 出现提问表单,提交后聊天进入等待队列。数据库验证:
SELECT id,dep_id,nick,status FROM lh_chat;
SELECT id,chat_id,user_id,LEFT(msg,50) FROM lh_msg;
id dep_id nick status
1 1 Visitor 0
id chat_id user_id LEFT(msg,50)
1 1 0 Hello, testing docker stack chat.
坐席在后台 Chats List 打开会话回复,实测三条消息完整落库(user_id -1 为系统事件消息):
id chat_id user_id LEFT(msg,60)
1 1 0 Hello, testing docker stack chat.
2 1 1 Hello! Reply from docker stack operator.
3 1 -1 Admin User has accepted the pending chat by sending a messag
7.3 resque worker 消费队列
php-resque 服务启动后,实测其 cron 计划(@reboot 启动 + 每分钟看护,见第八节排障三)拉起 worker,数量与 LHC_RESQUE_WORKERS_COUNT=6 一致:
docker exec lhc-497v-stack-php-resque-1 ps aux | grep resque | grep -v grep
/usr/local/bin/php resque.php
resque-1.2: Waiting for * x6
Redis db1 中出现 worker 注册与统计键,安装期积压的 lhc_imap_copy 队列被即时消费清零:
docker exec lhc-497v-stack-redis-1 redis-cli -n 1 keys 'resque*'
docker exec lhc-497v-stack-redis-1 redis-cli -n 1 llen resque:queue:lhc_imap_copy
resque:queues
resque:stat:processed
resque:stat:processed:73609c0ee037:30:* ...
resque:worker:73609c0ee037:30:*:started ...
resque:workers
0
7.4 cronjob 调度
php-cronjob 服务常驻 cron -f,按镜像内 /etc/cron.d/lhc 的 15 条计划执行(每分钟的 workflow/webhook/transfer、每 5 分钟的 cron_5m、每日的 archive/encrypt/report 等)。实测每分钟调度已生效:
docker exec lhc-497v-stack-php-cronjob-1 ps aux | head -6
root 1 cron -f
root 576 CRON -f
root 577 CRON -f
root 578 CRON -f
www-data 586 /bin/sh -c cd /scripts && ./workflow.sh >> /dev/null 2>&1
7.5 运行状态端点
编排内置了监控端点(网络内可达,nginx 配置默认放行私网地址段):
docker exec lhc-497v-stack-web-1 curl -s 'http://web/fpm-status?json'
{"pool":"www","process manager":"dynamic","start time":1793005202,
"start since":683,"accepted conn":22,"listen queue":0,
"idle processes":4,"active processes":1,"total processes":5,
"max active processes":1,"max children reached":0,
"slow requests":0,"memory peak":8388608}
http://web/nginx_status 同理可取 nginx 连接计数。日志按服务取:docker compose -f docker-compose-standard.yml logs php(PHP 错误走 stderr)与 logs web(nginx)。
八、排障实录(三个首启真问题)
8.1 首页 500:Failed opening required 'lib/vendor/autoload.php'
现象:栈全部 Up,但 GET / 返回 500,php 容器日志:
PHP Warning: require_once(lib/vendor/autoload.php): Failed to open stream:
No such file or directory in /code/index.php on line 30
PHP Fatal error: Uncaught Error: Failed opening required 'lib/vendor/autoload.php'
原因:挂载的代码来自 GitHub 源码包,不含 Composer 依赖目录。
解决:改用官方 Release 的 4.97v-with-dependencies.tgz 部署代码卷;或进 php 容器按 getcomposer.org 流程装 composer.phar 后执行 php composer.phar install。实测从已有实例 docker cp 拷贝 lhc_web/lib/vendor/(144 MB)后立即恢复,GET / 变为 302 进入安装向导。
8.2 安装向导 500:Directory cache/cacheconfig/ not writable!
现象:代码就绪后访问向导直接输出异常栈。
原因:bind mount 进容器的 cache/settings/var 在宿主上是 root 属主,容器内 php-fpm 以 www-data(uid 33)运行无法写入。
解决:宿主上 chown -R 33:33 cache settings var(官方 README 的容器内 chown 方案等价)。
8.3 php-resque 容器起来了但 worker 未运行
现象:容器 Up,进程里只有 cron -f,Redis 无 resque worker 注册键。
原因:resque 镜像内的 /etc/cron.d/lhc 靠 @reboot ... phpresque.sh 拉起 worker,而容器场景下 cron 的 @reboot 不一定触发;备用的每分钟看护脚本 resque.sh 要求 /scripts/.enable-cron 标志文件存在才会启动 worker。
解决:手动执行一次 docker exec -d lhc-497v-stack-php-resque-1 /bin/sh -c 'cd /scripts && ./phpresque.sh';生产环境可按官方脚本约定 touch conf/scripts/.enable-cron 让看护脚本自动拉起。
8.4 补充:php-resque 官方镜像拉取受阻的等效替代
国内网络环境下 remdex/php-resque 镜像经多个加速通道长时间拉不完时,可用已拉取的 cronjob 镜像等效替代(两者 Dockerfile 完全同源):
docker tag remdex/livehelperchat-php-cronjob:latest remdex/livehelperchat-php-resque:latest
并在 compose 的 php-resque 服务追加一行挂载,把 resque 版计划任务盖回镜像内的 cronjob 版:
volumes:
- ./Dockerfiles/php-resque/lhc/cron:/etc/cron.d/lhc:ro
实测该组合下 worker 正常拉起并消费队列(见 7.3)。
九、日常运维
- 更新:
git pull三个仓库(主程序/php-resque/编排仓)→ 必要时docker compose build --no-cache或pull→down && up -d;进 php 容器执行php composer.phar update && php composer.phar install,再跑php cron.php -s site_admin -c cron/util/update_database -p local与php cron.php -s site_admin -c cron/util/clear_cache。 - 数据库备份:容器内无 mysqldump,官方设计是从宿主走仅回环暴露的
127.0.0.1:3307连接 MariaDB 做导出。 - HTTPS:由外层反代或改造 web 服务实现(官方 README 提供 certbot webroot 方案与站点配置样例);走反代时记得开启
settings.ini.php的proxy_mode并配置转发头。 - 安装后推荐设置(官方 README「After install todo」):Screen sharing 启用 NodeJs 支持并填
/wsnodejs/socket.io;Online tracking 勾选两项 cronjob 化;Workflow 勾选离场转移;settings.ini.php与 lhcphpresque 配置里的site_address填实际站点地址。
十、小结
| 验证维度 | 结果 |
|---|---|
| 七服务编排启动 | 全部 Up,容器名前缀 lhc-497v-stack |
| .env 注入 | secrethash/worker 数/队列 db 均按 .env 生效 |
| 安装向导 | 三步完成,156 张表落库 |
| Redis 会话 | db0 PHPREDIS_SESSION 键随登录出现 |
| 聊天闭环 | 访客发问 → 坐席接管回复,3 条消息落库 |
| resque worker | 6 worker 注册,积压队列消费归零 |
| cronjob | 15 条计划任务每分钟调度生效 |
Compose 版与源码部署的核心差异就三点:代码以卷挂载方式进容器、URL 少了 index.php 前缀(force_virtual_host)、会话与队列天然落在编排内的 Redis。记住第四节"源码包无 vendor"、第八节三个首启问题,部署基本可以一次走通。相关阅读:环境与选型见《Live Helper Chat 4.97v 介绍与选型指南》,源码方式部署见《Debian 12 安装 Live Helper Chat 4.97v 指南》,安装后的配置文件逐项说明见本专栏下一篇配置详解。