# sumi.work NPM 部署说明 这份文档给 AI/运维执行者使用,用于把当前仓库部署为可运行的 Node.js 服务。项目包含静态首页、软件下载中心、玩家登录下载限制、软件管理后台和上传更新 API。 ## 1. 运行环境 要求: - Node.js 20+,推荐 Node.js 22 LTS 或更高版本 - npm - Subversion CLI:`svn` - 持久化可写目录:推荐 `/var/lib/sumi-work/` - 对外端口:默认 `3030`,可通过 `PORT` 修改 检查: ```bash node --version npm --version svn --version --quiet ``` ## 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 SUMI_SVN_DIR="/var/lib/sumi-work/svn" 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` - `SUMI_SVN_DIR`:SVN 工作副本和导出目录;设置后会覆盖 `SUMI_STORAGE_DIR/svn` - `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 mkdir -p /var/lib/sumi-work/svn 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` - SVN 管理:`http://服务器IP:3030/admin/svn.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 文件 - `/var/lib/sumi-work/svn/`:SVN 工作副本和导出文件 - `/var/lib/sumi-work/data/svn.json`:SVN 仓库配置 未设置 `SUMI_STORAGE_DIR`、`SUMI_DATA_DIR`、`SUMI_UPLOAD_DIR`、`SUMI_SVN_DIR` 时,本地开发会继续使用仓库里的 `server/data/`、`server/uploads/` 和 `server/svn/`。生产部署不要依赖这个默认路径。 建议备份命令: ```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/` 是否可写 SVN 管理不可用: - 检查服务器是否安装 `svn`:`svn --version --quiet` - 检查 `SUMI_SVN_DIR` 或 `/var/lib/sumi-work/svn/` 是否可写 - 检查仓库 URL、账号、密码和证书信任设置 - 写操作需要玩家登录并提供正确的 `ADMIN_TOKEN` 管理后台 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 /var/lib/sumi-work/svn 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 node --check assets/js/svn-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`”为准。