372 lines
19 KiB
Markdown
372 lines
19 KiB
Markdown
# 数字化桃育种系统 生产上线与运营手册
|
||||
|
|
|
|||
|
|
> 版本:3.0.1 适用:生产(Docker Compose)部署
|
|||
|
|
> 前置阅读:`docker/README.md`(部署操作)、`doc/桃育种系统模块扩展需求规格.md`(功能规格,v2.7,2026-08-04)
|
|||
|
|
> 本文档基于 2026-08-04 安全加固后的代码与配置撰写,上线前请逐项核对。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 1. 部署架构
|
|||
|
|
|
|||
|
|
### 1.1 组件清单
|
|||
|
|
|
|||
|
|
| 组件 | 技术栈 | 容器/进程 | 说明 |
|
|||
|
|
|------|--------|-----------|------|
|
|||
|
|
| 前端 | Vue(Vite 构建) | nginx 托管静态文件 | 经 `/web` 路径访问 |
|
|||
|
|
| 反向代理 | nginx 1.25-alpine | 容器 `nginx` | TLS 终结、HTTP→HTTPS、API 反代、限流 |
|
|||
|
|
| 后端 | FastAPI + SQLAlchemy async + Redis | 容器 `backend` | `python main.py run --env=prod` |
|
|||
|
|
| 数据库 | PostgreSQL 16 | 容器 `postgres` | 见 §3 |
|
|||
|
|
| 缓存 | Redis 7 | 容器 `redis` | 会话、验证码、登录锁定计数、系统参数缓存 |
|
|||
|
|
|
|||
|
|
### 1.2 端口暴露(已收紧到本机回环)
|
|||
|
|
|
|||
|
|
| 服务 | 容器端口 | 宿主机绑定 | 说明 |
|
|||
|
|
|------|----------|-----------|------|
|
|||
|
|
| nginx | 80 / 443 | `0.0.0.0`(公网) | 唯一对外入口 |
|
|||
|
|
| backend | 8001 | `127.0.0.1:8001` | 仅本机/容器网络可访问 |
|
|||
|
|
| 数据库 | 5432 | `127.0.0.1` | 仅本机可连,公网不可达 |
|
|||
|
|
| Redis | 6379 | `127.0.0.1` | 仅本机可连 |
|
|||
|
|
|
|||
|
|
> 安全边界:公网只能到达 nginx。后端 8001 直连会被跳过 Host 头/CORS/HTTPS 约束,因此**切勿把 backend 端口改成公网绑定**。
|
|||
|
|
|
|||
|
|
### 1.3 数据流
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
浏览器 ──443──> nginx(TLS/限流/反代)──8001──> backend ──> PostgreSQL 16
|
|||
|
|
└──> Redis
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 2. 配置体系
|
|||
|
|
|
|||
|
|
项目有两层配置,容易混淆,务必分清:
|
|||
|
|
|
|||
|
|
### 2.1 编排层:`docker/.env`
|
|||
|
|
|
|||
|
|
Docker Compose 使用(`docker compose --env-file .env up -d`)。必填项缺失时 compose 直接报错。
|
|||
|
|
|
|||
|
|
| 变量 | 必填 | 说明 |
|
|||
|
|
|------|------|------|
|
|||
|
|
| `DATABASE_USER` | 否 | 数据库用户(默认 `dpb`) |
|
|||
|
|
| `DATABASE_PASSWORD` | **是** | 数据库口令,强随机 |
|
|||
|
|
| `DATABASE_NAME` | 否 | 数据库名(默认 `dpb`) |
|
|||
|
|
| `DATABASE_PORT` | 否 | 数据库端口(默认 `5432`) |
|
|||
|
|
| `REDIS_PASSWORD` | **是** | Redis 口令,强随机 |
|
|||
|
|
| `SECRET_KEY` | **是** | JWT 签名密钥,`openssl rand -hex 32`,勿用示例值 |
|
|||
|
|
| `BACKEND_PORT` / `HTTP_PORT` / `HTTPS_PORT` | 否 | 默认 8001 / 80 / 443 |
|
|||
|
|
| `DEPLOY_ENV` | 否 | 固定 `prod` |
|
|||
|
|
|
|||
|
|
### 2.2 应用层配置(容器部署:全部收敛到 `docker/.env`)
|
|||
|
|
|
|||
|
|
**容器镜像已排除 `backend/env` 目录**(构建镜像不携带任何 .env 文件,防止凭据进镜像),生产全部配置由 `docker-compose` 以环境变量注入后端。因此 **`docker/.env` 是生产唯一配置源**,`backend/env/.env.prod` 仅用于裸机/非容器部署。
|
|||
|
|
|
|||
|
|
> 镜像内 `backend/env/.env.prod` 不存在时,`main.py` 的 env_file 加载被跳过,配置完全来自 compose 注入的环境变量(compose 已注入下述全部字段)。
|
|||
|
|
|
|||
|
|
| 变量 | 生产要求 | 说明 |
|
|||
|
|
|------|----------|------|
|
|||
|
|
| `ENVIRONMENT` | `prod` | compose 已注入 |
|
|||
|
|
| `DEBUG` | `false` | 开启则 prod 校验拒绝启动 |
|
|||
|
|
| `SECRET_KEY` | ≥32 位独立随机 | compose 已注入,兜底校验 |
|
|||
|
|
| `PROD_CORS_ORIGINS` | 具体域名,逗号分隔 | 空则拒绝启动 |
|
|||
|
|
| `ALLOWED_HOSTS` | 真实域名列表 | nginx 反代时后端据此校验 Host 头,未配置则请求 403 |
|
|||
|
|
| `IP_TRUST_PROXY_HEADERS` | `true` | 经 nginx 转发时必须开启;公网直连必须 `false` |
|
|||
|
|
| `LOGIN_MAX_FAILURES` 等 | 保持默认 | 登录锁定策略,见 §5 |
|
|||
|
|
| `DATABASE_TYPE` | `postgres` | compose 已注入,固定不变 |
|
|||
|
|
| `DATABASE_*` | — | compose 注入(容器部署时不读 `.env.prod`) |
|
|||
|
|
| `REDIS_PASSWORD` | — | compose 注入 |
|
|||
|
|
| `DEV_DEFAULT_PASSWORD` | **必须留空** | 非空 = 把密码明文下发浏览器 |
|
|||
|
|
| `SMTP_*` / `OPENAI_*` | 真实密钥 | 按需在 `docker/.env` 配置 |
|
|||
|
|
|
|||
|
|
### 2.3 加载优先级
|
|||
|
|
|
|||
|
|
容器部署(镜像不含 env 文件):`docker-compose` 注入的环境变量 > `setting.py` 默认值。
|
|||
|
|
裸机部署(本地起 prod):`backend/env/.env.prod` > `setting.py` 默认值。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 3. 数据库(PostgreSQL 16)
|
|||
|
|
|
|||
|
|
生产固定使用 PostgreSQL 16,与开发环境(`localhost:5432`,库/角色 `dpb`)一致,可用 `pg_dump`/`pg_restore` 无缝迁移。
|
|||
|
|
|
|||
|
|
`docker/docker-compose.yaml` 已编排 `postgres:16` 服务:
|
|||
|
|
|
|||
|
|
| 配置 | 值 |
|
|||
|
|
|------|-----|
|
|||
|
|
| 镜像 | `postgres:16`(容器名 `postgres`) |
|
|||
|
|
| 库名 / 用户 | 默认 `dpb`(`docker/.env` 的 `DATABASE_NAME` / `DATABASE_USER`) |
|
|||
|
|
| 口令 | `docker/.env` 的 `DATABASE_PASSWORD`(compose 强制必填,缺失即报错) |
|
|||
|
|
| 宿主机端口 | `127.0.0.1:5432`(仅本机可连,公网不可达) |
|
|||
|
|
| 数据卷 | `docker/postgres/data`(bind,容器内 `/var/lib/postgresql/data`) |
|
|||
|
|
| 健康检查 | `pg_isready`(backend 容器依赖其 healthy 才启动) |
|
|||
|
|
|
|||
|
|
首次启动时 postgres 容器自动初始化库与角色(`POSTGRES_DB/USER/PASSWORD`),无需手动建库。后端按 `DATABASE_TYPE=postgres` + `asyncpg` 驱动连接(compose 已注入),首次启动自动建表并导入种子数据(见 §4.3)。
|
|||
|
|
|
|||
|
|
> **数据目录**:`docker/postgres/data` 需存在(`deploy.sh` 会自动创建)。postgres 镜像启动时会自动把该目录 chown 到 postgres 用户(uid 999);若手动建目录后遇到权限错误,执行 `sudo chown -R 999:999 docker/postgres/data`。
|
|||
|
|
|
|||
|
|
### 3.1 开发数据迁移到生产
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
# 开发机导出(需本机装有 PostgreSQL 客户端 pg_dump)
|
|||
|
|
pg_dump -h localhost -p 5432 -U dpb -d dpb --no-owner -F c -f dpb.dump
|
|||
|
|
|
|||
|
|
# 生产导入(进 postgres 容器;生产服务器同样需要 pg_restore)
|
|||
|
|
docker compose exec postgres pg_restore -U dpb -d dpb --no-owner /tmp/dpb.dump
|
|||
|
|
# 或先将 dump 拷入容器:docker compose cp dpb.dump postgres:/tmp/
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
> 注意中文编码:Windows 下 psql 交互易乱码,用 `pg_restore -F c`(二进制格式)导入可规避。生产服务器如缺 `pg_restore`,先 `apt-get install -y postgresql-client`。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 4. 首次上线步骤
|
|||
|
|
|
|||
|
|
### 4.1 服务器准备
|
|||
|
|
|
|||
|
|
- Docker ≥ 20.10 + Docker Compose v2;建议 4 核 / 8GB 起步。
|
|||
|
|
- 防火墙/安全组**只开放 80、443**,其余端口(8001、5432、6379 等)一律不放行。
|
|||
|
|
- 确认服务器时区、磁盘空间(数据库卷建议 ≥50GB,监控磁盘水位)。
|
|||
|
|
|
|||
|
|
### 4.2 配置落地
|
|||
|
|
|
|||
|
|
1. 拷贝项目到服务器(当前仓库未接入 git,直接同步目录)。
|
|||
|
|
2. 准备编排层配置:
|
|||
|
|
```bash
|
|||
|
|
cd docker
|
|||
|
|
cp .env.example .env
|
|||
|
|
chmod 600 .env
|
|||
|
|
# 必改:REDIS_PASSWORD、SECRET_KEY(openssl rand -hex 32)、DATABASE_PASSWORD
|
|||
|
|
```
|
|||
|
|
3. 数据库已是 PostgreSQL 16(compose 已编排 `postgres` 服务),无需改编排;`DATABASE_*` 已在步骤 2 配置。
|
|||
|
|
4. 生产配置全部在 `docker/.env`(镜像已排除 `backend/env`,无需改 `.env.prod`):
|
|||
|
|
```bash
|
|||
|
|
# 必改:SECRET_KEY(openssl rand -hex 32)、DATABASE_PASSWORD、REDIS_PASSWORD、
|
|||
|
|
# PROD_CORS_ORIGINS(真实域名)、ALLOWED_HOSTS(真实域名)、SMTP_*/OPENAI_*(按需)
|
|||
|
|
```
|
|||
|
|
5. SSL 证书放入 `docker/nginx/ssl/`(`server.pem` + `server.key`),生产用正规 CA 证书。
|
|||
|
|
6. 修改 `docker/nginx/nginx.conf` 两处 `server_name` 为真实域名。
|
|||
|
|
7. 构建前端(若单独维护):
|
|||
|
|
```bash
|
|||
|
|
cd frontend/web && npm install && npm run build
|
|||
|
|
cp -r dist ../docker/nginx/web/dist
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 4.3 建表与初始数据(自动完成,无需手操)
|
|||
|
|
|
|||
|
|
后端首次启动时 `InitializeData.init_db()` 会:
|
|||
|
|
1. `create_all` **自动创建全部表**(仅建新表,不会修改已存在的表);
|
|||
|
|
2. 导入种子数据:菜单、部门、字典、角色、系统参数、默认用户。
|
|||
|
|
|
|||
|
|
种子用户(`backend/sql/data/sys_user.json`):`super`、`admin`(均为超管)、`user`。
|
|||
|
|
|
|||
|
|
**生产首次初始化时,种子账号的固定弱密码会被自动随机化**(消除公开的 `123456`)。一次性初始密码写入容器 `logs/prod_initial_passwords.txt`(同时打印到后端启动日志),运维需在首次登录后立即修改,并**删除该文件**:
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
docker compose exec backend cat /home/logs/prod_initial_passwords.txt # 查看随机初始密码
|
|||
|
|
# 登录修改密码后删除:
|
|||
|
|
docker compose exec backend rm /home/logs/prod_initial_passwords.txt
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
> 表结构变更:`create_all` 只建新表,**不会更新已存在的表**。模型字段变更走 `backend/sql/weld_*.sql` 幂等 ALTER(见 §6.4),不在本机执行;首次上线后新列的 SQL 由运维/开发在升级时统一应用。
|
|||
|
|
|
|||
|
|
### 4.4 构建与启动
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
cd docker
|
|||
|
|
docker compose --env-file .env build backend
|
|||
|
|
docker compose --env-file .env up -d
|
|||
|
|
docker compose ps # 全部 healthy 为佳
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 4.5 上线验证清单
|
|||
|
|
|
|||
|
|
- [ ] `docker compose ps` 四个服务均 `Up`(backend 至少 `starting`→`healthy`)
|
|||
|
|
- [ ] 健康检查:`curl -s https://域名/api/v1/common/health/check` 返回 200(就绪含依赖状态:`/api/v1/common/health/ready`)
|
|||
|
|
- [ ] 前端 `https://域名/web` 可打开登录页
|
|||
|
|
- [ ] 用 `super`/`admin` 登录成功(初始密码见 §4.3,生产默认开启滑块验证码,登录前需先完成滑块)
|
|||
|
|
- [ ] 登录后立即修改初始密码,并删除 `logs/prod_initial_passwords.txt`
|
|||
|
|
- [ ] 生产文档已关闭:`https://域名/docs` 应返回 404(符合预期)
|
|||
|
|
- [ ] `docker compose exec backend python -c "from app.config.setting import settings; print(settings.SECRET_KEY[:4]+'...')"` 确认不是默认密钥
|
|||
|
|
- [ ] 改掉种子账号默认密码,删除/停用不需要的账号(如 `user`)
|
|||
|
|
- [ ] 验证上传:控制台上传一张图片,确认 `backend/static/upload` 有文件且可访问
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 5. 安全加固核对表
|
|||
|
|
|
|||
|
|
### 5.1 代码层已加固(本次安全修复,无需重复操作)
|
|||
|
|
|
|||
|
|
| 项 | 加固内容 | 位置 |
|
|||
|
|
|----|----------|------|
|
|||
|
|
| 生产配置 fail-safe | SECRET_KEY 非默认/≥32 位、DEBUG=false、CORS 非空,否则**拒绝启动** | `setting.py` |
|
|||
|
|
| 日志脱敏 | 密码/token/验证码等字段掩码为 `***`;refresh/logout 裸 body 整体掩码 | `router_class.py` |
|
|||
|
|
| 登录暴力破解 | 同一用户名+IP 连续失败 5 次锁定 15 分钟(Redis);Redis 故障时自动降级不锁死 | `auth/service.py` |
|
|||
|
|
| 生产关闭文档 | `/docs`、`/redoc` 生产不注册 | `init_app.py` |
|
|||
|
|
| 客户端 IP 防伪造 | 默认不信任 XFF;`IP_TRUST_PROXY_HEADERS=true` 才读取 | `ip_local_util.py` |
|
|||
|
|
| 端口收内网 | 数据库/Redis/后端均绑 `127.0.0.1` | `docker-compose.yaml` |
|
|||
|
|
| 镜像自包含 | Dockerfile `COPY ./backend/`,生产不依赖宿主机代码挂载 | `Dockerfile` |
|
|||
|
|
| Redis 危险命令禁用 | `CONFIG`/`FLUSHALL`/`FLUSHDB` 重命名禁用;`protected-mode yes` | `redis.conf` |
|
|||
|
|
| 镜像排除凭据 | `.dockerignore` 排除 `backend/env`,`.env.dev`(含真实 SMTP 密码)等不进镜像;生产配置全走 `docker/.env` | `.dockerignore` |
|
|||
|
|
| 容器非 root 运行 | Dockerfile `USER app` + compose `user: 1001:1001`;配合 `cap_drop: ALL`、`no-new-privileges`、`tmpfs /tmp` | `Dockerfile` / `docker-compose.yaml` |
|
|||
|
|
| 种子账号弱口令消除 | 生产首次初始化把公开的 `123456` 种子密码随机化,一次性初始密码写 `logs/prod_initial_passwords.txt` | `initialize.py` |
|
|||
|
|
| HSTS / 权限策略 | nginx 补 `Strict-Transport-Security`、`Permissions-Policy`,移除已废弃的 `X-XSS-Protection` | `nginx.conf` |
|
|||
|
|
| 无用数据库依赖 | 移除 `aiomysql`/`pymysql`/`aiosqlite`(仅 PostgreSQL 驱动 `asyncpg`/`psycopg`) | `requirements.txt` / `pyproject.toml` |
|
|||
|
|
|
|||
|
|
### 5.2 运维层待办(上线时逐项落实)
|
|||
|
|
|
|||
|
|
- [ ] `docker/.env` 权限 `chmod 600`,禁止进版本库
|
|||
|
|
- [ ] 防火墙仅放行 80/443
|
|||
|
|
- [ ] 使用正规 CA 的 SSL 证书
|
|||
|
|
- [ ] 从 `logs/prod_initial_passwords.txt` 获取随机初始密码登录,立即修改并删除该文件
|
|||
|
|
- [ ] 数据库账号使用独立强口令,不用 root 直连业务
|
|||
|
|
- [ ] 配置备份任务并做一次恢复演练(§6.2)
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 6. 日常运营
|
|||
|
|
|
|||
|
|
### 6.1 启停与状态
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
cd docker
|
|||
|
|
docker compose --env-file .env ps # 状态
|
|||
|
|
docker compose --env-file .env up -d # 启动
|
|||
|
|
docker compose --env-file .env restart backend # 仅重启后端
|
|||
|
|
docker compose --env-file .env stop # 停止(保留数据卷)
|
|||
|
|
docker compose --env-file .env down # 停止并移除容器(卷保留)
|
|||
|
|
docker compose logs -f backend # 实时日志
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 6.2 备份与恢复
|
|||
|
|
|
|||
|
|
**备份优先级**:数据库 > 上传文件 > 配置 > 前端产物(可重建)> Redis(会话可重建)。
|
|||
|
|
|
|||
|
|
| 数据 | 位置 | 策略 |
|
|||
|
|
|------|------|------|
|
|||
|
|
| 数据库(核心) | 数据库卷 | 每日全量 + 保留 7~14 天,异地一份 |
|
|||
|
|
| 上传文件 | `backend/static/upload`(容器内 `/home/static/upload`) | 每日增量同步 |
|
|||
|
|
| 配置 | `docker/.env`、`backend/env/.env.prod` | 每次变更后备份 |
|
|||
|
|
| Redis | 会话/缓存 | 无需备份(丢失仅踢下线) |
|
|||
|
|
|
|||
|
|
**PostgreSQL 每日备份**(宿主机 crontab 示例):
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
0 2 * * * cd /opt/dpb/docker && docker compose exec -T postgres pg_dump -U dpb -d dpb --no-owner -F c \
|
|||
|
|
> /backup/dpb_$(date +\%F).dump && \
|
|||
|
|
find /backup -name 'dpb_*.dump' -mtime +14 -delete
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**恢复演练**(每季度一次,确保备份可用):
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
# 临时起一个空库恢复验证:
|
|||
|
|
docker compose exec postgres pg_restore -U dpb -d dpb --no-owner /backup/dpb_最近.dump
|
|||
|
|
# 上传文件:解压覆盖 backend/static/upload 即可
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 6.3 日志与监控
|
|||
|
|
|
|||
|
|
- **容器日志**:Docker 已配置轮转(每容器最多 3 个文件 × 10MB)。查看:`docker compose logs --tail=200 backend`。
|
|||
|
|
- **后端应用日志**:`backend/logs/`(容器内 `/home/logs`)。
|
|||
|
|
- **监控项**:
|
|||
|
|
- 健康检查:`/api/v1/common/health/check`(存活)与 `/api/v1/common/health/ready`(就绪,含 DB/Redis/磁盘,依赖未就绪返回 503);compose 已内置存活探针(15s 间隔,探测 `/common/health/check`)
|
|||
|
|
- 磁盘水位(数据库卷最易满)
|
|||
|
|
- 登录失败/锁定:日志关键字 `登录失败次数过多`、`已锁定`
|
|||
|
|
- 资源:compose 已设内存上限(backend 1G / postgres 1G / redis 512M / nginx 256M)
|
|||
|
|
|
|||
|
|
### 6.4 升级与表结构变更
|
|||
|
|
|
|||
|
|
**常规升级**(无模型变更):
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
cd docker
|
|||
|
|
docker compose --env-file .env build backend # 重新构建新镜像
|
|||
|
|
docker compose --env-file .env up -d --no-deps backend
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**模型字段变更**:`create_all` 只建新表、不更新已存在的表。本项目实际变更约定为**幂等 ALTER SQL 文件**(`backend/sql/weld_*.sql`,`ADD COLUMN IF NOT EXISTS`),新增列均以 psql 手动应用(**Alembic 脚手架存在但从未使用**——`backend/app/alembic/versions/` 为空,勿在本项目启用,与既有 weld 文件重复冲突):
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
# 开发机应用(对 dev 库):
|
|||
|
|
PGPASSWORD=dpb psql -h localhost -p 5432 -U dpb -d dpb -w -f backend/sql/weld_xxx.sql
|
|||
|
|
# 生产应用(先进容器,SQL 已随镜像/同步目录带入):
|
|||
|
|
docker compose cp backend/sql/weld_xxx.sql postgres:/tmp/weld_xxx.sql
|
|||
|
|
docker compose exec postgres psql -U dpb -d dpb -f /tmp/weld_xxx.sql
|
|||
|
|
# 清理:
|
|||
|
|
docker compose exec postgres rm /tmp/weld_xxx.sql
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
> 新增列示例:`weld_prediction_rigor.sql`(PA/溯源)、`weld_rootstock.sql`(矮化类/砧穗亲和性)、`weld_trait_direction.sql`(方向标注)、`weld_combining_design.sql`(交配设计)——文件幂等,重跑无害,可批量串行应用。**升级前先备份数据库(§6.2)**;涉及大表加列建议维护窗口执行(Postgres 11+ `ADD COLUMN` 默认仅加元数据,不需重写表,风险低)。
|
|||
|
|
|
|||
|
|
### 6.5 密钥轮换
|
|||
|
|
|
|||
|
|
**SECRET_KEY 轮换**:改动会令所有已签发 JWT 失效(全员需重新登录),在维护窗口操作:
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
# 1. 备份当前 .env → 2. 生成新密钥写入 docker/.env → 3. 重启 backend → 4. 验证登录
|
|||
|
|
openssl rand -hex 32
|
|||
|
|
docker compose --env-file .env up -d --no-deps backend
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**REDIS_PASSWORD 轮换**:先改 `docker/.env` 重启 redis,再改 backend 注入(compose 已自动传递),最后重启 backend。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 7. 故障排查
|
|||
|
|
|
|||
|
|
| 症状 | 原因 | 处理 |
|
|||
|
|
|------|------|------|
|
|||
|
|
| backend 启动即退出,日志提示 SECRET_KEY 配置不安全 | `.env` 未设置/长度不足/命中开发默认值 | 生成 ≥32 位随机密钥,写 `docker/.env` 后重建启动 |
|
|||
|
|
| 日志提示 PROD_CORS_ORIGINS 必须配置 | `.env.prod` 未填域名白名单 | 填具体域名(逗号分隔),勿用 `*` |
|
|||
|
|
| backend 连不上数据库 | 连接参数与 postgres 容器不一致(`DATABASE_USER`/`PASSWORD`/`NAME`),或容器未 healthy | `docker compose logs postgres` 看初始化是否成功;核对 `docker/.env` 的 `DATABASE_*` |
|
|||
|
|
| 能登录但请求 403 / 跨域失败 | CORS 白名单没包含当前域名;或 Host 头不在 `ALLOWED_HOSTS` | 核对 `PROD_CORS_ORIGINS`、`ALLOWED_HOSTS` |
|
|||
|
|
| 登录提示"账号已临时锁定" | 连续失败 5 次触发锁定(15 分钟) | 正常防护;等 TTL 或 `redis-cli DEL login:lock:*`(生产禁止清库) |
|
|||
|
|
| 不知道初始密码 | 生产首次初始化已随机化种子密码 | `docker compose exec backend cat /home/logs/prod_initial_passwords.txt`(仅首次初始化生成,若已删除需走数据库重置密码) |
|
|||
|
|
| `/docs` 404 | 生产已关闭文档 | 符合预期;如需排障临时 `DEBUG=true` 后恢复 |
|
|||
|
|
| 日志出现 `unknown command HELLO` | 连到了不支持 RESP3 的旧 Redis | 生产用 `redis:7` 无此问题;连接已固定 `protocol=2` 兜底 |
|
|||
|
|
| 中文内容乱码 | 数据库/迁移窗口编码问题 | 用二进制 dump(`-F c`)导入;后端连接串为 UTF-8,无需额外设置 |
|
|||
|
|
| 上传失败/图片 404 | 上传目录权限 | `docker compose exec backend ls /home/static/upload`,检查卷或 `chown` |
|
|||
|
|
| 公网访问 https 打不开 | 防火墙/安全组未放行 80/443,或证书未配置 | 核对安全组、`docker/nginx/ssl/` 证书、nginx `server_name` |
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 8. 应急预案与回滚
|
|||
|
|
|
|||
|
|
### 8.1 回滚镜像
|
|||
|
|
|
|||
|
|
镜像带标签 `backend:${BACKEND_IMAGE_TAG:-3.0.0}`。上一版本镜像仍在本地时:
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
# 用旧标签启动(先备份当前 .env 与数据库)
|
|||
|
|
BACKEND_IMAGE_TAG=<上个版本号> docker compose --env-file .env up -d --no-deps backend
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 8.2 数据恢复
|
|||
|
|
|
|||
|
|
按 §6.2 备份恢复。注意:恢复会**覆盖当前数据**,恢复前先导出线上现状存档。
|
|||
|
|
|
|||
|
|
### 8.3 紧急下线
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
cd docker && docker compose --env-file .env stop # 服务停、数据卷保留
|
|||
|
|
# 或直接封防火墙 80/443(保留进程,便于排查)
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 9. 常用命令速查
|
|||
|
|
|
|||
|
|
| 操作 | 命令 |
|
|||
|
|
|------|------|
|
|||
|
|
| 查看状态 | `cd docker && docker compose --env-file .env ps` |
|
|||
|
|
| 看后端日志 | `docker compose --env-file .env logs -f backend` |
|
|||
|
|
| 进后端容器 | `docker compose --env-file .env exec backend sh` |
|
|||
|
|
| 数据库 psql | `docker compose --env-file .env exec postgres psql -U dpb -d dpb` |
|
|||
|
|
| Redis 客户端 | `docker compose --env-file .env exec redis redis-cli -a "$REDIS_PASSWORD" ping` |
|
|||
|
|
| 生产健康检查 | `curl -s https://域名/api/v1/common/health/check` |
|
|||
|
|
| 生成新密钥 | `openssl rand -hex 32` |
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
*维护:本手册随配置变更更新;涉及安全项的修改请同步核对 §5 清单。*
|