mirror of
https://github.com/fastapiadmin/FastapiAdmin.git
synced 2026-10-14 13:06:51 +00:00
部署方式:服务器不再接收源码、不执行构建,改为本地构建成品后交付
- deploy-artifacts.sh:构建→备份→校验→原子替换,支持回滚、镜像/备份轮转、
mysql 与 postgres 双变体镜像;后端以 docker save|ssh|docker load 交付
- 依赖分组:requirements/{base,storage}.txt + db/{mysql,postgres,sqlite}.txt,
镜像按所选数据库只装对应驱动(MySQL 变体 565MB → 521MB)
编排与运行时加固
- compose:MySQL/Redis/backend 端口仅绑 127.0.0.1;密钥(SECRET_KEY、
DATA_ENCRYPTION_KEY、DATA_ENCRYPTION_OLD_KEYS)、PROD_CORS_ORIGINS、
FORWARDED_ALLOW_IPS、DEMO_ENABLE 一律由 docker/.env 注入
- Dockerfile:对齐依赖分组、以非 root(uid=1000) 运行;.dockerignore 排除全部真实 .env.*
- nginx:静态资源长缓存、隐藏文件拒绝、接口文档仅内网可访问、放行 ACME http-01 校验路径
工程基建
- 新增 CI:backend(uv sync + ruff + pytest)与 frontend(web type-check+vitest、app type-check)
- 新增 DEPLOYMENT.md 运维手册(部署/回滚/密钥轮换/每日巡检/证书/排查)
120 lines
5.9 KiB
Markdown
120 lines
5.9 KiB
Markdown
# FastapiAdmin 部署运维手册
|
||
|
||
> 适用环境:阿里云单机 Docker 部署(`service.fastapiadmin.com`)
|
||
> 最近更新:2026-10-04(本轮密钥轮换与加固之后)
|
||
|
||
---
|
||
|
||
## 1. 架构与目录
|
||
|
||
| 组件 | 说明 | 对外端口 |
|
||
| --- | --- | --- |
|
||
| nginx | TLS 终止、静态站点、反向代理 `/api/v1` | 80 / 443 |
|
||
| backend | FastAPI(uvicorn,1 worker,非 root 运行 uid=1000) | 仅 127.0.0.1:8001 |
|
||
| mysql | MySQL 8.0,数据卷 `mysql_data` | 仅 127.0.0.1:3306 |
|
||
| redis | Redis 7(会话/缓存/限流) | 仅 127.0.0.1:6379 |
|
||
|
||
服务器布局(`/home/FastapiAdmin`):
|
||
|
||
```
|
||
docker/ # 唯一部署目录,不含业务源码
|
||
├── docker-compose.yaml # 服务编排(端口仅 127.0.0.1,密钥由 .env 注入)
|
||
├── docker-compose.override.yaml # nginx 版本固定 + 缓存配置挂载 + ACME 目录
|
||
├── .env # 真实凭据(600,不入库)
|
||
├── .env.example # 占位模板(入库)
|
||
├── backend/Dockerfile # 源码构建路径(正式部署不用它)
|
||
├── nginx/
|
||
│ ├── nginx.conf # 站点配置(含文档封堵、隐藏文件拒绝、ACME 放行)
|
||
│ ├── cache-headers.inc # 静态资源长缓存片段
|
||
│ ├── acme/ # ACME http-01 校验目录
|
||
│ ├── ssl/ # 证书与私钥(600,不入库)
|
||
│ └── {web,app,docs}/dist # 三端静态成品(由本地构建后上传)
|
||
└── mysql/ redis/ # 初始化 SQL 与 redis.conf
|
||
backups/ # 部署前自动备份(每类保留 5 份)
|
||
```
|
||
|
||
仓库侧:`deploy-artifacts.sh`(本机执行的成品部署脚本)、`backend/requirements/`(依赖分组)、`.github/workflows/`(CI)。
|
||
|
||
---
|
||
|
||
## 2. 日常部署
|
||
|
||
在本机仓库根目录执行(需要本机可免密 SSH 到服务器、且本机 Docker 可用——`colima start`):
|
||
|
||
```bash
|
||
./deploy-artifacts.sh web # 构建并部署 Web 管理后台
|
||
./deploy-artifacts.sh app # 构建并部署移动端 H5
|
||
./deploy-artifacts.sh backend # 本地构建 MySQL 版镜像 → 传输 → 只重建 backend
|
||
./deploy-artifacts.sh all # 三样全发
|
||
./deploy-artifacts.sh verify # 公网四端验证
|
||
./deploy-artifacts.sh backups # 列出服务器备份
|
||
./deploy-artifacts.sh prune # 轮转清理旧备份与旧镜像
|
||
./deploy-artifacts.sh rollback web|app|backend
|
||
```
|
||
|
||
要点:
|
||
|
||
- **服务器不接收源码、不执行构建**:后端以 `docker save → ssh → docker load` 交付镜像,前端以 tar 管道交付成品。
|
||
- 每次部署前自动备份到 `backups/<标签>-<时间戳>`,备份失败即中止,不会带着假备份上线。
|
||
- 只重建变化的容器;MySQL/Redis/Nginx 不受影响。
|
||
- PostgreSQL 版本镜像:`./deploy-artifacts.sh backend-pg`(**只构建与自检,不切换线上**)。切换需人工把 `BACKEND_IMAGE_TAG` 指到该镜像并确保 compose 的数据库配置已改。
|
||
|
||
---
|
||
|
||
## 3. 密钥与口令
|
||
|
||
| 项 | 位置 | 说明 |
|
||
| --- | --- | --- |
|
||
| `SECRET_KEY` | 服务器 `docker/.env` | JWT 签名密钥,64 位 hex,随机生成 |
|
||
| `DATA_ENCRYPTION_KEY` | 服务器 `docker/.env` | 落库敏感数据加密主密钥 |
|
||
| `DATA_ENCRYPTION_OLD_KEYS` | 服务器 `docker/.env` | 轮换前的旧密钥,仅用于解密历史密文 |
|
||
| 种子账号口令 | 服务器 `/root/.fa-seed-passwords`(600) | `super`/`admin`/`user`,登录后请自行修改并删除该文件 |
|
||
|
||
**轮换密钥的正确步骤**(不可跳步,否则历史密文无法解密):
|
||
|
||
1. 把当前 `DATA_ENCRYPTION_KEY`(未设置时取当前 `SECRET_KEY`)追加到 `DATA_ENCRYPTION_OLD_KEYS`;
|
||
2. 生成新值:`openssl rand -hex 32`,写入 `SECRET_KEY` / `DATA_ENCRYPTION_KEY`;
|
||
3. `docker compose up -d --force-recreate backend`;
|
||
4. 验证历史密文仍可解密(例如存储源口令),再删除 `OLD_KEYS` 中不再需要的旧值。
|
||
|
||
> 注意:更换 `SECRET_KEY` 会使已签发的令牌全部失效,用户需重新登录。
|
||
|
||
---
|
||
|
||
## 4. 运行状态与巡检
|
||
|
||
- **每日巡检**:`systemctl list-timers fa-health-check.timer`(每天 08:30,带 5 分钟随机延迟)
|
||
- 巡检内容:4 个容器健康、`/api/v1/monitor/health/check` 与 `/web/`、`/app/` 可用性、证书剩余天数、磁盘、swap、备份与镜像堆积
|
||
- 结果:`/var/log/fa-health.log`;有告警时写入 syslog(`journalctl -t fa-health`)且服务退出码非 0
|
||
- 手动执行:`systemctl start fa-health-check.service && tail -n 30 /var/log/fa-health.log`
|
||
|
||
常用排查命令:
|
||
|
||
```bash
|
||
cd /home/FastapiAdmin/docker
|
||
docker compose ps
|
||
docker logs --tail 100 backend
|
||
docker inspect backend --format '{{.State.Health.Status}}'
|
||
ss -tlnp | grep docker-proxy # 确认对外只有 80/443
|
||
```
|
||
|
||
---
|
||
|
||
## 5. 证书
|
||
|
||
- 当前证书:`docker/nginx/ssl/server.pem`(`CN=service.fastapiadmin.com`),由巡检脚本监控到期天数
|
||
- 续期(重新签发后):替换 `server.pem` 与 `server.key` → `docker exec nginx nginx -s reload`
|
||
- 已放行 ACME http-01 校验路径(`/.well-known/acme-challenge/` → `docker/nginx/acme`),如需切换到 acme.sh 自动续期,把校验文件写入该目录即可,无需再改 nginx 配置
|
||
|
||
---
|
||
|
||
## 6. 已知遗留问题
|
||
|
||
安全与质量债的完整清单见 `AUDIT-REPORT.md` 与各分报告(`backend/audit-*.md`、`frontend/audit-*.md`、`docker/audit-deploy.md`)。当前仍待处理的高优先级项:
|
||
|
||
1. 会话失效机制:停用/删除/改密后旧会话仍有效(最长 7 天)——需应用侧改造;
|
||
2. 数据权限注入不完整:`CRUDBase` 的删除/清空/改状态路径未注入数据权限;
|
||
3. Web i18n 与通知状态枚举:`85/101` 个页面未接入 i18n;通知状态枚举与后端语义冲突;
|
||
4. 测试覆盖:后端仅 2 个用例,夹具掩盖缺陷(见 `backend/audit-testing.md`);
|
||
5. 多租户需求与实现错位(见 `backend/audit-requirements.md`)。
|