Files
sumi.work/DEPLOY.md
T

542 lines
14 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# sumi.work NPM 部署说明
这份文档给 AI/运维执行者使用,用于把当前仓库部署为可运行的 Node.js 服务。项目包含静态首页、软件下载中心、玩家登录下载限制、软件管理后台和上传更新 API。
## 1. 运行环境
要求:
- Node.js 20+,推荐 Node.js 22 LTS 或更高版本
- npm
- 持久化可写目录:推荐 `/var/lib/sumi-work/`
- 对外端口:默认 `3030`,可通过 `PORT` 修改
检查:
```bash
node --version
npm --version
```
## 2. 获取代码
```bash
git clone ssh://git@www.sumi.work:222/lwt/sumi.work.git
cd sumi.work
```
如果服务器上已经有仓库:
```bash
cd /path/to/sumi.work
git pull origin main
```
## 3. 安装依赖
生产环境建议使用锁文件安装:
```bash
npm ci
```
如果没有 `package-lock.json` 或需要临时恢复:
```bash
npm install
```
## 4. 配置环境变量
必须为生产环境设置自己的管理令牌和玩家账号密码,不要使用默认值。
```bash
export PORT=3030
export ADMIN_TOKEN="change-this-admin-token"
export PLAYER_USERNAME="player"
export PLAYER_PASSWORD="change-this-player-password"
export SUMI_STORAGE_DIR="/var/lib/sumi-work"
```
可选变量:
```bash
export SUMI_DATA_DIR="/var/lib/sumi-work/data"
export SUMI_UPLOAD_DIR="/var/lib/sumi-work/uploads"
export MAX_UPLOAD_BYTES=1073741824
export PLAYER_SESSION_TTL_MS=604800000
```
变量说明:
- `PORT`Node 服务监听端口,默认 `3030`
- `ADMIN_TOKEN`:管理后台调用上传/更新/删除 API 的令牌
- `PLAYER_USERNAME`:玩家登录账号
- `PLAYER_PASSWORD`:玩家登录密码
- `SUMI_STORAGE_DIR`:运行时数据根目录,推荐放在部署目录外,例如 `/var/lib/sumi-work`
- `SUMI_DATA_DIR`:软件列表和玩家账号数据目录;设置后会覆盖 `SUMI_STORAGE_DIR/data`
- `SUMI_UPLOAD_DIR`:上传图标、安装包和 version.json 目录;设置后会覆盖 `SUMI_STORAGE_DIR/uploads`
- `MAX_UPLOAD_BYTES`:最大上传文件大小,默认 1GB
- `PLAYER_SESSION_TTL_MS`:玩家登录有效期,默认 7 天
首次启动时,如果数据目录里的 `players.json` 不存在,服务会生成默认玩家。设置了 `PLAYER_USERNAME``PLAYER_PASSWORD` 时,会写入或更新对应玩家账号。
生产环境不要把上传数据放在 Git 部署目录里。推荐先创建持久化目录:
```bash
sudo mkdir -p /var/lib/sumi-work/data
sudo mkdir -p /var/lib/sumi-work/uploads/icons
sudo mkdir -p /var/lib/sumi-work/uploads/packages
sudo mkdir -p /var/lib/sumi-work/uploads/manifests
sudo chown -R "$USER":"$USER" /var/lib/sumi-work
```
如果服务器上已经有旧数据,先迁移到持久化目录再重新部署:
```bash
rsync -a server/data/ /var/lib/sumi-work/data/
rsync -a server/uploads/ /var/lib/sumi-work/uploads/
```
## 5. 启动服务
直接启动:
```bash
npm start
```
启动后访问:
- 首页:`http://服务器IP:3030/`
- 下载中心:`http://服务器IP:3030/software.html`
- 玩家登录:`http://服务器IP:3030/login.html`
- 管理后台:`http://服务器IP:3030/admin/software.html`
## 6. 用 PM2 部署
安装 PM2
```bash
npm install -g pm2
```
启动:
```bash
PORT=3030 \
ADMIN_TOKEN="change-this-admin-token" \
PLAYER_USERNAME="player" \
PLAYER_PASSWORD="change-this-player-password" \
SUMI_STORAGE_DIR="/var/lib/sumi-work" \
pm2 start server/server.js --name sumi-work
```
保存进程:
```bash
pm2 save
pm2 startup
```
查看日志:
```bash
pm2 logs sumi-work
```
重启:
```bash
pm2 restart sumi-work
```
更新部署:
```bash
cd /path/to/sumi.work
git pull origin main
npm ci
pm2 restart sumi-work
```
如果用 PM2 保存环境变量,修改 `SUMI_STORAGE_DIR` 后需要重新执行启动命令或使用 `pm2 restart sumi-work --update-env`。部署更新时只更新代码目录,不要删除 `/var/lib/sumi-work`
## 7. 用 systemd 部署
创建服务文件:
```bash
sudo nano /etc/systemd/system/sumi-work.service
```
示例内容,按实际路径替换 `WorkingDirectory`
```ini
[Unit]
Description=sumi.work Node Service
After=network.target
[Service]
Type=simple
WorkingDirectory=/path/to/sumi.work
ExecStart=/usr/bin/node server/server.js
Restart=always
RestartSec=3
Environment=NODE_ENV=production
Environment=PORT=3030
Environment=ADMIN_TOKEN=change-this-admin-token
Environment=PLAYER_USERNAME=player
Environment=PLAYER_PASSWORD=change-this-player-password
Environment=SUMI_STORAGE_DIR=/var/lib/sumi-work
[Install]
WantedBy=multi-user.target
```
启动并设置开机自启:
```bash
sudo systemctl daemon-reload
sudo systemctl enable --now sumi-work
sudo systemctl status sumi-work
```
查看日志:
```bash
journalctl -u sumi-work -f
```
更新部署:
```bash
cd /path/to/sumi.work
git pull origin main
npm ci
sudo systemctl restart sumi-work
```
## 8. Nginx 反向代理
建议让 Nginx 只反向代理到 Node 服务,不要直接把上传安装包目录暴露成静态目录。安装包下载必须走 `/api/software/:id/download`,这样才能验证玩家登录。
示例:
```nginx
server {
listen 80;
server_name sumi.work www.sumi.work;
client_max_body_size 1024m;
location / {
proxy_pass http://127.0.0.1:3030;
proxy_http_version 1.1;
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;
}
}
```
重新加载:
```bash
sudo nginx -t
sudo systemctl reload nginx
```
## 9. 验证部署
健康检查:
```bash
curl -i http://127.0.0.1:3030/api/health
```
预期包含:
```json
{"ok":true,"service":"sumi-software-center"}
```
检查软件下载列表:
```bash
curl -i http://127.0.0.1:3030/api/software
```
检查未登录不能下载:
```bash
curl -i -H "Accept: application/json" http://127.0.0.1:3030/api/software/sumi-launcher/download
```
预期:
```text
HTTP/1.1 401 Unauthorized
```
检查玩家登录:
```bash
curl -i \
-c /tmp/sumi-player.cookie \
-H "Content-Type: application/json" \
-d '{"username":"player","password":"change-this-player-password","next":"/software.html"}' \
http://127.0.0.1:3030/api/auth/login
```
检查登录状态:
```bash
curl -i -b /tmp/sumi-player.cookie http://127.0.0.1:3030/api/auth/me
```
管理后台读取列表:
```bash
curl -i -H "X-Admin-Token: change-this-admin-token" http://127.0.0.1:3030/api/admin/software
```
## 10. version.json 与检查更新
管理后台上传软件时可以同时上传 `version.json`,也可以直接编辑“版本内容 JSON”。如果上传安装包且版本内容留空,服务端会自动生成一个兼容更新器的 version.json。
推荐 `version.json`
```json
{
"version": "1.2.0",
"changelog": "修复已知问题并优化启动速度",
"forceUpdate": false,
"minSupportedVersion": "1.0.0",
"sha256": "package-sha256-if-known"
}
```
也兼容下面这种更新器常用格式:
```json
{
"version": "1.1.5",
"update_url": "https://sumi.work/api/software/server-manager/version.json",
"release_notes": "数据库测试连接改为真实 MySQL 连接探测。",
"download_url": "https://sumi.work/api/software/server-manager/download",
"full_installer_url": "https://sumi.work/api/software/server-manager/download",
"delta_updates": {}
}
```
字段说明:
- `version`:最新版本号,检查更新时用于和客户端当前版本对比
- `changelog`:更新说明
- `release_notes`:更新说明,等同于 `changelog`
- `update_url`version.json 地址,建议改成当前下载中心的 `/api/software/<软件ID>/version.json`
- `download_url`:完整安装包下载地址,建议改成当前下载中心的 `/api/software/<软件ID>/download`
- `full_installer_url`:完整安装包下载地址,等同于 `download_url`
- `delta_updates`:差分更新信息,会原样返回
- `forceUpdate`:是否强制更新
- `minSupportedVersion`:最低支持版本,客户端版本低于它时会返回 `forceUpdate: true`
- `sha256`:安装包校验值;如果未提供,会使用服务端上传安装包计算出的值
如果使用你原来的内网文件服务地址,例如:
```json
"update_url": "http://172.18.180.94:3000/api/file?path=server_manager/build/output/version.json",
"download_url": "http://172.18.180.94:3000/api/download?path=server_manager/build/output/ServerManager_Setup.exe"
```
它也能被服务端读取和保存。但如果希望下载中心继续执行“玩家登录后才能下载”的规则,应改成下载中心自己的地址:
```json
"update_url": "https://sumi.work/api/software/server-manager/version.json",
"download_url": "https://sumi.work/api/software/server-manager/download",
"full_installer_url": "https://sumi.work/api/software/server-manager/download"
```
其中 `server-manager` 是软件 ID。新增软件时服务端会按软件名自动生成 ID;也可以上传后在管理接口返回结果里查看 `id``versionManifestUrl``downloadUrl`
后台操作规则:
- 只上传安装包,版本内容留空:服务端自动生成 version.json。
- 上传安装包,同时填写版本内容 JSON:安装包会更新,版本内容按填写的 JSON 保存。
- 不上传安装包,只修改版本内容 JSON:只更新版本清单和检查更新内容。
- 上传 `version.json` 文件:文件内容优先于文本框内容。
获取版本清单:
```bash
curl -i http://127.0.0.1:3030/api/software/sumi-launcher/version.json
```
检查更新:
```bash
curl -i "http://127.0.0.1:3030/api/software/sumi-launcher/check-update?version=1.0.0"
```
返回重点字段:
```json
{
"currentVersion": "1.0.0",
"latestVersion": "1.2.0",
"updateAvailable": true,
"forceUpdate": false,
"downloadUrl": "/api/software/sumi-launcher/download",
"versionManifestUrl": "/api/software/sumi-launcher/version.json"
}
```
`downloadUrl` 仍然受玩家登录保护,未登录下载会返回 `401` 或跳转到登录页。
## 11. 数据与备份
生产环境需要把运行时数据放在 Git 部署目录外。推荐:
- `SUMI_STORAGE_DIR=/var/lib/sumi-work`
- `/var/lib/sumi-work/data/software.json`:软件元数据
- `/var/lib/sumi-work/data/players.json`:玩家账号数据
- `/var/lib/sumi-work/uploads/icons/`:上传的软件图标
- `/var/lib/sumi-work/uploads/packages/`:上传的软件安装包
- `/var/lib/sumi-work/uploads/manifests/`:上传的 version.json 文件
未设置 `SUMI_STORAGE_DIR``SUMI_DATA_DIR``SUMI_UPLOAD_DIR` 时,本地开发会继续使用仓库里的 `server/data/``server/uploads/`。生产部署不要依赖这个默认路径。
建议备份命令:
```bash
tar -czf sumi-work-data-$(date +%F).tar.gz -C /var/lib sumi-work
```
恢复时把备份内容还原到 `/var/lib/sumi-work`,确认服务环境变量仍然指向这个目录,然后重启服务。
重新部署代码时只执行:
```bash
cd /path/to/sumi.work
git pull origin main
npm ci
pm2 restart sumi-work --update-env
```
不要在部署脚本里执行 `rm -rf /var/lib/sumi-work`,也不要用新代码包覆盖这个目录。Node 服务只读取静态 HTML/CSS/JS 用于显示页面,上传软件包、version.json、玩家数据都写入持久化目录。
## 12. 常见问题
端口被占用:
```bash
lsof -i :3030
```
修改 `PORT` 后重启服务。
上传失败:
- 检查 `client_max_body_size`
- 检查 `MAX_UPLOAD_BYTES`
- 检查 `SUMI_UPLOAD_DIR``/var/lib/sumi-work/uploads/` 是否可写
管理后台 401
- 确认前端输入的 `ADMIN_TOKEN` 与服务端环境变量一致
- 确认请求头是 `X-Admin-Token`
玩家无法下载:
- 先访问 `/login.html` 登录
- 确认 `/api/auth/me` 返回 `authenticated: true`
- 确认 Nginx 没有直接拦截或改写 Cookie
安装包被绕过下载:
- 不要配置 Nginx 直接静态暴露上传安装包目录,例如 `/var/lib/sumi-work/uploads/packages/`
- 正确做法是所有请求都反代到 Node 服务
## 13. 快速执行清单
```bash
cd /path/to/sumi.work
git pull origin main
npm ci
sudo mkdir -p /var/lib/sumi-work/data /var/lib/sumi-work/uploads/icons /var/lib/sumi-work/uploads/packages /var/lib/sumi-work/uploads/manifests
sudo chown -R "$USER":"$USER" /var/lib/sumi-work
export PORT=3030
export ADMIN_TOKEN="change-this-admin-token"
export PLAYER_USERNAME="player"
export PLAYER_PASSWORD="change-this-player-password"
export SUMI_STORAGE_DIR="/var/lib/sumi-work"
npm start
```
验证:
```bash
curl http://127.0.0.1:3030/api/health
```
## 14. 后续本地开发与服务器发布流程
本地开发:
```bash
cd /path/to/sumi.work
npm install
npm start
```
提交并推送:
```bash
git status
git add .
git commit -m "your change message"
git push origin main
```
当前服务器已经配置好干净部署目录和持久化数据目录:
- 代码目录:`/var/www/sumi.work`
- 持久化目录:`/var/lib/sumi-work`
- systemd 服务:`sumi-work`
- 快捷部署命令:`/usr/local/bin/deploy-sumi-work`
本地推送后,在服务器执行:
```bash
deploy-sumi-work
```
它会自动执行:
```bash
cd /var/www/sumi.work
git fetch origin main
git pull --ff-only origin main
npm ci
node --check server/server.js
node --check assets/js/software.js
node --check assets/js/software-admin.js
systemctl restart sumi-work
curl -fsS http://127.0.0.1:3030/api/health
```
通过 SSH 节点技能远程执行:
```powershell
python C:/Users/Administrator/.codex/skills/ssh-remote-node/scripts/ssh_node.py --host 43.136.76.224 --port 22 --user root --key D:\rsa\id_rsa exec --command deploy-sumi-work
```
服务器保留了部署前备份:
- 完整备份目录:`/root/sumi-work-backups/`
- 上一次旧代码目录:`/var/www/sumi.work.previous-*`
不要再手工覆盖 `/var/www/sumi.work`,后续以“本地提交 -> 推送 Git -> 服务器执行 `deploy-sumi-work`”为准。