EOF Co-authored-by: Cursor <cursoragent@cursor.com>
11 KiB
Ubuntu 零 Node 部署文档
中学成绩档案系统 · 版权所有 © 马建军 · 微信 dekun03 · 手机 18364911125
仓库:https://git.bz121.com/dekun/secondary-school-grade-archive.git
1. 部署方式
| 项目 | 说明 |
|---|---|
| 方式 | systemd + FastAPI 单进程(服务器无需 Node.js / npm) |
| 系统 | Ubuntu 20.04 / 22.04 / 24.04 |
| 用户 | root |
| 目录 | /opt/secondary-school-grade-archive |
| 端口 | 23566(API + 前端静态资源同一端口) |
架构
浏览器 → :23566 (systemd: grade-archive, Uvicorn)
├── /api/* → FastAPI 接口
└── /* → frontend/dist 静态文件
└──→ PostgreSQL (本机)
└──→ uploads/
└──→ Ollama (本机可选, :11434)
为何不在服务器构建前端?
前端 npm ci && npm run build 会占用大量磁盘与内存,且需在服务器安装 Node.js。
因此采用 开发机构建 → 推送 frontend/dist → 服务器只拉取 的方式,服务器仅需 Python + PostgreSQL。
2. 代码修改与发布流程(重要)
每次修改代码后,按改动范围在开发机操作,再推送到远端仓库,最后在服务器执行 update.sh。
服务器需代理时:在
update.sh前设置与 §3 一键部署 相同的export http_proxy=...命令。
流程总览
┌─────────────┐ ┌──────────────────┐ ┌─────────────┐ ┌─────────────────┐
│ 开发机改代码 │ → │ 本地构建(如需) │ → │ git push 远端 │ → │ 服务器 update.sh │
└─────────────┘ └──────────────────┘ └─────────────┘ └─────────────────┘
2.1 仅修改后端(backend/)
不涉及前端页面时,无需 npm run build:
git add backend/
git commit -m "fix: 说明本次改动"
git push
服务器:
bash /opt/secondary-school-grade-archive/deploy/update.sh
update.sh 会:git pull → pip install → systemctl restart grade-archive。
2.2 修改前端(frontend/src 等)或同时改前后端
必须先在开发机构建,并将构建产物 frontend/dist/ 提交到仓库:
# Windows
.\deploy\build-frontend.ps1
# Linux / macOS
bash deploy/build-frontend.sh
上述脚本等价于 cd frontend && npm ci && npm run build,并检查 dist/index.html 是否生成。
然后提交并推送(务必包含 frontend/dist):
git add frontend/ frontend/dist
git commit -m "feat: 说明本次改动"
git push
服务器:
bash /opt/secondary-school-grade-archive/deploy/update.sh
2.3 常见错误
| 现象 | 原因 | 处理 |
|---|---|---|
| 服务器页面没变化 | 只 push 了源码,未 push frontend/dist |
本地 npm run build 后重新提交 dist |
install.sh 报错找不到 dist |
仓库里没有预构建的 dist | 开发机构建并 push 后再部署 |
| API 正常但页面 404 | FRONTEND_DIST 路径不对 |
检查 .env 中 FRONTEND_DIST |
3. 一键部署(新服务器)
若服务器访问 Git / apt / PyPI 需走代理,在 bash deploy/install.sh 之前设置:
export http_proxy=http://192.168.8.246:10810
export https_proxy=http://192.168.8.246:10810
export HTTP_PROXY="$http_proxy"
export HTTPS_PROXY="$https_proxy"
完整安装命令:
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
脚本会读取上述环境变量,并自动配置
apt代理。git pull、pip install同样生效。内网直连时可不设代理。
脚本自动完成:
- 安装 PostgreSQL、Python 依赖
- 检查
frontend/dist/index.html是否存在 - 生成
.env、创建数据库 - 注册并启动 systemd 服务
grade-archive
前提: 仓库中已包含 frontend/dist/(开发机构建后推送)。
部署成功后访问:http://<服务器IP>:23566
默认超级管理员:admin / admin123(登录后请在「系统设置」中修改)
4. 环境变量(.env)
| 变量 | 默认 | 说明 |
|---|---|---|
WEB_PORT |
23566 | 对外端口 |
FRONTEND_DIST |
.../frontend/dist |
前端静态目录(绝对路径) |
DATABASE_URL |
自动生成 | PostgreSQL 连接 |
SECRET_KEY |
自动生成 | JWT 密钥 |
UPLOAD_DIR |
.../uploads |
错题图片目录 |
ADMIN_DEFAULT_USERNAME |
admin | 首次安装默认管理员用户名 |
ADMIN_DEFAULT_PASSWORD |
admin123 | 首次安装默认管理员密码 |
示例见仓库根目录 .env.example。
5. 常用命令
# 服务状态
systemctl status grade-archive
# 实时日志
journalctl -u grade-archive -f
# 拉代码并重启(日常更新;需代理时先 export,见 §3)
export http_proxy=http://192.168.8.246:10810
export https_proxy=http://192.168.8.246:10810
export HTTP_PROXY="$http_proxy"
export HTTPS_PROXY="$https_proxy"
bash /opt/secondary-school-grade-archive/deploy/update.sh
# 备份数据库与 uploads
bash /opt/secondary-school-grade-archive/deploy/backup.sh
5.1 停止与启动服务
仅暂停服务、不卸载时使用:
sudo systemctl stop grade-archive # 停止
sudo systemctl start grade-archive # 启动
sudo systemctl restart grade-archive # 重启
systemctl status grade-archive # 查看状态
若曾安装 OCR Worker:
sudo systemctl stop ocr-worker
sudo systemctl start ocr-worker
sudo systemctl status ocr-worker
journalctl -u ocr-worker -f
一键部署会自动 systemctl enable ocr-worker,重启后 OCR 随系统启动。
停止后浏览器访问 http://<服务器IP>:23566 会无法连接;启动后即可恢复。
5.2 卸载
卸载脚本会停止并禁用 systemd 服务、清理旧版 PM2 进程,以及可选删除安装目录 / 数据库。
# 停止服务并禁用,保留代码、数据库、uploads(可再次 install / update)
sudo bash /opt/secondary-school-grade-archive/deploy/uninstall.sh
# 额外删除安装目录 /opt/secondary-school-grade-archive
sudo bash /opt/secondary-school-grade-archive/deploy/uninstall.sh --purge
# 额外删除 PostgreSQL 库与用户(默认库 student_archive、用户 gradeapp)
sudo bash /opt/secondary-school-grade-archive/deploy/uninstall.sh --purge-db
# 完全清除(目录 + 数据库),便于干净重装
sudo bash /opt/secondary-school-grade-archive/deploy/uninstall.sh --purge --purge-db
说明:
| 选项 | 效果 |
|---|---|
| (无选项) | 停止并删除 grade-archive / ocr-worker 服务单元;保留 /opt/...、数据库、上传文件 |
--purge |
删除安装目录(含代码、.env、uploads) |
--purge-db |
删除 PostgreSQL 数据库与应用用户 |
脚本需 root 执行(sudo bash ...)。交互式终端下会询问确认;取消则退出且不做修改。
卸载后重新部署见 §3 一键部署。若仅停服务未 --purge,可直接:
cd /opt/secondary-school-grade-archive
sudo bash deploy/install.sh
6. 从旧版 PM2 迁移
若之前使用 grade-api + grade-web(PM2 + Express),执行 deploy/update.sh 会:
- 停止并删除 PM2 进程
grade-api、grade-web - 重启 systemd 服务
grade-archive
.env 调整建议:
- 保留
WEB_PORT=23566 - 添加
FRONTEND_DIST=/opt/secondary-school-grade-archive/frontend/dist - 可删除
API_PORT、API_TARGET(已不再使用)
7. 超级管理员
| 功能 | 说明 |
|---|---|
| 默认账号 | admin / admin123(首次安装后请立即修改) |
| 系统设置 | 超级管理员可修改自己的用户名、密码 |
| 注册开关 | 可开启/关闭登录页公开注册 |
| 用户管理 | 注册关闭时,由管理员添加用户并重置密码 |
| 普通用户 | 不能自行修改用户名和密码 |
使用说明见 USAGE.md。
8. 反向代理(用户自行配置)
本项目不包含 Nginx / Caddy 等反向代理配置。若需 HTTPS 或域名访问,请在服务器上自行配置,将流量转发到 127.0.0.1:23566。
9. OCR 报错 libGL.so.1
若错题识别失败并提示 libGL.so.1: cannot open shared object file,说明服务器缺少 OpenGL 运行库(PaddleOCR/OpenCV 需要)。
在服务器执行:
cd /opt/secondary-school-grade-archive
git pull
sudo bash deploy/install-ocr-deps.sh
sudo systemctl restart grade-archive
或执行完整更新(已包含 OCR 依赖检查):
sudo bash deploy/update.sh
10. pip 安装失败(No matching distribution / from versions: none)
若 install.sh / update.sh 在安装 Python 依赖时报:
ERROR: Could not find a version that satisfies the requirement fastapi==0.115.6 (from versions: none)
ERROR: No matching distribution found for fastapi==0.115.6
说明 pip 根本拉不到 PyPI 索引(网络/代理问题),不是版本号写错。
在服务器上排查:
curl -I https://pypi.tuna.tsinghua.edu.cn/simple/fastapi/
curl -I https://mirrors.aliyun.com/pypi/simple/fastapi/
处理方式(任选其一后重新安装):
# 方式 A:走代理后再装(代理地址按实际修改)
export http_proxy=http://192.168.8.246:10810
export https_proxy=http://192.168.8.246:10810
export HTTP_PROXY="$http_proxy"
export HTTPS_PROXY="$https_proxy"
cd /opt/secondary-school-grade-archive
sudo -E bash deploy/install.sh
# 方式 B:换国内镜像
export PIP_MIRROR=https://mirrors.aliyun.com/pypi/simple
cd /opt/secondary-school-grade-archive/backend
source venv/bin/activate
pip install -r requirements.txt -i "$PIP_MIRROR" --trusted-host mirrors.aliyun.com
deactivate
# 依赖装好后继续跑完安装(或再执行 install.sh)
sudo -E bash /opt/secondary-school-grade-archive/deploy/install.sh
当前脚本会自动尝试多个镜像;仍失败时请先保证服务器能访问上述 URL。
11. 更新后无法访问(连接被拒绝)
若浏览器提示 ERR_CONNECTION_REFUSED,通常是 update.sh 停止了旧 PM2,但 systemd 服务未成功启动。
在服务器执行一键修复:
cd /opt/secondary-school-grade-archive
git pull
sudo bash deploy/repair.sh
手动排查:
systemctl status grade-archive
journalctl -u grade-archive -n 50 --no-pager
ss -tlnp | grep 23566
注意:
update.sh/repair.sh必须用 root 运行(sudo bash ...)。
12. 技术支持
微信 dekun03 · 手机 18364911125