Files
crmchat/部署文档.md
T

9.5 KiB
Raw Blame History

CRMChat 客服系统 — Docker 部署文档

环境要求

  • Docker 24+
  • Docker Compose v2+
  • 端口 18091(可自定义)

快速开始

国内网络(默认,镜像加速)

# 1. 复制环境变量
cp .env.docker .env

# 2. 一键启动
docker compose -f docker-compose.yml -f docker-compose.cn.yml up -d

海外网络

cp .env.docker .env
docker compose up -d

主服务器部署与更新(8.133.254.174)

生产环境部署在主服务器阿里云,IP 直连 18091 端口(无域名、无证书,勿再使用已废弃的 kefu.wildcs2.com)。

服务器访问

ssh -i "C:/data/密钥/祝总阿里云.pem" root@8.133.254.174
  • 部署目录:/www/projects/crmchat(gitea clone,master 分支)
  • 访问地址:http://8.133.254.174:18091(阿里云安全组已放行 18091/TCP)
  • 代码推送:git push origin master(偶发认证失败,重试一次即可)

更新部署标准流程(顺序不可颠倒)

# 本地:提交并推送
git push origin master

# 服务器:拉取 → 重建 php 镜像 → 重建容器 → 重启 nginx → 健康检查
cd /www/projects/crmchat
git pull
docker compose build php
docker compose up -d php
docker restart crmchat-nginx
curl -s -o /dev/null -w "%{http_code}\n" http://localhost:18091/chat/index   # 预期 200

每一步都有原因,跳过或换序会出事故:

步骤 为什么
docker compose build php 必须在任何重启之前 旧镜像的 entrypoint 没有空库守卫,对旧镜像容器执行 restart 会无条件重导初始化 SQL,清空整个数据库(2026-09-25 已踩:清掉了用户会话数据)。新镜像的 entrypoint 检测到库已初始化(eb_system_admin 哨兵表存在)会跳过导入
up -d php 而非 restart php 新 entrypoint 在新镜像里,restart 不换镜像;up -d 重建容器才会用新镜像
docker restart crmchat-nginx 收尾 ① php 容器重建后 IP 变化,nginx 缓存旧 IP → 502;② nginx.conf 是单文件 bind mount,git pull 替换文件后容器仍指向旧 inode,nginx -s reload 读到的还是旧配置,必须 restart 容器重新挂载

已固化的构建/配置修改(勿回退)

  • docker/php/Dockerfile:apt 源切阿里云镜像。原因:php:7.4-cli 基于 Debian bullseye,LTS 已于 2026-08-31 结束,deb.debian.org 从 ECS 访问超时、各镜像站陆续清理 bullseye 包(404);security 源在镜像站/archive 迁移空窗期同样 404,暂去掉(基础镜像本身是 2022 快照,无实际回退;中期应升级基础镜像到受支持的 Debian/PHP 版本)
  • nginx/nginx.conf:absolute_redirect off。原因:容器内 nginx 监听 80、对外映射 18091,nginx 发绝对 Location 重定向时用的是容器内端口(80),外部端口 18091 会丢失
  • entrypoint.sh:空库守卫 + eb_system_admin 哨兵表检查(见上)

忘记密码重置方法

# 在服务器上执行(以 admin 为例,kefu 同理换表名字段)
cd /www/projects/crmchat
MYSQLPASS=$(grep '^MYSQL_ROOT_PASSWORD=' .env | cut -d= -f2)
NEWPASS=$(openssl rand -hex 8); echo "新密码: $NEWPASS"
HASH=$(docker exec crmchat-php php -r "echo password_hash(\$argv[1], PASSWORD_DEFAULT);" "$NEWPASS")
docker exec crmchat-mysql mysql -uroot -p"$MYSQLPASS" crmeb_chat \
  -e "UPDATE eb_system_admin SET pwd='$HASH' WHERE account='admin';"
# kefu 坐席:UPDATE eb_chat_service SET password='$HASH' WHERE account='kefu';

访问地址

本地开发默认 admin123 / kefu123;主服务器(8.133.254.174:18091)的 admin / kefu 密码已于 2026-09-25 重置为随机值(不再使用默认密码),重置方法见「主服务器部署与更新」。

入口 地址 账号 密码
后台管理 http://localhost:18091/admin admin admin123
客服坐席 http://localhost:18091/kefu kefu kefu123
用户端 http://localhost:18091/chat/index?token=82b739d20bd2d29dc67f112b7f193683 — —
Demo 页 http://localhost:18091/demo — —

容器架构

