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>
11 KiB
11 KiB
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 克隆仓库并配置环境变量
git clone https://github.com/zclaw/zclaw.git
cd zclaw
# 从模板创建环境变量文件
cp saas-env.example .env
2.2 编辑 .env 填入真实值
# 必须修改的变量:
# - 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 启动服务
# 构建并启动(后台运行)
docker compose up -d --build
# 查看日志
docker compose logs -f saas
# 验证服务健康
curl http://localhost:8080/health
2.4 常用运维命令
# 停止服务
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 提供默认配置,环境变量优先级更高:
[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
sudo apt update && sudo apt install -y nginx
4.2 获取 SSL 证书 (Let's Encrypt)
# 安装 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
# 复制配置模板
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 会自动设置定时续期:
# 验证续期定时器
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未设置或设为falsecors_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 防火墙配置
# 仅开放必要端口
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 日志审计
生产环境建议将日志写入文件并配置日志轮转:
# Nginx 日志轮转(通常已内置)
sudo vim /etc/logrotate.d/nginx
6. 备份策略
6.1 数据库备份
# 手动备份
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 恢复数据库
# 从备份恢复
gunzip -c /path/to/backups/zclaw_20260331.sql.gz | \
docker compose exec -T postgres psql -U zclaw -d zclaw_saas
6.3 环境变量备份
# 安全存储 .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 容器立即退出
排查步骤:
# 查看容器日志
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
排查步骤:
# 检查数据库容器状态
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 错误
排查步骤:
# 检查 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 磁盘空间不足
# 查看 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. 备份
[ ] 数据库自动备份已配置
[ ] 备份恢复测试已通过