Files
ai-kefu-admin/deploy/openresty-all-kefu.conf.template
T
浅念 96131ebdec docs: 部署手册(继承jc血泪+切换runbook+备份演练)+ openresty模板
- docs/deploy-production.md: 环境前置(.env 逐项/Compose>=2.24 依据/容器自含
  pip 免装) → 首次部署(build/bootstrap/up/health 分级解读/domains=3 口径) →
  1Panel 反代(Host 透传/WS 单套升级头/client_max_body_size 5m/api public
  放行/include 行检查) → 存量迁移(停容器或 backup API 导出, 禁运行时裸 cp;
  经 data/ 卷喂 import_legacy) → 切换 runbook(隧道+hosts 全功能验证 → 逐域名
  切反代 → 观察一周日检 → 老项目归档; 30 秒回滚预案) → 日常运维(backup API
  备份+季度恢复演练/日志封顶+PII 现状如实记/archive 维护窗口/tag 发版纪律/
  加租户零容器操作/bootstrap 幂等) → 踩坑实录 13 条(jc 五条承继+本项目八条,
  含 Host 头漏传全站 404 与头像 413 两条新增预判)
- deploy/openresty-all-kefu.conf.template: upstream + 租户 server 块(WS 单套
  升级头/XFF/上传体积) + admin 形态 A/B(注释切换) + 1Panel 适配注记(include
  行位置/片段直写 IP/验证重载命令)
- CLAUDE.md: 文档索引落位(手册+模板已存在, 补 Phase 4 计划链接)

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-10-14 09:44:28 +08:00

