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>
430 lines
11 KiB
Markdown
430 lines
11 KiB
Markdown
# 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. 备份
|
||
[ ] 数据库自动备份已配置
|
||
[ ] 备份恢复测试已通过
|
||
```
|