Files
ai-kefu-jc/docs/deploy-production.md
T
浅念 ae812d9932 docs: 清理已完成待办
Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-30 14:29:35 +08:00

9.0 KiB
Raw Blame History

线上部署文档(生产环境实录)

更新:2026-09-30 · 对应线上版本 5d83dd9 本文记录实际部署状态(不是理想方案),排查问题和重新部署都以此为准。

1. 线上环境总览

项 值
目标服务器 阿里云 ECS(境外)47.254.176.10,Debian 13,Docker 29.4.0,1Panel 面板
跳板机 国内阿里云 8.152.213.143(境外机直连不通,必须经跳板)
线上域名 https://chat2.agent.hnxinyouhe.com(1Panel 建站,HTTPS 证书已绑定)
应用容器 hs-ai-kefu(端口 8017:8000,内存限额 512M)
代码位置 /opt/1panel/www/sites/chat2.agent.hnxinyouhe.com/index(git clone 自公司 git)
git 仓库 http://219.157.255.213:25311/xinyouhe/ai-kefu-jc.git

同服务器共存的其它项目(部署/排障时绝对不要碰): 汽车客服 cc-ai-kefu(chat.agent.hnxinyouhe.com,端口 8016)、tracker 系列、 photo-live 系列、php7433 等。本项目与它们仅共享 Docker 守护进程,容器/端口/目录/数据完全隔离。

2. SSH 连接方式(专属密钥 + 跳板链路)

本机 ~/.ssh/config 已配好两个别名(密钥为本项目专属 ~/.ssh/ai_kefu_jc_deploy, 吊销 = 删服务器 ~/.ssh/authorized_keys 中带 ai-kefu-jc-deploy 注释的行):

Host ai-kefu-jc-bastion          # 跳板(国内)
    HostName 8.152.213.143 / User root / Port 22

Host ai-kefu-jc-prod             # 目标(境外,经跳板)
    HostName 47.254.176.10 / User root / Port 22
    ProxyJump ai-kefu-jc-bastion
ssh ai-kefu-jc-prod 'echo ok'    # 一键直达到目标服务器

3. 服务器上的实际布局

/opt/1panel/www/sites/chat2.agent.hnxinyouhe.com/
├── index/                    ← 项目根(git 仓库,即部署目录)
│   ├── app/ static/ tests/ ...
│   ├── docker-compose.yml    ← 注意:服务器上有本地改动(mem_limit 512m,未提交)
│   ├── deploy.sh             ← 同上(本地改动)
│   ├── data/hesupipe_ai_kefu.db   ← 生产 SQLite(容器卷挂载,gitignore)
│   └── .env                  ← 生产配置(gitignore,权限600)
├── log/                      ← 站点访问日志
├── ssl/                      ← HTTPS 证书(1Panel 管理)
└── proxy/                    ← 反代配置(1Panel 站点的 include 加载)
    ├── root.conf             ← HTTP 全站反代 → 127.0.0.1:8017
    └── ws.conf               ← WebSocket 专用路由(与汽车客服同款)