154 lines
8.9 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# =============================================================================
# all-kefu 生产反代模板(openresty / nginx 通用,完整可抄)
# =============================================================================
# 拓扑(spec §9):所有域名(租户域名 × N + 管理后台)反代到同一个容器
# chat.agent.hnxinyouhe.com (租户 auto) ─┐
# chat2.agent.hnxinyouhe.com (租户 jiancai) ─┼→ 127.0.0.1:8018 → all-kefu 容器
# <admin 域名>(形态 A,部署前由需求方确定)─┘
#
# 两种用法:
# · 独立 openresty/nginx:整份可抄——upstream + server 块齐备,按需删掉
# 不用的块(admin 只用形态 A 或 B 其一)。
# · 1Panel:server 块由面板生成,**只抄 location 片段**到
# /opt/1panel/www/sites/<域名>/proxy/*.conf——文末「1Panel 适配注记」
# 有逐条对照与现成片段。
#
# 血泪纪律(每条都出过线上事故,改配置前重读一遍):
# 1. Host 头必须透传(proxy_set_header Host $host)——本项目按 Host 头
# 解析租户,漏了这一行全站 404(不是报错,是静默 404)。
# 2. WS 升级头(Upgrade/Connection)全站只能出现一套——1Panel 面板生成
# 的反代若已带一套,再抄一份会重复定义,uvicorn 严格解析直接拒绝
# 握手(HTTP 正常、WS 426)。
# 3. client_max_body_size 至少 5m——头像上传上限 2MB,nginx 默认 1m
# 会直接 413(应用层校验根本收不到请求)。
# =============================================================================
# ---- upstream(独立部署时用;1Panel 场景见文末注记,直接写 IP:端口) --------
upstream all_kefu {
server 127.0.0.1:8018; # 单容器单 upstream;换端口只改这里
}
# ---- 租户域名 server 块(每个租户域名复制一份,改 server_name 即可) --------
# 含:全站反代 + WS 单套升级头 + /api/public(widget 头像/品牌,放行即全站
# 反代的一部分,单独点名是防"按路径收紧"时漏掉它——漏配的症状是 widget
# 头像 404)。
server {
listen 80; # 1Panel/证书层负责 443 与 HTTPS;独立部署自行补 listen 443 ssl
server_name chat2.agent.hnxinyouhe.com; # ← 每个租户域名一份:chat.(auto)/ chat2.(jiancai)
# WebSocket(/ws/chat):升级头单套 + 长读超时(长连接心跳间隔内不断开)
location /ws/ {
proxy_pass http://all_kefu;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host; # 纪律 1:WS 也按 Host 解析租户
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; # 引擎 IP/区域解析取 XFF 第一段
proxy_set_header X-Forwarded-Proto $scheme;
proxy_read_timeout 3600s;
proxy_send_timeout 3600s;
}
# 其余全部(/, /static, /api/chat*, /api/public, /health …)——
# /static/widget.js 的 no-cache 由应用层中间件下发(响应头已带
# Cache-Control: no-cache),反代无需另加,也别加会覆盖它的 expires。
location / {
proxy_pass http://all_kefu;
proxy_http_version 1.1;
proxy_set_header Host $host; # 纪律 1
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;
client_max_body_size 5m; # 纪律 3(头像上传)
}
# ---- admin 形态 B(同域名路径分流;不用独立管理域名时启用) --------------
# 应用层对 /admin 与 /api/platform/ 前缀豁免租户 Host 解析,挂在租户
# 域名下照常工作(与租户聊天面共存,同源零 CORS)。启用 = 取消注释;
# nginx 最长前缀匹配,这两块优先于上面的 location /。
# 已知边界:形态 B 下后台"品牌-头像预览"走本域 /api/public/avatar,
# 解析到的是**本域名对应的租户**——切换到其他租户的配置页时头像预览
# 不准(已知项,CLAUDE.md Phase 4 清理单 #3/#4)。
#
# location /admin {
# proxy_pass http://all_kefu;
# proxy_http_version 1.1;
# 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;
# client_max_body_size 5m; # 头像上传走 /api/platform/.../brand/avatar
# }
# location /api/platform/ {
# proxy_pass http://all_kefu;
# proxy_http_version 1.1;
# 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;
# client_max_body_size 5m;
# }
}
# ---- admin 形态 A:独立管理域名 server 块(与形态 B 二选一) ------------------
# 整域反代到同一容器:/admin(SPA 静态,含 assets)与 /api/platform(后台
# API,认证由路由依赖守护)同一 upstream。全站反代即可,无需按路径拆分。
# 入口是 https://<admin 域名>/admin/——管理域根路径 / 走租户 Host 解析,
# 404 属预期(要友好可在本块加 location = / { return 302 /admin/; })。
# 已知边界:独立管理域名下 /api/public/*(按租户 Host 解析)必 404——后台
# "品牌-头像预览"在该形态加载不出(预览以本地简化预览为准),已知项
# (CLAUDE.md Phase 4 清理单 #3),非配置错误,勿按 404 排障反代。
server {
listen 80;
server_name admin.example.com; # ← 占位:管理域名部署前由需求方确定
location / {
proxy_pass http://all_kefu;
proxy_http_version 1.1;
proxy_set_header Host $host; # 形态 A 的 Host 是管理域(未知租户)——
# /admin 与 /api/platform 豁免租户解析,照常工作
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;
client_max_body_size 5m; # 头像上传
}
}
# =============================================================================
# 1Panel 适配注记(jc 项目两次线上事故的源头,逐条核对)
# =============================================================================
# 1. server 块由面板建站生成,不要手写整个 server——只把上面的 location
# 片段放进站点目录:
# /opt/1panel/www/sites/<域名>/proxy/root.conf ← location /(全站反代)
# /opt/1panel/www/sites/<域名>/proxy/ws.conf ← location /ws/(升级头单套)
# /opt/1panel/www/sites/<域名>/proxy/admin.conf ← 形态 B 的两块(启用时)
# 片段内 proxy_pass 直接写 http://127.0.0.1:8018——upstream 块只能声明在
# http 上下文,server 级 include 文件里放不进去(面板世界没有"全局
# upstream 文件"的挂载点,直写地址即单一事实源,换端口全文替换)。
#
# 2. 主 conf 的 include 行检查(1Panel 坑:面板建站默认可能不带):
# /opt/1panel/www/conf.d/<域名>.conf
# 里必须有(没有就手工补,改前备份同目录 *.conf.bak.<日期>):
# include /www/sites/<域名>/proxy/*.conf;
# 注意路径前缀是 /www/sites/...(1Panel 容器内视角),不是 /opt/1panel/...。
# 面板配了反代却不生效,九成是这行缺失。
#
# 3. 1Panel 面板生成的反代若自带 Upgrade/Connection 头,删掉面板那套再放
# ws.conf(升级头只能一套,见顶部纪律 2)。
#
# 4. 改完必验再重载(先 -t 再 reload;reload 平滑,不影响其他站点):
# docker exec $(docker ps --filter name=openresty -q | head -1) nginx -t
# docker exec $(docker ps --filter name=openresty -q | head -1) nginx -s reload
# 验证(逐域名):
# curl -s https://<租户域名>/health | head -c 200 # {"status":"ok",...}
# curl -sI https://<租户域名>/static/widget.js | grep -i cache # Cache-Control: no-cache
# curl -s -i --http1.1 -H "Connection: Upgrade" -H "Upgrade: websocket" \
# -H "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==" -H "Sec-WebSocket-Version: 13" \
# https://<租户域名>/ws/chat | head -1 # HTTP/2 101 或 HTTP/1.1 101
# =============================================================================