Files
sumi.work/DEPLOY.md
T

14 KiB
Raw Blame History

sumi.work NPM 部署说明

这份文档给 AI/运维执行者使用,用于把当前仓库部署为可运行的 Node.js 服务。项目包含静态首页、软件下载中心、玩家登录下载限制、软件管理后台和上传更新 API。

1. 运行环境

要求:

  • Node.js 20+,推荐 Node.js 22 LTS 或更高版本
  • npm
  • 持久化可写目录:推荐 /var/lib/sumi-work/
  • 对外端口:默认 3030,可通过 PORT 修改

检查:

node --version
npm --version

2. 获取代码

git clone ssh://git@www.sumi.work:222/lwt/sumi.work.git
cd sumi.work

如果服务器上已经有仓库:

cd /path/to/sumi.work
git pull origin main

3. 安装依赖

生产环境建议使用锁文件安装:

npm ci

如果没有 package-lock.json 或需要临时恢复:

npm install

4. 配置环境变量

必须为生产环境设置自己的管理令牌和玩家账号密码,不要使用默认值。

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"

可选变量:

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

变量说明:

  • PORTNode 服务监听端口,默认 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_USERNAMEPLAYER_PASSWORD 时,会写入或更新对应玩家账号。

生产环境不要把上传数据放在 Git 部署目录里。推荐先创建持久化目录:

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

如果服务器上已经有旧数据,先迁移到持久化目录再重新部署:

rsync -a server/data/ /var/lib/sumi-work/data/
rsync -a server/uploads/ /var/lib/sumi-work/uploads/

5. 启动服务

直接启动:

npm start

启动后访问:

  • 首页:http://服务器IP:3030/
  • 下载中心:http://服务器IP:3030/software.html
  • 玩家登录:http://服务器IP:3030/login.html
  • 管理后台:http://服务器IP:3030/admin/software.html

6. 用 PM2 部署

安装 PM2

npm install -g pm2

启动:

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

保存进程:

pm2 save
pm2 startup

查看日志:

pm2 logs sumi-work

重启:

pm2 restart sumi-work

更新部署:

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 部署

创建服务文件:

sudo nano /etc/systemd/system/sumi-work.service

示例内容,按实际路径替换 WorkingDirectory

[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

启动并设置开机自启:

sudo systemctl daemon-reload
sudo systemctl enable --now sumi-work
sudo systemctl status sumi-work

查看日志:

journalctl -u sumi-work -f

更新部署:

cd /path/to/sumi.work
git pull origin main
npm ci
sudo systemctl restart sumi-work

8. Nginx 反向代理

建议让 Nginx 只反向代理到 Node 服务,不要直接把上传安装包目录暴露成静态目录。安装包下载必须走 /api/software/:id/download,这样才能验证玩家登录。

示例:

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;
    }
}

重新加载:

sudo nginx -t
sudo systemctl reload nginx

9. 验证部署

健康检查:

curl -i http://127.0.0.1:3030/api/health

预期包含:

{"ok":true,"service":"sumi-software-center"}

检查软件下载列表:

curl -i http://127.0.0.1:3030/api/software

检查未登录不能下载:

curl -i -H "Accept: application/json" http://127.0.0.1:3030/api/software/sumi-launcher/download

预期:

HTTP/1.1 401 Unauthorized

检查玩家登录:

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

检查登录状态:

curl -i -b /tmp/sumi-player.cookie http://127.0.0.1:3030/api/auth/me

管理后台读取列表:

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

{
  "version": "1.2.0",
  "changelog": "修复已知问题并优化启动速度",
  "forceUpdate": false,
  "minSupportedVersion": "1.0.0",
  "sha256": "package-sha256-if-known"
}

也兼容下面这种更新器常用格式:

{
  "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_urlversion.json 地址,建议改成当前下载中心的 /api/software/<软件ID>/version.json
  • download_url:完整安装包下载地址,建议改成当前下载中心的 /api/software/<软件ID>/download
  • full_installer_url:完整安装包下载地址,等同于 download_url
  • delta_updates:差分更新信息,会原样返回
  • forceUpdate:是否强制更新
  • minSupportedVersion:最低支持版本,客户端版本低于它时会返回 forceUpdate: true
  • sha256:安装包校验值;如果未提供,会使用服务端上传安装包计算出的值

如果使用你原来的内网文件服务地址,例如:

"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"

它也能被服务端读取和保存。但如果希望下载中心继续执行“玩家登录后才能下载”的规则,应改成下载中心自己的地址:

"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;也可以上传后在管理接口返回结果里查看 idversionManifestUrldownloadUrl

后台操作规则:

  • 只上传安装包,版本内容留空:服务端自动生成 version.json。
  • 上传安装包,同时填写版本内容 JSON:安装包会更新,版本内容按填写的 JSON 保存。
  • 不上传安装包,只修改版本内容 JSON:只更新版本清单和检查更新内容。
  • 上传 version.json 文件:文件内容优先于文本框内容。

获取版本清单:

curl -i http://127.0.0.1:3030/api/software/sumi-launcher/version.json

检查更新:

curl -i "http://127.0.0.1:3030/api/software/sumi-launcher/check-update?version=1.0.0"

返回重点字段:

{
  "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_DIRSUMI_DATA_DIRSUMI_UPLOAD_DIR 时,本地开发会继续使用仓库里的 server/data/server/uploads/。生产部署不要依赖这个默认路径。

建议备份命令:

tar -czf sumi-work-data-$(date +%F).tar.gz -C /var/lib sumi-work

恢复时把备份内容还原到 /var/lib/sumi-work,确认服务环境变量仍然指向这个目录,然后重启服务。

重新部署代码时只执行:

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. 常见问题

端口被占用:

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. 快速执行清单

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

验证:

curl http://127.0.0.1:3030/api/health

14. 后续本地开发与服务器发布流程

本地开发:

cd /path/to/sumi.work
npm install
npm start

提交并推送:

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

本地推送后,在服务器执行:

deploy-sumi-work

它会自动执行:

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 节点技能远程执行:

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”为准。