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

15 KiB
Raw Permalink Blame History

生产环境部署指南

一、概述

本文档描述如何在云端服务器上部署企业微信 AI 助手的最小回调壳,支持企业微信回调 URL 校验和消息回调。

部署架构

企业微信 → HTTPS (443) → Nginx → Backend (8000)
                              ↓
                          PostgreSQL (可选)

服务清单

  • backend: Python 3.12 + FastAPI + Uvicorn最小回调壳
  • nginx: 反向代理 + HTTPSLet's Encrypt
  • db: PostgreSQL 16可选最小回调壳可以先不启用
  • admin: Next.js 管理后台(可选,最小回调壳可以先不启用)

二、云服务器准备

2.1 服务器要求

  • 操作系统Ubuntu 20.04+ / CentOS 7+ / Debian 11+
  • CPU1 核以上
  • 内存1GB 以上(推荐 2GB
  • 磁盘20GB 以上
  • 网络:公网 IP开放 80/443 端口

2.2 安装 Docker 和 Docker Compose

Ubuntu/Debian

# 更新系统
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

# 安装依赖
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)

# 允许 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)

# 允许 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 解析

# 检查 DNS 解析
nslookup your-domain.com
# 或
dig your-domain.com

# 应该返回你的服务器 IP

四、项目部署

4.1 克隆项目

# 创建项目目录
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 配置环境变量

# 复制环境变量模板
cp .env.example .env.prod

# 编辑 .env.prod填写必需变量
nano .env.prod

必需变量

# ============ 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

重要

  • WECOM_TOKENWECOM_ENCODING_AES_KEY 必须与企微后台配置完全一致
  • .env.prod 文件包含敏感信息,不要提交到 Git 仓库

4.3 首次部署

方式 A使用部署脚本推荐

# 赋予执行权限
chmod +x deploy/scripts/*.sh

# 启动服务
./deploy/scripts/start.sh

方式 B手动部署

# 设置镜像标签(默认 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

sudo apt-get update
sudo apt-get install -y certbot python3-certbot-nginx

CentOS/RHEL

sudo yum install -y certbot python3-certbot-nginx

5.2 配置 Nginx 占位路径

在获取证书之前,需要先配置 Nginx 的 HTTP 服务,以便 Certbot 验证域名所有权。

临时修改 deploy/docker/nginx.conf

# 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;
    }
}

创建验证目录

sudo mkdir -p /var/www/certbot
sudo chown -R $USER:$USER /var/www/certbot

更新 docker-compose.prod.yml,添加验证目录挂载:

nginx:
  volumes:
    - ./deploy/docker/nginx.conf:/etc/nginx/nginx.conf:ro
    - /var/www/certbot:/var/www/certbot:ro  # 添加此行

重启 Nginx

docker-compose -f docker-compose.prod.yml restart nginx

5.3 申请 SSL 证书

# 设置域名和邮箱
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

# 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,确保证书目录已挂载:

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

docker-compose -f docker-compose.prod.yml restart nginx

5.5 配置证书自动续期

Let's Encrypt 证书有效期为 90 天,需要定期续期。

# 测试续期
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 首次部署

# 使用部署脚本
./deploy/scripts/start.sh

# 或手动部署
docker-compose -f docker-compose.prod.yml --env-file .env.prod up -d

6.2 更新部署

方式 A使用部署脚本

# 更新到最新版本
./deploy/scripts/update.sh latest

# 更新到指定版本
./deploy/scripts/update.sh v1.0.0

方式 B手动更新

# 设置镜像标签
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 回滚部署

# 回滚到指定版本(需要知道之前的镜像标签)
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

查看历史版本

# 查看 GitHub Container Registry 中的镜像标签
# 访问: https://github.com/your-org/wecom-ai-assistant/pkgs/container/wecom-ai-backend

6.4 停止服务

# 使用部署脚本
./deploy/scripts/stop.sh

# 或手动停止
docker-compose -f docker-compose.prod.yml --env-file .env.prod down

七、验证部署

7.1 检查服务状态

# 查看服务状态
docker-compose -f docker-compose.prod.yml ps

# 查看日志
docker-compose -f docker-compose.prod.yml logs -f backend

7.2 健康检查

# 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
    • 进入:应用管理 → 自建应用 → 选择你的应用
    • 配置回调:
      • 接收消息服务器 URLhttps://your-domain.com/api/wecom/callback
      • Token:与 .env.prod 中的 WECOM_TOKEN 完全一致
      • EncodingAESKey:与 .env.prod 中的 WECOM_ENCODING_AES_KEY 完全一致
      • 消息加解密方式安全模式
    • 点击 保存
  2. 验证 GET 校验

    • 保存后,企业微信会立即发送 GET 请求验证
    • 观察后端日志:
      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 密钥对

# 在本地生成 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 分支

    git push origin main
    
  2. GitHub Actions 自动执行

    • 构建 backend 镜像
    • 推送到 GHCR
    • SSH 到生产服务器
    • 拉取最新镜像
    • 重启服务
    • 健康检查
  3. 查看部署日志

    • 访问 GitHub Actionshttps://github.com/your-org/wecom-ai-assistant/actions

九、常见问题

9.1 服务启动失败

症状docker-compose ps 显示服务状态为 RestartingExited

排查

# 查看详细日志
docker-compose -f docker-compose.prod.yml logs backend

# 检查环境变量
docker-compose -f docker-compose.prod.yml config

常见原因

  • 环境变量未正确配置
  • 端口被占用
  • 镜像拉取失败

9.2 HTTPS 证书问题

症状:浏览器显示"不安全连接"或证书错误

排查

# 检查证书
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_TOKENWECOM_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 失败,提示认证错误

解决

# 登录到 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
    • 及时应用安全补丁

十一、参考文档