feat(ops): 环境变量化配置 + 健康检查 + 启动脚本 + 部署/安全文档
主要变更: config - 引入 python-dotenv,从 .env 加载 SECRET_KEY / MAIL_* / SQLALCHEMY_DATABASE_URI - 拆分 BaseConfig / DevConfig / ProConfig,PEAR_ENV 控制切换 - ProConfig 在 init_app() 校验 SECRET_KEY,禁止使用默认值 ops - 新增 /healthz 端点:DB 探活 + 环境名 + 时间戳,失败返回 503 - 新增 start.bat (Windows) / Makefile (跨平台) 一键启动 / 初始化 - 新增 .env.example 模板;.gitignore 排除 .env / logs / vscode 等 - 新增 docs/DEPLOY.md(部署指南)和 docs/SECURITY.md(安全清单) - app.py 不再硬编码 debug=False,交给配置类决定 本提交不包含上一次会话的其它工作树修改(模板/导航相关),后续单独 PR。
This commit is contained in:
+164
@@ -0,0 +1,164 @@
|
||||
# Pear Admin Flask - 部署指南
|
||||
|
||||
本文档面向把本项目部署到生产环境的运维 / 二次开发者。
|
||||
请结合根目录的 `README.md` 与 `docs/SECURITY.md` 一起阅读。
|
||||
|
||||
## 0. 环境要求
|
||||
|
||||
| 项目 | 版本 |
|
||||
| --- | --- |
|
||||
| Python | 3.8(推荐 3.11) |
|
||||
| SQLite | 3.x(仅开发用) |
|
||||
| MySQL | 5.7+ / 8.0(生产推荐) |
|
||||
| 操作系统 | Windows / Linux 均可 |
|
||||
|
||||
## 1. 克隆代码
|
||||
|
||||
```bash
|
||||
git clone https://gitea.bwhome.top/bwadmin/pear-admin-flask.git
|
||||
cd pear-admin-flask
|
||||
```
|
||||
|
||||
> 如仓库使用自签证书导致 `SEC_E_WRONG_PRINCIPAL` 报错,
|
||||
> 可临时关闭 SSL 校验:`git -c http.sslVerify=false clone <url>`。
|
||||
> 长期建议把根证书导入到系统信任库。
|
||||
|
||||
## 2. 创建虚拟环境 + 安装依赖
|
||||
|
||||
```bash
|
||||
# Linux / macOS
|
||||
python -m venv venv
|
||||
source venv/bin/activate
|
||||
|
||||
# Windows (cmd)
|
||||
python -m venv venv
|
||||
venv\Scripts\activate.bat
|
||||
|
||||
pip install -r requirements.txt
|
||||
```
|
||||
|
||||
## 3. 配置 .env
|
||||
|
||||
复制模板:
|
||||
|
||||
```bash
|
||||
cp .env.example .env # Linux
|
||||
copy .env.example .env # Windows
|
||||
```
|
||||
|
||||
按需修改(**生产模式 SECRET_KEY 必填**,参见下文):
|
||||
|
||||
```dotenv
|
||||
PEAR_ENV=production
|
||||
SECRET_KEY=<用 python -c "import secrets; print(secrets.token_urlsafe(48))" 生成>
|
||||
|
||||
# MySQL 示例
|
||||
SQLALCHEMY_DATABASE_URI=mysql+pymysql://user:pass@127.0.0.1:3306/pear?charset=utf8mb4
|
||||
|
||||
# 邮件(可选)
|
||||
MAIL_SERVER=smtp.qq.com
|
||||
MAIL_USE_SSL=true
|
||||
MAIL_PORT=465
|
||||
MAIL_USERNAME=your_account@qq.com
|
||||
MAIL_PASSWORD=your_authorization_code_here
|
||||
```
|
||||
|
||||
⚠️ `.env` 文件已在 `.gitignore` 中,**不会**被提交到 git。
|
||||
|
||||
## 4. 数据库初始化
|
||||
|
||||
```bash
|
||||
# 1) 生成迁移脚本
|
||||
flask db migrate
|
||||
# 2) 升级到当前 head
|
||||
flask db upgrade
|
||||
# 3) 导入 admin 基础数据(用户 / 角色 / 菜单)
|
||||
flask admin init
|
||||
```
|
||||
|
||||
MySQL 用户需提前建库:
|
||||
|
||||
```sql
|
||||
CREATE DATABASE pear DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
CREATE USER 'pear'@'%' IDENTIFIED BY 'your_strong_password';
|
||||
GRANT ALL PRIVILEGES ON pear.* TO 'pear'@'%';
|
||||
FLUSH PRIVILEGES;
|
||||
```
|
||||
|
||||
## 5. 启动
|
||||
|
||||
### 5.1 开发
|
||||
|
||||
```bash
|
||||
# Linux
|
||||
make run
|
||||
# Windows
|
||||
start.bat
|
||||
```
|
||||
|
||||
### 5.2 生产
|
||||
|
||||
推荐用 `gunicorn`(`pip install gunicorn`),或反向代理到 `waitress`:
|
||||
|
||||
```bash
|
||||
# Linux
|
||||
PEAR_ENV=production gunicorn -w 4 -b 0.0.0.0:5000 app:app
|
||||
|
||||
# Windows
|
||||
pip install waitress
|
||||
PEAR_ENV=production waitress-serve --port=5000 app:app
|
||||
```
|
||||
|
||||
### 5.3 健康检查
|
||||
|
||||
服务起来后:
|
||||
|
||||
```bash
|
||||
curl http://127.0.0.1:5000/healthz
|
||||
# 200 OK → {"status":"ok","db_ok":true,...}
|
||||
# 503 → {"status":"degraded","db_ok":false,...}
|
||||
```
|
||||
|
||||
## 6. 反向代理(Nginx 示例)
|
||||
|
||||
```nginx
|
||||
server {
|
||||
listen 80;
|
||||
server_name pear.example.com;
|
||||
|
||||
location / {
|
||||
proxy_pass http://127.0.0.1:5000;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
client_max_body_size 50m;
|
||||
}
|
||||
|
||||
location = /healthz {
|
||||
proxy_pass http://127.0.0.1:5000/healthz;
|
||||
access_log off;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 7. 升级流程
|
||||
|
||||
```bash
|
||||
git pull
|
||||
source venv/bin/activate
|
||||
pip install -r requirements.txt
|
||||
flask db migrate
|
||||
flask db upgrade
|
||||
# 重启进程
|
||||
systemctl restart pear-admin-flask
|
||||
```
|
||||
|
||||
## 8. 常见问题
|
||||
|
||||
| 现象 | 处理 |
|
||||
| --- | --- |
|
||||
| `[ProConfig] 生产环境必须通过环境变量 SECRET_KEY 传入强随机密钥` | 在 `.env` 或系统环境变量中设置 `SECRET_KEY`。 |
|
||||
| `SEC_E_WRONG_PRINCIPAL` 克隆失败 | `git -c http.sslVerify=false clone ...` 或导入根证书。 |
|
||||
| 启动后 `/` 跳转到登录页 | 正常。后台默认账号 `admin` / 密码 `123456`,**请立即修改**。 |
|
||||
| 数据库表缺失 | `flask db upgrade` 后 `flask admin init`。 |
|
||||
@@ -0,0 +1,89 @@
|
||||
# Pear Admin Flask - 安全指南
|
||||
|
||||
## 1. 密钥(SECRET_KEY)
|
||||
|
||||
`SECRET_KEY` 用于 Flask `session` 签名、`csrf_token`、Flask-Session
|
||||
等。**一旦泄露,攻击者可伪造任意管理员会话。**
|
||||
|
||||
要求:
|
||||
- 长度 ≥ 32 字节(推荐 48+);
|
||||
- 高熵随机(`secrets.token_urlsafe(48)` / `openssl rand -base64 48`);
|
||||
- **禁止**使用默认值 `pear-system-flask`;
|
||||
- **禁止**把 `.env` / 含密钥的部署脚本提交到 git。
|
||||
|
||||
开发模式自动生成的密钥仅供本地调试,**重启即失效**。
|
||||
|
||||
## 2. 凭据(Mail / DB)
|
||||
|
||||
所有凭据通过 `.env` 注入,代码里只放占位符。强烈建议:
|
||||
- 生产数据库单独建用户,**只授必要的库权限**;
|
||||
- Mail 使用**授权码**而非登录密码(QQ / 163 / Gmail 均提供);
|
||||
- 定期轮换凭据,并在变更后重启服务。
|
||||
|
||||
## 3. 默认管理员账号
|
||||
|
||||
`flask admin init` 会写入默认账号 `admin / 123456`,**首次登录后必须立即修改密码**。
|
||||
|
||||
可执行:
|
||||
|
||||
```bash
|
||||
# 1) 登录后台 → 用户管理 → 修改 admin 密码;
|
||||
# 2) 或直接 SQL:
|
||||
sqlite3 pear.db "UPDATE rbac_user SET password='<pbkdf2:sha256:...>' WHERE username='admin';"
|
||||
```
|
||||
|
||||
## 4. Cookie / Session
|
||||
|
||||
`SESSION_COOKIE_HTTPONLY = True`(默认)与 `SESSION_COOKIE_SAMESITE = 'Lax'`
|
||||
已经在配置中体现。生产部署在 HTTPS 下请额外设置:
|
||||
|
||||
```python
|
||||
SESSION_COOKIE_SECURE = True
|
||||
```
|
||||
|
||||
> 若启用 Flask-Session(filesystem / redis),请把 `flask_session/`
|
||||
> 目录排除在 Web 静态目录之外,并定期清理。
|
||||
|
||||
## 5. CSRF
|
||||
|
||||
本项目基于 `flask_wtf`,所有写操作均有 CSRF 校验。
|
||||
前端表单务必带上 `{{ csrf_token() }}` 或请求头 `X-CSRFToken`。
|
||||
|
||||
## 6. 上传文件
|
||||
|
||||
`UPLOADED_PHOTOS_DEST = static/upload`,后缀白名单已限制为图片。
|
||||
但**用户可上传 SVG / 伪装为图片的 JS** 等——建议:
|
||||
|
||||
- 上传目录关闭脚本执行(Nginx: `location ^~ /static/upload/ { ... }`);
|
||||
- 后端校验真实文件类型(`python-magic`),而非仅看后缀。
|
||||
|
||||
## 7. 限流
|
||||
|
||||
`Flask-Limiter` 已挂载(`applications/extensions/init_limit.py`)。
|
||||
生产模式请按业务需求调整默认速率,避免误伤。
|
||||
|
||||
## 8. 日志
|
||||
|
||||
`LOG_LEVEL` 控制根 logger 输出等级。生产推荐 `WARN` / `ERROR`。
|
||||
**不要把 `SECRET_KEY`、用户密码、token 写入日志。**
|
||||
|
||||
## 9. 依赖漏洞
|
||||
|
||||
建议在 CI 中加入 `pip-audit`:
|
||||
|
||||
```bash
|
||||
pip install pip-audit
|
||||
pip-audit -r requirements.txt
|
||||
```
|
||||
|
||||
## 10. 上线前 Checklist
|
||||
|
||||
- [ ] `PEAR_ENV=production`
|
||||
- [ ] `SECRET_KEY` 已替换为强随机值
|
||||
- [ ] 数据库用户仅授必要权限
|
||||
- [ ] 默认 admin 密码已修改
|
||||
- [ ] HTTPS 已上线(`SESSION_COOKIE_SECURE` 同步开启)
|
||||
- [ ] `flask_session/` 目录已加入备份策略
|
||||
- [ ] `static/upload/` 已禁用脚本执行
|
||||
- [ ] `pip-audit` 跑过
|
||||
- [ ] `/healthz` 已接入负载均衡 / 容器探活
|
||||
Reference in New Issue
Block a user