feat(deploy): add Dockerfile, saas-env.example, nginx config, and production deployment guide

Multi-stage Docker build for zclaw-saas with dependency caching,
environment variable template with security defaults, Nginx reverse
proxy with SSE/WebSocket support and HTTPS, and comprehensive
Chinese-language production deployment documentation.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
iven
2026-03-31 10:26:30 +08:00
parent 8e6abc91e1
commit d0ae7d2770
4 changed files with 680 additions and 0 deletions

View File

@@ -0,0 +1,429 @@
# ZCLAW SaaS 生产环境部署指南
本指南覆盖 ZCLAW SaaS 后端的生产环境部署,包括 Docker 容器化、Nginx 反向代理、HTTPS 配置、安全加固和备份策略。
---
## 1. 环境要求
| 组件 | 最低版本 | 说明 |
|------------|-----------|------------------------------|
| Docker | 24.0+ | 容器运行时 |
| Docker Compose | v2.0+ | 容器编排 |
| Nginx | 1.24+ | 反向代理 + TLS 终止 |
| PostgreSQL | 16+ | 数据库Docker 内置或外部) |
| RAM | 2 GB+ | 最低内存 |
| Disk | 20 GB+ | 数据库 + 日志空间 |
### 端口规划
| 端口 | 用途 | 暴露方式 |
|-------|------------------------|--------------|
| 80 | HTTP (Nginx) | 外部 -> Nginx |
| 443 | HTTPS (Nginx) | 外部 -> Nginx |
| 8080 | SaaS 后端 (Axum) | 仅本地回环 |
| 5432 | PostgreSQL | 仅 Docker 网络 |
---
## 2. 快速启动 (Docker Compose)
### 2.1 克隆仓库并配置环境变量
```bash
git clone https://github.com/zclaw/zclaw.git
cd zclaw
# 从模板创建环境变量文件
cp saas-env.example .env
```
### 2.2 编辑 `.env` 填入真实值
```bash
# 必须修改的变量:
# - POSTGRES_PASSWORD 数据库密码
# - ZCLAW_DATABASE_URL 连接字符串(密码需与上面一致)
# - ZCLAW_SAAS_JWT_SECRET JWT 密钥openssl rand -hex 32
# - ZCLAW_TOTP_ENCRYPTION_KEY 加密密钥openssl rand -hex 32
# - ZCLAW_ADMIN_PASSWORD 管理员密码
# 生成随机密钥
export JWT_SECRET=$(openssl rand -hex 32)
export TOTP_KEY=$(openssl rand -hex 32)
# 使用 sed 替换(或手动编辑)
sed -i "s/请使用openssl_rand_hex_32生成/$JWT_SECRET/" .env
sed -i "0,/请使用openssl_rand_hex_32生成/s//$TOTP_KEY/" .env
```
### 2.3 启动服务
```bash
# 构建并启动(后台运行)
docker compose up -d --build
# 查看日志
docker compose logs -f saas
# 验证服务健康
curl http://localhost:8080/health
```
### 2.4 常用运维命令
```bash
# 停止服务
docker compose down
# 重启 SaaS 后端(不影响数据库)
docker compose restart saas
# 查看数据库状态
docker compose exec postgres pg_isready -U zclaw
# 进入数据库
docker compose exec postgres psql -U zclaw -d zclaw_saas
# 查看资源使用
docker stats zclaw-saas zclaw-postgres
```
---
## 3. 环境变量配置
### 3.1 核心变量
| 变量 | 必填 | 说明 |
|----------------------------|------|------------------------------------------|
| `POSTGRES_USER` | 是 | 数据库用户名 |
| `POSTGRES_PASSWORD` | 是 | 数据库密码 |
| `POSTGRES_DB` | 是 | 数据库名称 |
| `ZCLAW_DATABASE_URL` | 是 | 完整数据库连接 URL |
| `ZCLAW_SAAS_JWT_SECRET` | 是 | JWT 签名密钥(>= 32 字符随机字符串) |
| `ZCLAW_TOTP_ENCRYPTION_KEY`| 是 | TOTP/API Key 加密密钥64 字符 hex |
| `ZCLAW_ADMIN_USERNAME` | 否 | 初始管理员用户名(默认 admin |
| `ZCLAW_ADMIN_PASSWORD` | 否 | 初始管理员密码 |
| `ZCLAW_SAAS_DEV` | 否 | 开发模式标志(生产环境必须 false 或不设置) |
### 3.2 连接 URL 格式
```
postgres://<用户名>:<密码>@<主机>:<端口>/<数据库名>
```
Docker 内部网络使用主机名 `postgres`
```
ZCLAW_DATABASE_URL=postgres://zclaw:your_password@postgres:5432/zclaw_saas
```
外部 PostgreSQL 使用实际 IP/域名:
```
ZCLAW_DATABASE_URL=postgres://zclaw:your_password@10.0.0.5:5432/zclaw_saas
```
### 3.3 saas-config.toml 配置
`saas-config.toml` 提供默认配置,环境变量优先级更高:
```toml
[server]
host = "0.0.0.0"
port = 8080
cors_origins = ["https://your-domain.com"]
[database]
url = "postgres://zclaw:${DB_PASSWORD}@localhost:5432/zclaw"
[auth]
jwt_expiration_hours = 24
totp_issuer = "ZCLAW SaaS"
[rate_limit]
requests_per_minute = 60
burst = 10
```
配置支持 `${ENV_VAR}` 环境变量插值。
---
## 4. Nginx 反向代理 + HTTPS
### 4.1 安装 Nginx
```bash
sudo apt update && sudo apt install -y nginx
```
### 4.2 获取 SSL 证书 (Let's Encrypt)
```bash
# 安装 certbot
sudo apt install -y certbot python3-certbot-nginx
# 获取证书(替换为你的域名和邮箱)
sudo certbot --nginx -d api.yourdomain.com -m admin@yourdomain.com --agree-tos
```
### 4.3 配置 Nginx
```bash
# 复制配置模板
sudo cp deploy/nginx.conf /etc/nginx/sites-available/zclaw-saas
# 替换占位符
sudo sed -i 's/<YOUR_DOMAIN>/api.yourdomain.com/g' /etc/nginx/sites-available/zclaw-saas
sudo sed -i 's|<CERT_PATH>|/etc/letsencrypt/live/api.yourdomain.com/fullchain.pem|g' /etc/nginx/sites-available/zclaw-saas
sudo sed -i 's|<KEY_PATH>|/etc/letsencrypt/live/api.yourdomain.com/privkey.pem|g' /etc/nginx/sites-available/zclaw-saas
# 启用站点
sudo ln -sf /etc/nginx/sites-available/zclaw-saas /etc/nginx/sites-enabled/
sudo rm -f /etc/nginx/sites-enabled/default
# 验证配置
sudo nginx -t
# 重载 Nginx
sudo systemctl reload nginx
```
### 4.4 自动续期
Let's Encrypt 证书有效期为 90 天certbot 会自动设置定时续期:
```bash
# 验证续期定时器
sudo systemctl status certbot.timer
# 手动测试续期
sudo certbot renew --dry-run
```
### 4.5 SSE / WebSocket 注意事项
Nginx 配置中已包含 SSE 流式响应支持:
- `proxy_buffering off` - 禁用缓冲,确保事件实时推送
- `proxy_read_timeout 300s` - 5 分钟超时,支持长连接
- `Upgrade` / `Connection` 头 - 支持 WebSocket 升级
如果需要更长的流式响应时间,调大 `proxy_read_timeout`
---
## 5. 安全清单
### 5.1 部署前必检
- [ ] 所有密码/密钥已替换为强随机值(非模板默认值)
- [ ] `ZCLAW_SAAS_DEV` 未设置或设为 `false`
- [ ] `cors_origins` 仅包含实际域名(不含 localhost
- [ ] PostgreSQL 端口 (5432) 未暴露到公网
- [ ] SaaS 后端端口 (8080) 仅绑定 127.0.0.1
- [ ] SSL 证书已配置且有效
- [ ] Nginx 安全头已启用X-Frame-Options, HSTS 等)
- [ ] `.env` 文件权限设为 600`chmod 600 .env`
### 5.2 Cookie 安全
| 属性 | 开发环境 | 生产环境 |
|---------------|---------|---------|
| `Secure` | false | true |
| `HttpOnly` | true | true |
| `SameSite` | Strict | Strict |
| Path | /api | /api |
### 5.3 Rate Limiting
内置 API 请求限流:
- `/api/auth/login` - 5 次/分钟/IP防暴力破解
- `/api/auth/register` - 3 次/小时/IP防刷注册
- 公共端点 - 20 次/分钟/IP防滥用
### 5.4 防火墙配置
```bash
# 仅开放必要端口
sudo ufw default deny incoming
sudo ufw allow 22/tcp # SSH
sudo ufw allow 80/tcp # HTTP
sudo ufw allow 443/tcp # HTTPS
sudo ufw enable
```
### 5.5 日志审计
生产环境建议将日志写入文件并配置日志轮转:
```bash
# Nginx 日志轮转(通常已内置)
sudo vim /etc/logrotate.d/nginx
```
---
## 6. 备份策略
### 6.1 数据库备份
```bash
# 手动备份
docker compose exec postgres pg_dump -U zclaw zclaw_saas > backup_$(date +%Y%m%d_%H%M%S).sql
# 自动每日备份crontab
# 每天凌晨 3 点备份
echo "0 3 * * * docker compose -f /path/to/zclaw/docker-compose.yml exec -T postgres pg_dump -U zclaw zclaw_saas | gzip > /path/to/backups/zclaw_\$(date +\%Y\%m\%d).sql.gz" | crontab -
```
### 6.2 恢复数据库
```bash
# 从备份恢复
gunzip -c /path/to/backups/zclaw_20260331.sql.gz | \
docker compose exec -T postgres psql -U zclaw -d zclaw_saas
```
### 6.3 环境变量备份
```bash
# 安全存储 .env 文件
cp .env /path/to/backups/env_$(date +%Y%m%d)
chmod 600 /path/to/backups/env_*
```
### 6.4 备份保留策略
| 备份类型 | 保留期限 | 频率 |
|-----------|-----------|---------|
| 每日备份 | 7 天 | 每天一次 |
| 每周备份 | 4 周 | 每周日 |
| 每月备份 | 12 个月 | 每月 1 日 |
---
## 7. 常见问题
### 7.1 服务无法启动
**症状**: `docker compose up` 后 saas 容器立即退出
**排查步骤**:
```bash
# 查看容器日志
docker compose logs saas
# 检查环境变量是否正确
docker compose config
# 检查数据库是否就绪
docker compose exec postgres pg_isready -U zclaw
```
**常见原因**:
- 数据库 URL 格式错误
- JWT 密钥未设置
- PostgreSQL 尚未就绪healthcheck 未通过)
### 7.2 数据库连接失败
**症状**: 日志显示 `connection refused``authentication failed`
**排查步骤**:
```bash
# 检查数据库容器状态
docker compose ps postgres
# 验证连接字符串
docker compose exec saas env | grep DATABASE_URL
# 测试数据库连接
docker compose exec postgres psql -U zclaw -d zclaw_saas -c "SELECT 1"
```
### 7.3 502 Bad Gateway
**症状**: Nginx 返回 502 错误
**排查步骤**:
```bash
# 检查 SaaS 后端是否运行
curl http://127.0.0.1:8080/health
# 检查 Nginx 错误日志
sudo tail -50 /var/log/nginx/zclaw-saas-error.log
# 检查端口绑定
ss -tlnp | grep 8080
```
### 7.4 SSE 流式响应中断
**症状**: 聊天响应在中间断开
**解决方案**:
- 确认 Nginx `proxy_buffering off` 已设置
- 增大 `proxy_read_timeout`(默认 300s
- 检查 Nginx 错误日志是否有 upstream timeout
### 7.5 Docker 构建缓慢
**症状**: `docker build` 耗时很长
**优化**:
- Dockerfile 已配置依赖缓存层,首次构建后仅重建源码变更
- 确保 `.dockerignore` 排除了 `target/``node_modules/` 等大目录
- 使用 `docker compose build --parallel` 并行构建
### 7.6 磁盘空间不足
```bash
# 查看 Docker 磁盘使用
docker system df
# 清理未使用的资源
docker system prune -a --volumes
# 查看数据库大小
docker compose exec postgres psql -U zclaw -c "SELECT pg_size_pretty(pg_database_size('zclaw_saas'));"
```
---
## 附录: 完整部署检查清单
```
[ ] 1. 服务器准备
[ ] 2GB+ RAM, 20GB+ 磁盘
[ ] Docker + Docker Compose 已安装
[ ] 防火墙已配置(仅 22/80/443
[ ] 2. 应用配置
[ ] .env 已从模板创建并填入真实值
[ ] 所有密钥已用 openssl rand -hex 32 生成
[ ] ZCLAW_SAAS_DEV=false
[ ] saas-config.toml cors_origins 已更新
[ ] 3. 启动服务
[ ] docker compose up -d --build 成功
[ ] docker compose ps 显示所有容器 healthy
[ ] curl http://localhost:8080/health 返回 200
[ ] 4. HTTPS 配置
[ ] SSL 证书已获取
[ ] Nginx 配置已部署并测试 (nginx -t)
[ ] HTTP 正确重定向到 HTTPS
[ ] https://api.yourdomain.com/health 返回 200
[ ] 5. 安全验证
[ ] 安全头存在curl -I https://api.yourdomain.com
[ ] 5432 端口外部不可访问
[ ] 8080 端口仅 127.0.0.1 可访问
[ ] .env 文件权限 600
[ ] 6. 备份
[ ] 数据库自动备份已配置
[ ] 备份恢复测试已通过
```