┌──────────┐     ┌──────────────┐     ┌───────────┐     ┌────────┐
│  Nginx   │────▶│ PHP 7.4 +    │────▶│  MySQL 5.7│     │ Redis  │
│  :18091   │     │ Swoole 4     │     │  :3306    │     │ :6379  │
└──────────┘     └──────────────┘     └───────────┘     └────────┘
     │                  │
     ▼                  ▼
 静态文件           ThinkPHP 6 路由
 admin/             /api/* /kefu /install
 demo/              WebSocket /ws
容器 镜像 说明
crmchat-nginx nginx:alpine 反向代理 + 静态文件
crmchat-php 自构建 (PHP 7.4 + Swoole 4.8 + Redis) ThinkPHP 6 应用
crmchat-mysql mysql:5.7 数据库,数据持久化
crmchat-redis redis:alpine 缓存/Session/WebSocket 状态

环境变量 (.env)

# 数据库
DB_HOSTNAME=mysql
DB_DATABASE=crmeb_chat
DB_USERNAME=root
DB_PASSWORD=root          # 生产环境务必修改
DB_PORT=3306

# Redis
REDIS_HOSTNAME=redis
REDIS_PORT=6379
REDIS_PASSWORD=

# Nginx 端口
NGINX_PORT=18091

# MySQL root 密码
MYSQL_ROOT_PASSWORD=root   # 生产环境务必修改

目录结构

kefu/
├── docker/
│   └── php/
│       ├── Dockerfile          # PHP 7.4 + Swoole4 镜像
│       ├── entrypoint.sh       # 启动脚本(自动生成 .env、导入数据库、启动 Swoole)
│       └── swoole.php          # Swoole 配置
├── nginx/
│   └── nginx.conf              # Nginx 配置
├── crmchat/                    # ThinkPHP 6 后端源码
│   └── public/
│       ├── admin/              # 管理后台前端(构建产物)
│       ├── demo/               # 用户端 Demo 页
│       └── install/
│           ├── crmeb_clean.sql # 数据库初始化 SQL(29 张表,含初始数据)
│           └── install.lock    # 自动生成,跳过安装向导
├── docker-compose.yml          # 海外版 Docker Compose
├── docker-compose.cn.yml       # 国内镜像加速版(覆盖镜像源)
├── .env.docker                 # 环境变量模板
└── .env                        # 实际环境变量(gitignore)

常用命令

# 启动
docker compose -f docker-compose.yml -f docker-compose.cn.yml up -d

# 停止
docker compose down

# 停止并清除数据(完全重置)
docker compose down -v

# 重启
docker compose restart

# 查看日志
docker compose logs -f php

# 进入容器
docker exec -it crmchat-php bash

数据库说明

初始化 SQL 文件 crmchat/public/install/crmeb_clean.sql 包含:

  • 29 张 eb_ 前缀表
  • 完整初始数据:管理员、客服、角色权限、系统菜单、系统配置、应用 Token
  • 启动时 entrypoint.sh 自动导入,首次启动即用,无需安装向导

APP_KEY 已固定,Token 82b739d20bd2d29dc67f112b7f193683 重启不变。

注意事项

  1. 客服需要打开 WebSocket — 仅仅登录 API 不够,需要浏览器访问 /kefu 进入聊天面板建立 WebSocket 连接才能接收用户消息
  2. 生产环境务必修改 .env 中的数据库密码和 MySQL root 密码
  3. APP_KEY 已固定 — 如需更换,修改 entrypoint.sh 中 APP_KEY 的值,并重新执行 docker compose down -v && docker compose up -d

模块打包部署

三个模块的分工与部署方式:

模块 功能 Docker 部署方式
admin/ Web 前端(管理后台 + 客服面板 + 用户端) 构建后复制到 crmchat/public/admin/,Nginx 静态 serve
crmchat/ PHP 后端(API + WebSocket) Volume 挂载到容器,Swoole 运行
uniapp/ 移动端客服 App 不在 Docker 范围内,需单独打包

admin/ — 管理后台前端

构建产物已内置在 crmchat/public/admin/ 中,直接可用,无需额外构建步骤。

只有在修改了 admin/src/ 下的源码后,才需要重新构建并提交:

cd admin
npm install                    # 首次或依赖变更后
npm run build                  # 构建 → dist/

# Windows
Remove-Item -Path "..\crmchat\public\admin\*" -Recurse -Force
Copy-Item -Path "dist\*" -Destination "..\crmchat\public\admin\" -Recurse

# Linux / Mac
rm -rf ../crmchat/public/admin/*
cp -r dist/* ../crmchat/public/admin/

# 确认提交
git add ../crmchat/public/admin/ && git commit -m "更新 admin 前端构建产物"

构建产物提交后,新环境 clone 即可直接用 Docker 部署,无需安装 Node.js。

crmchat/ — PHP 后端

代码通过 volume 挂载到容器(./crmchat:/var/www/html),修改 .php 文件后需重启 PHP 容器才能生效:

docker compose restart php

uniapp/ — 移动端客服 App

不在 Docker 部署范围内。使用 HBuilderX 打开 uniapp/ 目录,即可编译打包为:

  • Android APK
  • iOS IPA
  • 微信小程序 / 支付宝小程序 / 百度小程序 / 头条小程序
  • H5 网页

打包前需在 uniapp/pages/config/app.js 中配置后端 API 域名和 WebSocket 地址:

defaultDomainName: '你的后端域名',   // 如 chat.example.com
defaultRequestType: 'https',         // http 或 https
defaultWsType: 'wss',               // ws 或 wss