# Pear Admin Flask - 个人 NAS 部署指南 适用:内网 / 家庭 / 小团队(≤ 50 并发用户,无 K8s 需求)。 --- ## 1. 前置检查 NAS 上需安装: | 软件 | 最低版本 | 验证命令 | |---|---|---| | Docker Engine | 20.10+ | `docker --version` | | Docker Compose | v2.x | `docker compose version` | > 如果 NAS 是群晖 / 威联通,请在套件中心安装 **Container Manager** 或自行 SSH 安装 docker。 --- ## 2. 准备 .env ```bash cd /volume1/docker/pear-admin-flask cp .env.example .env # 编辑 .env:SECRET_KEY 必须改成强随机字符串 python -c "import secrets; print(secrets.token_urlsafe(48))" # 把输出贴到 .env 的 SECRET_KEY= ``` `.env` **绝不能提交到 git**(已在 `.gitignore` 中)。 --- ## 3. 首次构建 + 启动 ```bash # 进入项目目录 cd /volume1/docker/pear-admin-flask # 改成你自己的路径 # 如果你之前用过 pear-admin-flask,要把现有库搬过来: mkdir -p data cp pear.db data/pear.db # 把根目录的库搬到 data/ 下(容器会把整个 ./data 挂进 /app/data) # 构建镜像(首次约 3-5 分钟) docker compose -f deploy/nas/docker-compose.yaml build # 后台启动 docker compose -f deploy/nas/docker-compose.yaml up -d # 查看启动日志(应看到 "Listening at: http://0.0.0.0:5000") docker compose -f deploy/nas/docker-compose.yaml logs -f ``` 启动成功后访问:`http://NAS_IP:5000` 默认账号 `admin` / `123456`(首次登录后**强烈建议改密码**)。 --- ## 4. 健康检查 ```bash # 进程是否还活着(DB OK 返回 200;DB 不可达返回 503) curl -i http://NAS_IP:5000/healthz # 200 OK: {"status":"ok","db_ok":true,"env":"production","system":"Pear Admin","timestamp":"..."} # 容器视角的健康状态(Docker 30s 探一次) docker inspect --format='{{.State.Health.Status}}' pear-admin-nas # healthy / unhealthy / starting ``` --- ## 5. 端口与局域网访问 `docker-compose.yaml` 中默认 `5000:5000`,局域网内任意设备 `http://NAS_IP:5000` 都能访问。 如要改端口(如 NAS 上 5000 被占用): ```yaml ports: - "8080:5000" # 宿主 8080 → 容器 5000 ``` 手机访问:`http://NAS_IP:8080`(确保 NAS 防火墙放行)。 --- ## 6. 数据持久化 整个数据库 / 会话 / 备份 / 上传,**统一收进宿主 `./data` 目录**,容器内路径 `/app/data`。 ``` ./data # docker-compose 唯一绑定挂载 ├── pear.db # SQLite 主库(WAL 模式) ├── pear.db-wal # WAL 文件(不要删) ├── pear.db-shm # 共享内存文件(不要删) ├── backup/ # 在线热备(自动保留最近 14 天) │ └── pear-20260906_020000.db.gz ├── flask_session/ # Flask-Session 文件 ├── logs/ # gunicorn / Flask 日志 │ ├── access.log │ └── error.log └── upload/ # 上传图片 ``` 在 NAS File Station 里直接看得到、可以直接 tar 走 —— 这是从"看不见的虚拟卷"改成"看得见的文件夹"的核心收益。 ### 备份(在线热备) 容器镜像里带了 `sqlite3`,`deploy/nas/backup.sh` 走 `sqlite3 .backup`(含 WAL 一致性,比 `cp` 安全): ```bash docker exec pear-admin-nas /app/deploy/nas/backup.sh # 输出:[backup] done. latest = /app/data/backup/pear-20260906_020000.db.gz ``` ### 自动备份(推荐,群晖 / 威联通 / Linux 都适用) 群晖 DSM:「控制面板 → 任务计划表 → 新增 → 计划的任务 → 用户定义的脚本」: ``` 每天 02:00 跑: docker exec pear-admin-nas /app/deploy/nas/backup.sh ``` 或者宿主 crontab: ```bash 0 2 * * * docker exec pear-admin-nas /app/deploy/nas/backup.sh ``` 默认保留 14 天(`BACKUP_KEEP=14` 可改)。 ### 恢复 ```bash # 停容器 docker compose -f deploy/nas/docker-compose.yaml down # 把备份解开(注意:必须先停容器才能覆盖 pear.db,否则 SQLite 还在持有文件锁) gunzip -c data/backup/pear-20260906_020000.db.gz > data/pear.db # 顺带把 -wal / -shm 也清掉(WAL 会自动重建) rm -f data/pear.db-wal data/pear.db-shm # 起回去 docker compose -f deploy/nas/docker-compose.yaml up -d ``` 整库迁移到新机器: ```bash # 旧机器:tar 整个 data 目录(不算大,库 100MB 级别) cd /volume1/docker/pear-admin-flask tar czf pear-data-$(date +%F).tgz data/ # 新机器:解开 → 启动即用 tar xzf pear-data-2026-09-06.tgz -C /volume1/docker/pear-admin-flask/ docker compose -f deploy/nas/docker-compose.yaml up -d ``` --- ## 7. 升级流程 ```bash # 1. 拉取最新代码 cd /volume1/docker/pear-admin-flask git pull # 2. 重新构建镜像 docker compose -f deploy/nas/docker-compose.yaml build # 3. 重启容器(migrations 自动跑) docker compose -f deploy/nas/docker-compose.yaml up -d # 4. 验证 curl -i http://NAS_IP:5000/healthz ``` 数据库迁移由 `start.sh` 中的 `flask db upgrade` 自动执行(幂等;含 `site_nav_click` 等插件表的迁移)。 --- ## 8. 常见问题 ### Q1:容器启动后立刻退出 ```bash docker compose -f deploy/nas/docker-compose.yaml logs --tail=50 ``` 最常见原因: - `SECRET_KEY` 还是占位符 `PLEASE_REPLACE_WITH_RANDOM_STRING` → ProConfig 会拒绝启动 - 端口被占用 → 修改 `ports` 段 - `data/` 目录存在但权限不对(容器内 uid 1001 没写权限)→ `chown -R 1001:1001 data/` ### Q2:访问首页 502 / 拒绝连接 ```bash # 确认容器在跑 docker ps | grep pear-admin-nas # 看健康状态 docker inspect --format='{{.State.Health.Status}}' pear-admin-nas ``` ### Q3:忘记 admin 密码 直接重置(删除整个 `data/pear.db`,再启动让 `flask admin init` 重新生成默认账号): ```bash docker compose -f deploy/nas/docker-compose.yaml down rm -f data/pear.db data/pear.db-wal data/pear.db-shm docker compose -f deploy/nas/docker-compose.yaml up -d ``` ⚠️ **此操作会清空所有数据**,务必先 `docker exec … backup.sh` 一份。 ### Q4:日志占满磁盘 ```bash # 看 data/logs 实际大小 du -sh data/logs # 清空(保留文件) : > data/logs/access.log : > data/logs/error.log ``` ### Q5:想要外网访问 需要做两件事: 1. NAS 上做端口映射(5000 → 公网 IP) + DDNS 2. **必须**在前面套一层 Nginx/Caddy 加 HTTPS(避免密码明文) 可参考 `deploy/nas/README.md`(如果后续加入 nginx 反代方案)。 --- ## 9. 性能调优 NAS 通常内存有限(4-8 GB)。如遇卡顿: ```yaml # docker-compose.yaml 中调小资源限制 deploy: resources: limits: memory: 768M # 从 1024M 降到 768M ``` 或减少 worker: ```env # .env 里 GUNICORN_WORKERS=1 GUNICORN_THREADS=16 # SQLite + WAL 单进程跑,线程数给够 ``` **为什么默认 workers=1 threads=8 而不是 2×4**:SQLite 写串行;多进程提交事务时仍可能撞锁,gunicorn worker 越多事故面越大。单进程写最稳,线程吃满网络并发。你的场景下 8 线程绰绰有余,要更高把线程拉到 16 就行。