# 生产环境部署指南 ## 一、概述 本文档描述如何在云端服务器上部署企业微信 AI 助手的最小回调壳,支持企业微信回调 URL 校验和消息回调。 **部署架构**: ``` 企业微信 → HTTPS (443) → Nginx → Backend (8000) ↓ PostgreSQL (可选) ``` **服务清单**: - `backend`: Python 3.12 + FastAPI + Uvicorn(最小回调壳) - `nginx`: 反向代理 + HTTPS(Let's Encrypt) - `db`: PostgreSQL 16(可选,最小回调壳可以先不启用) - `admin`: Next.js 管理后台(可选,最小回调壳可以先不启用) --- ## 二、云服务器准备 ### 2.1 服务器要求 - **操作系统**:Ubuntu 20.04+ / CentOS 7+ / Debian 11+ - **CPU**:1 核以上 - **内存**:1GB 以上(推荐 2GB) - **磁盘**:20GB 以上 - **网络**:公网 IP,开放 80/443 端口 ### 2.2 安装 Docker 和 Docker Compose #### Ubuntu/Debian ```bash # 更新系统 sudo apt-get update sudo apt-get install -y ca-certificates curl gnupg lsb-release # 添加 Docker 官方 GPG 密钥 sudo mkdir -p /etc/apt/keyrings curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg # 添加 Docker 仓库 echo \ "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \ $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null # 安装 Docker sudo apt-get update sudo apt-get install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin # 将当前用户添加到 docker 组(可选,避免每次使用 sudo) sudo usermod -aG docker $USER newgrp docker # 验证安装 docker --version docker compose version ``` #### CentOS/RHEL ```bash # 安装依赖 sudo yum install -y yum-utils # 添加 Docker 仓库 sudo yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo # 安装 Docker sudo yum install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin # 启动 Docker sudo systemctl start docker sudo systemctl enable docker # 将当前用户添加到 docker 组 sudo usermod -aG docker $USER newgrp docker # 验证安装 docker --version docker compose version ``` ### 2.3 配置防火墙 #### Ubuntu (UFW) ```bash # 允许 SSH(避免锁定) sudo ufw allow 22/tcp # 允许 HTTP/HTTPS sudo ufw allow 80/tcp sudo ufw allow 443/tcp # 启用防火墙 sudo ufw enable # 检查状态 sudo ufw status ``` #### CentOS/RHEL (firewalld) ```bash # 允许 HTTP/HTTPS sudo firewall-cmd --permanent --add-service=http sudo firewall-cmd --permanent --add-service=https sudo firewall-cmd --reload # 检查状态 sudo firewall-cmd --list-all ``` --- ## 三、域名 DNS 配置 ### 3.1 添加 A 记录 在域名服务商(如阿里云、腾讯云、Cloudflare)添加 A 记录: ``` 类型: A 主机记录: @ 或 api(例如:api.yourdomain.com) 记录值: 你的服务器公网 IP TTL: 600(或默认) ``` ### 3.2 验证 DNS 解析 ```bash # 检查 DNS 解析 nslookup your-domain.com # 或 dig your-domain.com # 应该返回你的服务器 IP ``` --- ## 四、项目部署 ### 4.1 克隆项目 ```bash # 创建项目目录 sudo mkdir -p /opt/wecom-ai-assistant sudo chown $USER:$USER /opt/wecom-ai-assistant cd /opt/wecom-ai-assistant # 克隆项目(或通过 CI/CD 部署) git clone https://github.com/your-org/wecom-ai-assistant.git . ``` ### 4.2 配置环境变量 ```bash # 复制环境变量模板 cp .env.example .env.prod # 编辑 .env.prod,填写必需变量 nano .env.prod ``` **必需变量**: ```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 # JWT(admin 登录,可选) 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 ``` **重要**: - `WECOM_TOKEN` 和 `WECOM_ENCODING_AES_KEY` 必须与企微后台配置**完全一致** - `.env.prod` 文件包含敏感信息,**不要提交到 Git 仓库** ### 4.3 首次部署 #### 方式 A:使用部署脚本(推荐) ```bash # 赋予执行权限 chmod +x deploy/scripts/*.sh # 启动服务 ./deploy/scripts/start.sh ``` #### 方式 B:手动部署 ```bash # 设置镜像标签(默认 latest) export IMAGE_TAG=latest export GITHUB_REPOSITORY_OWNER=your-org # 启动服务 docker-compose -f docker-compose.prod.yml --env-file .env.prod up -d # 查看日志 docker-compose -f docker-compose.prod.yml logs -f backend ``` --- ## 五、HTTPS 配置(Let's Encrypt) ### 5.1 安装 Certbot #### Ubuntu/Debian ```bash sudo apt-get update sudo apt-get install -y certbot python3-certbot-nginx ``` #### CentOS/RHEL ```bash sudo yum install -y certbot python3-certbot-nginx ``` ### 5.2 配置 Nginx 占位路径 在获取证书之前,需要先配置 Nginx 的 HTTP 服务,以便 Certbot 验证域名所有权。 **临时修改 `deploy/docker/nginx.conf`**: ```nginx # HTTP 服务器(临时配置,用于证书申请) server { listen 80; server_name your-domain.com; # Let's Encrypt 验证路径 location /.well-known/acme-challenge/ { root /var/www/certbot; } # /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; } # 健康检查 location /health { proxy_pass http://backend/api/health; access_log off; } } ``` **创建验证目录**: ```bash sudo mkdir -p /var/www/certbot sudo chown -R $USER:$USER /var/www/certbot ``` **更新 `docker-compose.prod.yml`**,添加验证目录挂载: ```yaml nginx: volumes: - ./deploy/docker/nginx.conf:/etc/nginx/nginx.conf:ro - /var/www/certbot:/var/www/certbot:ro # 添加此行 ``` **重启 Nginx**: ```bash docker-compose -f docker-compose.prod.yml restart nginx ``` ### 5.3 申请 SSL 证书 ```bash # 设置域名和邮箱 export DOMAIN=your-domain.com export EMAIL=your-email@example.com # 申请证书(使用 Nginx 插件) sudo certbot certonly --nginx \ -d $DOMAIN \ -d www.$DOMAIN \ --email $EMAIL \ --agree-tos \ --non-interactive \ --preferred-challenges http # 或使用 standalone 模式(如果 Nginx 未运行) sudo certbot certonly --standalone \ -d $DOMAIN \ -d www.$DOMAIN \ --email $EMAIL \ --agree-tos \ --non-interactive ``` ### 5.4 更新 Nginx 配置 证书申请成功后,更新 `deploy/docker/nginx.conf`: ```nginx # HTTPS 服务器 server { listen 443 ssl http2; server_name your-domain.com; # SSL 证书(使用实际域名替换 _) ssl_certificate /etc/letsencrypt/live/your-domain.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/your-domain.com/privkey.pem; # ... 其他配置 } ``` **更新 `docker-compose.prod.yml`**,确保证书目录已挂载: ```yaml nginx: volumes: - ./deploy/docker/nginx.conf:/etc/nginx/nginx.conf:ro - /etc/letsencrypt:/etc/letsencrypt:ro # SSL 证书 - /var/www/certbot:/var/www/certbot:ro # 验证文件 ``` **重启 Nginx**: ```bash docker-compose -f docker-compose.prod.yml restart nginx ``` ### 5.5 配置证书自动续期 Let's Encrypt 证书有效期为 90 天,需要定期续期。 ```bash # 测试续期 sudo certbot renew --dry-run # 添加定时任务(每天检查一次) sudo crontab -e # 添加以下行: 0 0 * * * certbot renew --quiet --deploy-hook "docker-compose -f /opt/wecom-ai-assistant/docker-compose.prod.yml restart nginx" ``` --- ## 六、部署命令 ### 6.1 首次部署 ```bash # 使用部署脚本 ./deploy/scripts/start.sh # 或手动部署 docker-compose -f docker-compose.prod.yml --env-file .env.prod up -d ``` ### 6.2 更新部署 #### 方式 A:使用部署脚本 ```bash # 更新到最新版本 ./deploy/scripts/update.sh latest # 更新到指定版本 ./deploy/scripts/update.sh v1.0.0 ``` #### 方式 B:手动更新 ```bash # 设置镜像标签 export IMAGE_TAG=latest # 或指定版本,如 v1.0.0 # 登录到容器镜像仓库 docker login ghcr.io -u your-username -p your-token # 拉取最新镜像 docker-compose -f docker-compose.prod.yml --env-file .env.prod pull # 重启服务 docker-compose -f docker-compose.prod.yml --env-file .env.prod up -d ``` ### 6.3 回滚部署 ```bash # 回滚到指定版本(需要知道之前的镜像标签) export IMAGE_TAG=v0.9.0 # 替换为要回滚的版本 # 拉取指定版本镜像 docker-compose -f docker-compose.prod.yml --env-file .env.prod pull # 重启服务 docker-compose -f docker-compose.prod.yml --env-file .env.prod up -d ``` **查看历史版本**: ```bash # 查看 GitHub Container Registry 中的镜像标签 # 访问: https://github.com/your-org/wecom-ai-assistant/pkgs/container/wecom-ai-backend ``` ### 6.4 停止服务 ```bash # 使用部署脚本 ./deploy/scripts/stop.sh # 或手动停止 docker-compose -f docker-compose.prod.yml --env-file .env.prod down ``` --- ## 七、验证部署 ### 7.1 检查服务状态 ```bash # 查看服务状态 docker-compose -f docker-compose.prod.yml ps # 查看日志 docker-compose -f docker-compose.prod.yml logs -f backend ``` ### 7.2 健康检查 ```bash # HTTP 健康检查(如果 HTTPS 未配置) curl http://your-domain.com/api/health # HTTPS 健康检查(推荐) curl https://your-domain.com/api/health # 应该返回: # {"status":"ok"} ``` ### 7.3 企业微信回调验证 1. **配置企业微信回调 URL**: - 登录企业微信管理后台:https://work.weixin.qq.com - 进入:应用管理 → 自建应用 → 选择你的应用 - 配置回调: - **接收消息服务器 URL**:`https://your-domain.com/api/wecom/callback` - **Token**:与 `.env.prod` 中的 `WECOM_TOKEN` **完全一致** - **EncodingAESKey**:与 `.env.prod` 中的 `WECOM_ENCODING_AES_KEY` **完全一致** - **消息加解密方式**:**安全模式** - 点击 **保存** 2. **验证 GET 校验**: - 保存后,企业微信会立即发送 GET 请求验证 - 观察后端日志: ```bash docker-compose -f docker-compose.prod.yml logs -f backend ``` - 应该看到: ``` INFO: wecom verify success {"trace_id": "...", "echostr_length": 43} ``` 3. **验证 POST 回调**: - 在企业微信中发送测试消息 - 观察后端日志,应该看到: ``` INFO: wecom message received {"trace_id": "...", "external_userid": "...", "msgid": "...", "content_summary": "..."} INFO: wecom reply sent {"trace_id": "...", "reply_summary": "..."} ``` --- ## 八、GitHub Actions 自动部署 ### 8.1 配置 GitHub Secrets 在 GitHub 仓库设置中添加以下 Secrets: | Secret 名称 | 说明 | 示例 | |------------|------|------| | `PROD_HOST` | 生产服务器 IP 或域名 | `123.45.67.89` | | `PROD_USER` | SSH 用户名 | `ubuntu` | | `PROD_SSH_KEY` | SSH 私钥 | `-----BEGIN OPENSSH PRIVATE KEY-----...` | | `PROD_SSH_PORT` | SSH 端口(可选,默认 22) | `22` | | `PROD_DOMAIN` | 生产域名 | `api.yourdomain.com` | | `PROD_APP_PATH` | 应用部署路径(可选) | `/opt/wecom-ai-assistant` | ### 8.2 生成 SSH 密钥对 ```bash # 在本地生成 SSH 密钥对 ssh-keygen -t ed25519 -C "github-actions-deploy" -f ~/.ssh/github-actions-deploy # 将公钥添加到服务器 ssh-copy-id -i ~/.ssh/github-actions-deploy.pub user@your-server # 将私钥内容复制到 GitHub Secrets cat ~/.ssh/github-actions-deploy ``` ### 8.3 自动部署流程 1. **推送代码到 main 分支**: ```bash git push origin main ``` 2. **GitHub Actions 自动执行**: - 构建 backend 镜像 - 推送到 GHCR - SSH 到生产服务器 - 拉取最新镜像 - 重启服务 - 健康检查 3. **查看部署日志**: - 访问 GitHub Actions:`https://github.com/your-org/wecom-ai-assistant/actions` --- ## 九、常见问题 ### 9.1 服务启动失败 **症状**:`docker-compose ps` 显示服务状态为 `Restarting` 或 `Exited` **排查**: ```bash # 查看详细日志 docker-compose -f docker-compose.prod.yml logs backend # 检查环境变量 docker-compose -f docker-compose.prod.yml config ``` **常见原因**: - 环境变量未正确配置 - 端口被占用 - 镜像拉取失败 ### 9.2 HTTPS 证书问题 **症状**:浏览器显示"不安全连接"或证书错误 **排查**: ```bash # 检查证书 sudo certbot certificates # 检查证书有效期 sudo openssl x509 -in /etc/letsencrypt/live/your-domain.com/cert.pem -noout -dates # 测试续期 sudo certbot renew --dry-run ``` ### 9.3 企业微信回调失败 **症状**:企微后台保存失败,日志显示 `wecom verify failed` **排查**: 1. 检查 `.env.prod` 中的 `WECOM_TOKEN` 和 `WECOM_ENCODING_AES_KEY` 2. 确保与企微后台配置**完全一致**(包括大小写、空格) 3. 检查域名是否可访问:`curl https://your-domain.com/api/wecom/callback` 4. 查看后端日志:`docker-compose -f docker-compose.prod.yml logs backend` ### 9.4 镜像拉取失败 **症状**:`docker pull` 失败,提示认证错误 **解决**: ```bash # 登录到 GHCR docker login ghcr.io -u your-username -p your-token # 或使用 GitHub Personal Access Token echo $GITHUB_TOKEN | docker login ghcr.io -u your-username --password-stdin ``` --- ## 十、安全最佳实践 1. **环境变量**: - 使用 `.env.prod` 存储敏感信息 - **不要提交 `.env.prod` 到 Git 仓库** - 定期轮换密钥和 Token 2. **SSH 安全**: - 使用密钥认证,禁用密码登录 - 限制 SSH 访问 IP(可选) - 定期更新 SSH 密钥 3. **防火墙**: - 只开放必要的端口(80, 443, 22) - 使用 fail2ban 防止暴力破解(可选) 4. **日志**: - 定期清理日志文件 - 监控异常日志 5. **更新**: - 定期更新系统和 Docker - 及时应用安全补丁 --- ## 十一、参考文档 - [本地部署指南](./deploy-cloud-minimal.md) - [企业微信回调配置](./wecom.md) - [企业微信测试指南](./wecom-test-guide.md) - [GitHub Actions 部署 Workflow](../.github/workflows/deploy.yml)