Files
wecom-ai-assistant/docs/deploy-cloud-minimal.md
2026-02-05 16:36:32 +08:00

416 lines
10 KiB
Markdown
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.
# 云端最小回调壳部署方案
## 一、目标
**阶段目标**:在备案域名上部署最小可用回调壳,使企业微信能完成 URL 校验与回调联调。
**最小功能范围**
-`/api/wecom/callback` GET 校验(兼容 `signature`/`msg_signature`
-`/api/wecom/callback` POST 密文消息回调验签、解密、echo 回复)
- ✅ 结构化日志 + trace_id
- ✅ Nginx 反代 + HTTPSLet's Encrypt
- ⏸️ 数据库(可先不启用,但接口与配置要预留)
- ⏸️ Admin 后台(可先占位)
---
## 二、架构
```
企业微信 → HTTPS (443) → Nginx → Backend (8000)
PostgreSQL (可选)
```
**服务清单**
- `backend`: Python 3.12 + FastAPI + Uvicorn最小回调壳
- `nginx`: 反代 + HTTPSLet's Encrypt
- `db`: PostgreSQL 16可选先不启用
---
## 三、环境变量配置
### 3.1 必需变量(`.env`
```bash
# ============ Backend ============
API_HOST=0.0.0.0
API_PORT=8000
# Database可选先不启用
DATABASE_URL=postgresql+asyncpg://wecom:wecom_secret@db:5432/wecom_ai
DATABASE_URL_SYNC=postgresql://wecom:wecom_secret@db:5432/wecom_ai
# JWTadmin 登录,可选)
JWT_SECRET=your-jwt-secret-change-in-production
JWT_ALGORITHM=HS256
JWT_EXPIRE_MINUTES=60
# WeCom Callback必须从企业微信管理后台获取
WECOM_CORP_ID=你的企业ID
WECOM_AGENT_ID=你的应用AgentId
WECOM_SECRET=你的应用Secret可选用于主动发送消息
WECOM_TOKEN=你的Token必须与企微后台一致
WECOM_ENCODING_AES_KEY=你的43位密钥必须与企微后台一致
# WeCom API
WECOM_API_BASE=https://qyapi.weixin.qq.com
WECOM_API_TIMEOUT=10
WECOM_API_RETRIES=2
# Log
LOG_LEVEL=INFO
LOG_JSON=true
# ============ Nginx ============
# 域名(必须,备案域名)
DOMAIN=your-domain.com
# SSLLet's Encrypt
SSL_EMAIL=your-email@example.com
```
### 3.2 关键变量说明
| 变量 | 说明 | 来源 |
|------|------|------|
| `WECOM_TOKEN` | 企业微信回调 Token | 企微后台 → 应用 → 接收消息 → Token |
| `WECOM_ENCODING_AES_KEY` | 43 位 Base64 编码密钥 | 企微后台 → 应用 → 接收消息 → EncodingAESKey |
| `WECOM_CORP_ID` | 企业 ID | 企微后台 → 我的企业 → 企业信息 |
| `WECOM_AGENT_ID` | 应用 AgentId | 企微后台 → 应用管理 → 自建应用 → 应用详情 |
| `DOMAIN` | 备案域名 | 你的域名服务商 |
---
## 四、部署步骤
### 4.1 前置条件
1. **备案域名**:已备案且主体关联的域名(例如:`api.yourdomain.com`
2. **服务器**LinuxUbuntu 20.04+ / CentOS 7+),公网 IP开放 80/443 端口
3. **Docker**:已安装 Docker 和 docker-compose
4. **GitHub**:代码已推送到 GitHub用于 CI/CD
### 4.2 服务器初始化
```bash
# 1. 安装 Docker 和 docker-compose
curl -fsSL https://get.docker.com | sh
sudo usermod -aG docker $USER
sudo curl -L "https://github.com/docker/compose/releases/latest/download/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
sudo chmod +x /usr/local/bin/docker-compose
# 2. 克隆项目(或通过 CI/CD 部署)
git clone https://github.com/your-org/wecom-ai-assistant.git
cd wecom-ai-assistant
# 3. 创建 .env 文件
cp .env.example .env
# 编辑 .env填入上述必需变量
```
### 4.3 配置 Nginx + HTTPS
#### 方案 A使用 CertbotLet's Encrypt
```bash
# 1. 安装 Certbot
sudo apt-get update
sudo apt-get install certbot python3-certbot-nginx
# 2. 先启动 HTTP 服务(用于验证)
docker-compose up -d backend
# 3. 配置 Nginx临时 HTTP 配置)
# 编辑 deploy/nginx.conf添加 server_name
# 然后运行docker-compose up -d nginx
# 4. 获取 SSL 证书
sudo certbot --nginx -d your-domain.com -d www.your-domain.com --email your-email@example.com --agree-tos --non-interactive
# 5. 更新 nginx.conf使用 Certbot 生成的配置
# Certbot 会自动修改 /etc/nginx/sites-available/default
# 将配置复制到 deploy/nginx.conf或使用 volume 挂载
```
#### 方案 B手动配置 Nginx + Let's Encrypt
创建 `deploy/nginx-ssl.conf`
```nginx
events { worker_connections 1024; }
http {
upstream backend {
server backend:8000;
}
# HTTP → HTTPS 重定向
server {
listen 80;
server_name your-domain.com www.your-domain.com;
return 301 https://$server_name$request_uri;
}
# HTTPS
server {
listen 443 ssl http2;
server_name your-domain.com www.your-domain.com;
# SSL 证书Let's Encrypt
ssl_certificate /etc/letsencrypt/live/your-domain.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/your-domain.com/privkey.pem;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!MD5;
# /api -> backend
location /api/ {
proxy_pass http://backend;
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 30s;
}
# 健康检查
location /health {
proxy_pass http://backend/health;
access_log off;
}
}
}
```
更新 `docker-compose.yml`
```yaml
nginx:
image: nginx:alpine
ports:
- "80:80"
- "443:443"
volumes:
- ./deploy/nginx-ssl.conf:/etc/nginx/nginx.conf:ro
- /etc/letsencrypt:/etc/letsencrypt:ro # SSL 证书
depends_on:
- backend
```
### 4.4 启动服务
```bash
# 1. 构建镜像
docker-compose build backend
# 2. 启动服务(最小回调壳:只启动 backend + nginx
docker-compose up -d backend nginx
# 3. 检查日志
docker-compose logs -f backend
```
### 4.5 验证服务
```bash
# 1. 检查服务状态
docker-compose ps
# 2. 检查健康检查
curl https://your-domain.com/health
# 3. 检查回调接口(应返回 400因为缺少参数
curl https://your-domain.com/api/wecom/callback
```
---
## 五、本地验证
### 5.1 本地启动最小回调壳
```bash
# 1. 启动后端(不启动 db/admin
docker-compose up -d backend
# 2. 检查日志
docker-compose logs backend
# 3. 测试 GET 校验(模拟企业微信)
# 注意:需要正确的 signature/timestamp/nonce/echostr
curl "http://localhost:8000/api/wecom/callback?signature=xxx&timestamp=123&nonce=abc&echostr=xxx"
```
### 5.2 本地测试 POST 回调
```bash
# 使用企业微信官方测试工具生成测试请求
# 或使用 curl 模拟(需要正确的签名和加密)
curl -X POST "http://localhost:8000/api/wecom/callback?msg_signature=xxx&timestamp=123&nonce=abc" \
-H "Content-Type: application/xml" \
-d '<xml><Encrypt><![CDATA[加密内容]]></Encrypt></xml>'
```
### 5.3 验证日志格式
检查日志输出是否符合结构化日志格式:
```json
{
"timestamp": "2025-02-05T10:00:00Z",
"level": "INFO",
"message": "wecom verify success",
"trace_id": "abc123",
"echostr_length": 43
}
```
---
## 六、线上验证
### 6.1 企业微信后台配置
1. **登录企业微信管理后台**https://work.weixin.qq.com
2. **进入应用设置**:应用管理 → 自建应用 → 选择你的应用
3. **配置回调 URL**
- 接收消息服务器 URL`https://your-domain.com/api/wecom/callback`
- Token`.env` 中的 `WECOM_TOKEN` **完全一致**
- EncodingAESKey`.env` 中的 `WECOM_ENCODING_AES_KEY` **完全一致**
- 消息加解密方式:**安全模式**
4. **点击保存**
### 6.2 验证 GET 校验
保存后,企业微信会立即发送 GET 请求验证。观察后端日志:
```bash
docker-compose logs -f backend
```
**成功日志**
```
INFO: wecom verify success {"trace_id": "...", "echostr_length": 43}
```
**失败日志**
```
WARNING: wecom verify failed {"trace_id": "...", "timestamp": "...", "nonce": "..."}
```
如果验证失败,检查:
- Token 是否一致
- EncodingAESKey 是否一致
- 域名是否可访问(`curl https://your-domain.com/api/wecom/callback`
### 6.3 验证 POST 回调
1. **在企业微信中发送测试消息**
- 打开企业微信客户端
- 找到你配置的应用
- 发送文本消息:`你好,测试一下`
2. **观察后端日志**
```bash
docker-compose logs -f backend
```
**成功日志**
```json
{
"timestamp": "2025-02-05T10:00:00Z",
"level": "INFO",
"message": "wecom message received",
"trace_id": "abc123",
"external_userid": "external_userid_xxx",
"msgid": "123456",
"msg_type": "text",
"content_summary": "你好,测试一下"
}
```
```json
{
"timestamp": "2025-02-05T10:00:01Z",
"level": "INFO",
"message": "wecom reply sent",
"trace_id": "abc123",
"external_userid": "external_userid_xxx",
"msgid": "123456",
"reply_summary": "已收到:你好,测试一下"
}
```
3. **检查企业微信客户端**:应收到回复:`已收到:你好,测试一下`
---
## 七、常见问题
### 7.1 GET 校验失败
**原因**
- Token 不一致
- EncodingAESKey 不一致
- 签名算法错误
**解决**
1. 检查 `.env` 中的 `WECOM_TOKEN``WECOM_ENCODING_AES_KEY`
2. 确保与企微后台配置**完全一致**(包括大小写、空格)
3. 重启后端:`docker-compose restart backend`
### 7.2 POST 回调失败
**原因**
- 签名验证失败
- 解密失败
- XML 解析失败
**解决**
1. 检查日志中的错误信息
2. 确认 EncodingAESKey 正确
3. 确认消息加解密方式为**安全模式**
### 7.3 HTTPS 证书问题
**原因**
- Let's Encrypt 证书未正确配置
- 证书过期
**解决**
1. 检查证书:`sudo certbot certificates`
2. 续期证书:`sudo certbot renew`
3. 重启 Nginx`docker-compose restart nginx`
### 7.4 域名无法访问
**原因**
- DNS 未解析
- 防火墙未开放 80/443 端口
- Nginx 配置错误
**解决**
1. 检查 DNS`nslookup your-domain.com`
2. 检查端口:`netstat -tlnp | grep -E '80|443'`
3. 检查 Nginx 日志:`docker-compose logs nginx`
---
## 八、下一步
完成最小回调壳部署后,按以下顺序逐步接入:
1.**最小回调壳**(当前阶段)
2. ⏭️ **数据库接入**(会话与消息入库)
3. ⏭️ **Admin 后台**(会话列表、工单、知识库)
4. ⏭️ **FAQ/RAG**(智能回复)
---
## 九、参考文档
- [企业微信回调配置](./wecom.md)
- [企业微信测试指南](./wecom-test-guide.md)
- [GitHub Actions CI/CD](../deploy/ci/github-actions.yml)