Switch production deployment from Docker to PM2 on Ubuntu.

Add Express gateway, ecosystem config, and one-click install with native PostgreSQL, Node, and Python venv on port 23566.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
dekun
2026-06-28 11:52:20 +08:00
parent e329d3398a
commit e797d188ee
20 changed files with 1578 additions and 714 deletions
+70 -219
View File
@@ -1,235 +1,126 @@
# Ubuntu 部署文档
# Ubuntu PM2 部署文档
> **中学成绩档案系统**Secondary School Grade Archive
> 版权所有 © 马建军 · 微信 **dekun03** · 手机 **18364911125**
> 代码仓库:[https://git.bz121.com/dekun/secondary-school-grade-archive.git](https://git.bz121.com/dekun/secondary-school-grade-archive.git)
> **中学成绩档案系统** · 版权所有 © 马建军 · 微信 **dekun03** · 手机 **18364911125**
> 仓库:[https://git.bz121.com/dekun/secondary-school-grade-archive.git](https://git.bz121.com/dekun/secondary-school-grade-archive.git)
---
## 1. 部署概述
## 1. 部署方式
| 项目 | 说明 |
|------|------|
| 目标系统 | Ubuntu 20.04 / 22.04 / 24.04(推荐 22.04+ |
| 运行用户 | **root**(一键脚本要求) |
| 安装目录 | **`/opt/secondary-school-grade-archive`** |
| 部署方式 | Docker Compose |
| 对外端口 | **`23566`**HTTP,可在 `.env` 修改 `WEB_PORT` |
| 反向代理 | **不包含在本项目中**需用户自行配置 Nginx/Caddy 等 |
| 方式 | **PM2**(非 Docker |
| 系统 | Ubuntu 20.04 / 22.04 / 24.04 |
| 用户 | **root** |
| 目录 | `/opt/secondary-school-grade-archive` |
| 端口 | **23566**Web + API 统一入口 |
| 反向代理 | **不包含**自行配置 |
### 1.1 架构说明
### 架构
```
浏览器 ──► :23566 (Nginx/Web) ──► API (内部) ──► PostgreSQL (内部)
└──► Ollama (宿主机,可选)
└── uploads/ (宿主机挂载)
浏览器 :23566 (PM2: grade-web, Express 静态 + /api 反代)
└──→ 127.0.0.1:8000 (PM2: grade-api, Uvicorn)
└──→ PostgreSQL (本机)
└── uploads/
└──→ Ollama (本机可选, :11434)
```
- **Web**:Nginx 提供前端静态文件,并将 `/api` 反向代理到后端容器
- **API**FastAPI,不直接暴露端口到宿主机
- **PostgreSQL**:仅 Docker 内网访问,不映射宿主机端口
- **Ollama**:可选,运行在宿主机,容器通过 `host.docker.internal` 访问
PM2 进程:
| 名称 | 说明 |
|------|------|
| `grade-api` | FastAPI / Uvicorn |
| `grade-web` | 前端静态资源 + `/api` 反向代理 |
---
## 2. 环境要求
### 2.1 硬件(建议
| 资源 | 最低 | 推荐 |
|------|------|------|
| CPU | 2 核 | 4 核+ |
| 内存 | 2 GB | 4 GB+(启用 OCR 建议 8 GB |
| 磁盘 | 10 GB | 20 GB+ |
### 2.2 软件
- Ubuntu Server64 位)
- 可访问互联网(拉取 Docker 镜像与 Git 仓库)
- 防火墙放行 **23566/TCP**(若需外网访问)
### 2.3 端口
| 端口 | 用途 | 是否必须对外开放 |
|------|------|------------------|
| **23566** | Web 前端 + API(经 Nginx 统一入口) | 是 |
| 11434 | Ollama(宿主机,错题 AI 解法) | 仅本机,可不对外 |
| 5432 | PostgreSQL | **否**(已关闭对外映射) |
- CPU 2 核+,内存 4 GB+OCR 建议 8 GB
- 磁盘 15 GB+
- 可访问 Git 仓库与 npm / PyPI
---
## 3. 一键部署(推荐)
**root** 登录 Ubuntu 服务器后执行:
## 3. 一键部署
```bash
# 方式 A:克隆后执行(仓库已有代码时)
git clone https://git.bz121.com/dekun/secondary-school-grade-archive.git /opt/secondary-school-grade-archive
cd /opt/secondary-school-grade-archive
chmod +x deploy/*.sh
bash deploy/install.sh
```
```bash
# 方式 B:仅下载安装脚本(仓库已推送 install.sh 后)
export WEB_PORT=23566
export INSTALL_DIR=/opt/secondary-school-grade-archive
curl -fsSL https://git.bz121.com/dekun/secondary-school-grade-archive/raw/branch/main/deploy/install.sh -o /tmp/install.sh
chmod +x /tmp/install.sh
bash /tmp/install.sh
```
脚本自动完成:
### 3.1 脚本自动完成的事项
1. 检测 root、Ubuntu、端口 23566
2. 安装 PostgreSQL、Python3、Node.js 20、PM2
3. 克隆/更新代码
4. 生成 `.env`(随机密钥、数据库密码)
5. 创建 PostgreSQL 用户与数据库
6. Python 虚拟环境 + `pip install`
7. 前端 `npm ci && npm run build`
8. `pm2 start` 并设置开机自启
1. 检测是否为 root 用户
2. 检测 Ubuntu/Debian 系操作系统
3. 检测内存、磁盘(不足时警告)
4. 检测 **23566** 端口是否占用
5. 安装 `git``curl``openssl` 等基础工具
6. 若未安装 Docker,自动安装 **Docker CE + Compose 插件**
7. 克隆/更新代码到 `/opt/secondary-school-grade-archive`
8. 自动生成 `.env`(随机 `SECRET_KEY`、数据库密码)
9. `docker compose up -d --build` 构建并启动
10. 等待 API 健康检查通过后输出访问地址
### 3.2 部署成功后的访问
```
http://<服务器IP>:23566
```
首次使用请在页面 **注册** 账号,然后登录添加学生。
部署成功后访问:**`http://<服务器IP>:23566`**
---
## 4. 环境变量(`.env`
部署后配置文件位于:
| 变量 | 默认 | 说明 |
|------|------|------|
| `WEB_PORT` | 23566 | 对外 Web 端口 |
| `API_PORT` | 8000 | 内部 API 端口 |
| `DATABASE_URL` | 自动生成 | PostgreSQL 连接 |
| `SECRET_KEY` | 自动生成 | JWT 密钥 |
| `UPLOAD_DIR` | `.../uploads` | 错题图片目录 |
| `OLLAMA_BASE_URL` | `http://127.0.0.1:11434` | 本地 Ollama |
```
/opt/secondary-school-grade-archive/.env
```
| 变量 | 默认值 | 说明 |
|------|--------|------|
| `WEB_PORT` | `23566` | Web 对外端口 |
| `SECRET_KEY` | 自动生成 | JWT 密钥,生产环境请勿泄露 |
| `POSTGRES_PASSWORD` | 自动生成 | 数据库密码 |
| `CORS_ORIGINS` | 含服务器 IP | 前端跨域白名单 |
| `OLLAMA_BASE_URL` | `http://host.docker.internal:11434` | Ollama 地址 |
| `OLLAMA_MODEL` | `qwen2.5:7b` | 模型名称 |
| `FLUCTUATION_THRESHOLD` | `0.08` | 成绩波动高亮阈值(8% |
修改 `.env` 后重启:
修改后重启:
```bash
cd /opt/secondary-school-grade-archive
docker compose --env-file .env up -d
```
修改 `WEB_PORT` 后需重新创建容器:
```bash
docker compose --env-file .env up -d --force-recreate web
pm2 reload deploy/pm2/ecosystem.config.cjs --update-env
```
---
## 5. 常用运维命令
## 5. 常用命令
```bash
cd /opt/secondary-school-grade-archive
# 查看运行状态
docker compose ps
pm2 status # 进程状态
pm2 logs # 全部日志
pm2 logs grade-api # 后端日志
pm2 logs grade-web # 网关日志
# 查看日志
docker compose logs -f
docker compose logs -f api
docker compose logs -f web
# 停止服务
docker compose down
# 启动服务
docker compose --env-file .env up -d
# 更新版本(拉代码 + 重建)
bash deploy/update.sh
# 数据备份
bash deploy/backup.sh
# 卸载容器(保留数据)
bash deploy/uninstall.sh
# 卸载并删除数据库卷(危险)
REMOVE_VOLUMES=1 bash deploy/uninstall.sh
bash deploy/update.sh # 拉代码 + 重建 + 重启
bash deploy/backup.sh # 备份数据库与 uploads
bash deploy/uninstall.sh # 停止 PM2 服务
```
---
## 6. Ollama 可选配置(错题 AI 解法
错题上传后的「整理题目 / 生成解法」依赖宿主机 Ollama。若不安装,OCR 仍可用,AI 解法需手动填写。
## 6. Ollama可选)
```bash
# 安装 Ollama(参考 https://ollama.com
curl -fsSL https://ollama.com/install.sh | sh
# 拉取模型
ollama pull qwen2.5:7b
# 确认服务运行
curl http://127.0.0.1:11434/api/tags
```
确保 `.env` 中:
```
OLLAMA_BASE_URL=http://host.docker.internal:11434
OLLAMA_MODEL=qwen2.5:7b
```
---
## 7. 反向代理(用户自行配置)
## 7. 反向代理(自行配置)
**本项目不包含 HTTPS、域名、反向代理配置。** 若需通过域名访问或启用 HTTPS,请在宿主机自行配置 Nginx/Caddy/Traefik 等。
### 7.1 原则
- 反向代理将流量转发到 **`http://127.0.0.1:23566`**
- 代理需支持 **WebSocket**(若未来扩展)及 **大文件上传**(错题图片最大 10MB
- 代理 `/api``/` 均应转发到同一 upstream(本项目 Nginx 已统一处理)
### 7.2 Nginx 示例(仅供参考,不包含在项目中)
```nginx
server {
listen 443 ssl http2;
server_name grade.example.com;
ssl_certificate /path/to/fullchain.pem;
ssl_certificate_key /path/to/privkey.pem;
client_max_body_size 10M;
location / {
proxy_pass http://127.0.0.1:23566;
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;
}
}
```
使用 HTTPS 反向代理后,请同步修改 `.env` 中的 `CORS_ORIGINS`,加入 `https://grade.example.com`
将域名/HTTPS 流量转发到 **`http://127.0.0.1:23566`** 即可。
使用 HTTPS 后请更新 `.env``CORS_ORIGINS`
---
## 8. 防火墙示例(UFW
## 8. 防火墙
```bash
ufw allow 22/tcp
@@ -243,62 +134,22 @@ ufw enable
| 现象 | 处理 |
|------|------|
| 无法访问 23566 | `docker compose ps` 确认 web 运行;`ufw status` 检查防火墙 |
| 注册/登录 502 | `docker compose logs api` 查看后端;确认 db 健康 |
| OCR 很慢/失败 | 首次运行需下载 PaddleOCR 模型;查看 api 日志 |
| AI 解法失败 | 确认宿主机 Ollama 运行;`curl host.docker.internal:11434` 从 api 容器内测试 |
| 端口被占用 | 修改 `.env``WEB_PORT` 或释放占用进程 |
| 无法访问 | `pm2 status` · `ss -tlnp \| grep 23566` |
| 502 / API 错误 | `pm2 logs grade-api` |
| 数据库连接失败 | `systemctl status postgresql` · 检查 `.env``DATABASE_URL` |
| 前端空白 | 确认 `frontend/dist` 存在 · `pm2 logs grade-web` |
进入 API 容器调试:
---
## 10. 自定义参数
```bash
docker compose exec api bash
WEB_PORT=23566 INSTALL_DIR=/opt/secondary-school-grade-archive bash deploy/install.sh
```
---
## 10. 数据备份与恢复
## 11. 版权
### 备份
```bash
bash /opt/secondary-school-grade-archive/deploy/backup.sh
```
生成文件位于 `backups/`
- `db_YYYYMMDD_HHMMSS.sql` — 数据库
- `uploads_YYYYMMDD_HHMMSS.tar.gz` — 错题图片
### 恢复数据库(示例)
```bash
cd /opt/secondary-school-grade-archive
docker compose exec -T db psql -U postgres student_archive < backups/db_XXXXXX.sql
```
---
## 11. 版权与授权
本软件著作权归 **马建军** 所有。部署和使用须遵守 [LICENSE](../LICENSE) 与 [COPYRIGHT.md](../COPYRIGHT.md)。
- 微信:**dekun03**
- 手机:**18364911125**
未经授权不得用于商业分发或去除版权信息。
---
## 12. 自定义安装参数
```bash
# 自定义端口
WEB_PORT=23566 bash deploy/install.sh
# 自定义目录
INSTALL_DIR=/opt/my-grade-app bash deploy/install.sh
# 指定分支
BRANCH=main bash deploy/install.sh
```
见 [LICENSE](../LICENSE) · [COPYRIGHT.md](../COPYRIGHT.md)
技术支持:微信 **dekun03** · 手机 **18364911125**
+1 -1
View File
@@ -16,7 +16,7 @@
- 错题库:拍照上传 → OCR 识别 → AI 生成解法(可编辑)
- 成绩 CSV 导出
部署方式见 [DEPLOY.md](./DEPLOY.md)。
部署方式见 [DEPLOY.md](./DEPLOY.md)PM2,端口 23566
---