1Panel 主配置:/opt/1panel/www/conf.d/chat2.agent.hnxinyouhe.com.conf (其中第 19 行 include /www/sites/chat2.agent.hnxinyouhe.com/proxy/*.conf; 是部署时手工补的 —— 1Panel 建站默认不带 include,面板配的反代不会生效, 备份在同目录 *.conf.bak.20260930)。

反代实际生效配置(排查时对照)

proxy/root.conf(HTTP):

location ^~ / {
    proxy_pass http://127.0.0.1:8017;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_read_timeout 300s;
}

proxy/ws.conf(WebSocket 专用,/ws/ 前缀优先命中):

location /ws/ {
    proxy_pass http://127.0.0.1:8017;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_read_timeout 3600s;
    proxy_send_timeout 3600s;
}

⚠️ 反代改动后要重载:docker exec $(docker ps --filter name=openresty -q | head -1) nginx -t && nginx -s reload (先 -t 语法检查再 reload;reload 是平滑的,不影响其他站点)

4. 生产 .env(结构,值脱敏)

AI_PROVIDER=glm
ZHIPU_API_KEY=<与汽车项目同一个>
AI_MODEL=glm-4-flash
ZHIPU_BASE_URL=<同汽车项目>

DATABASE_URL=sqlite+aiosqlite:///./data/hesupipe_ai_kefu.db

SMTP_HOST/PORT/USER/PASS=<真实发件账号,同汽车项目>
NOTIFY_EMAIL=hesu@hesuu.com            # 询盘通知收件箱

PUSH_ENABLED=false                      # 暂不推送 UniService(需求方决定)
PUSH_API_URL=https://uniservice.server.hnxinyouhe.com/open/v1/inquiry/push
PUSH_API_KEY=<已备好,开启时用>
PUSH_EXTERNAL_KEY_PREFIX=ai-kefu-jc     # 与汽车项目线索键隔离,勿改!

APP_HOST=0.0.0.0
APP_PORT=8017
APP_DEBUG=false

凭据来源:部署时从汽车项目服务器上的 .env(chat.agent.hnxinyouhe.com/index/.env) 提取同类键,只读未动。

5. 部署 / 更新流程(日常发版照此执行)

# 0. 本地:测试全绿才发版
python -m pytest -q          # 231 项

# 1. 本地:推送
git push origin master

# 2. 服务器:更新并重建(一条命令)
ssh ai-kefu-jc-prod '
cd /opt/1panel/www/sites/chat2.agent.hnxinyouhe.com/index
git pull
docker compose build && docker compose up -d
sleep 3 && curl -s http://127.0.0.1:8017/health
'

说明:

  • 静态文件(widget.js 等)打进镜像,改前端必须 build(仅 up -d 不够)
  • .env 和 data/ 不在 git 里,更新不受影响
  • 回滚:git checkout <上一版本> && docker compose build && docker compose up -d

6. 验证清单(发版后必跑)

# ① 健康
curl -s https://chat2.agent.hnxinyouhe.com/health            # {"status":"ok"}
# ② 页面
curl -s https://chat2.agent.hnxinyouhe.com/ | grep -o "<title>.*</title>"
# ③ WebSocket(期待 HTTP/1.1 101)
curl -s -i --http1.1 -H "Connection: Upgrade" -H "Upgrade: websocket" \
  -H "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==" -H "Sec-WebSocket-Version: 13" \
  https://chat2.agent.hnxinyouhe.com/ws/chat | head -1
# ④ 静态与缓存头
curl -sI https://chat2.agent.hnxinyouhe.com/static/widget.js | grep -i "cache\|HTTP"

功能级验证(改前端/挂件后):打开 https://chat2.agent.hnxinyouhe.com/static/widget-test.html, 用 Playwright 或肉眼核对:邀请卡 5 秒弹出位置、面板四个方位(data-position)、 头像加载、主题色断言面板 9/9 绿。

7. 本次上线踩坑实录(排查手册)

现象 根因 解法(已内置,重蹈覆辙时对照)
两个客服互斥:起一个、另一个 502 1Panel 站点目录都叫 index,compose 默认以目录名为项目名 → 与汽车项目同属 project "index",任一目录 down/up 会互删对方容器 compose 固定专属项目名 name: hs-ai-kefu(3db3e5b),已重演事故操作验证互不影响
WS 握手 426(HTTP 正常) 1Panel 面板生成的反代里 Upgrade/Connection 头重复定义两套,uvicorn 严格解析直接拒绝 拆分 ws.conf 单套路(§3),nginx -T dump 最终配置 + 假后端 dump 收到的头可快速定位
改了 widget.js 线上"没生效" 响应无 Cache-Control,浏览器启发式缓存旧脚本 已加中间件 /static/* → Cache-Control: no-cache(ec2d17b);用户端 Ctrl+F5 一次即愈
bottom-left 弹出元素溢出屏幕(面板 x=-183) 弹出层(chat-panel / invite-container)CSS 硬编码 right:0 只适配右下角 已随 pos-<position> 类联动(5d83dd9),静态测试锁死;新增弹出元素时必须同时加联动规则
1Panel 配了反代不生效 面板建站的主 conf 默认不含 include proxy/*.conf 手工补 include 行(§3),备份后 reload
deploy 时 git pull 报本地改动冲突 服务器 compose/deploy.sh 曾有本地改动(mem_limit) 已正式入 git(3db3e5b),服务器工作区保持干净,pull 不再需要 stash

8. 常见运维操作

# 看应用日志(最近100行)
ssh ai-kefu-jc-prod 'docker logs hs-ai-kefu --tail 100'

# 重启应用(不动其他容器)
ssh ai-kefu-jc-prod 'cd /opt/1panel/www/sites/chat2.agent.hnxinyouhe.com/index && docker compose up -d --force-recreate'

# 容器状态/内存
ssh ai-kefu-jc-prod 'docker stats hs-ai-kefu --no-stream'

# 破防率观测(上线第一周必做,见 CLAUDE.md 观察期)
ssh ai-kefu-jc-prod 'docker exec hs-ai-kefu python scripts/breach_rate.py'

# 管理后台
https://chat2.agent.hnxinyouhe.com/admin   # 密码在生产 .env 同汽车项目口径

9. 待办与提醒

  • 官网嵌入:hesupipe.com 按 docs/embed-guide.md(script src 用 https://chat2.agent.hnxinyouhe.com/static/widget.js,位置/配色/邮箱可配)
  • 邮件通道冒烟:跑一轮测试留资,确认 hesu@hesuu.com 能收到询盘邮件 (单邮件通道,SMTP 失败不自动补发,上线头几天盯收件)
  • 开启 UniService 推送(届时只改 .env 的 PUSH_ENABLED=true 并重启容器)
  • 上线第一周:跑 breach_rate 观测漏放/误杀(已知 4 项残差见 docs/test-checklist.md)