From 2de1fecbc6b01c34699ac242b7fd6ce1e5b181d4 Mon Sep 17 00:00:00 2001 From: xsl Date: Mon, 31 Aug 2026 11:43:32 +0800 Subject: [PATCH] =?UTF-8?q?docs:=20=E5=85=AC=E7=BD=91=E9=9D=99=E6=80=81?= =?UTF-8?q?=E9=83=A8=E7=BD=B2=E6=89=8B=E5=86=8C=EF=BC=88game.xiangsilian.c?= =?UTF-8?q?om=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 线上只托管静态文件、不暴露玩具级用户 API;HTTPS 域名下大厅隐藏登录。部署步骤与 Nginx 配置记在 docs/deploy.md,便于以后 rsync 更新。 Co-authored-by: Cursor --- README.md | 5 +- docs/deploy.md | 161 +++++++++++++++++++++++++++++++++++++++++++ web/index.html | 18 +++-- web/server/README.md | 3 +- 4 files changed, 181 insertions(+), 6 deletions(-) create mode 100644 docs/deploy.md diff --git a/README.md b/README.md index 7bf06a52..aa0640cf 100644 --- a/README.md +++ b/README.md @@ -10,6 +10,8 @@ BGM 用 Mureka API 生成 + 程序合成。 无需安装 App,手机浏览器打开即玩(Android Chrome / iOS Safari / 鸿蒙 ArkWeb 均支持, 音频提供 ogg + m4a 双格式)。 +线上:(Nginx 静态托管,无用户 API;部署见 `docs/deploy.md`)。 + ```bash ./web/serve.sh # 启动 Node 服务器(静态 + 用户系统 API,默认端口 8000) ``` @@ -36,7 +38,7 @@ BGM 用 Mureka API 生成 + 程序合成。 交互式演练教学、60 秒保护期、单击加速双击护盾 Web 引擎文档见 `docs/web-engine-api.md`;服务器 API 见 `web/server/README.md`; -设计文档在 `docs/design/`;资产管线文档在 `docs/audio/`。 +公网部署见 `docs/deploy.md`;设计文档在 `docs/design/`;资产管线文档在 `docs/audio/`。 ## 三款游戏(Android 版,已停止迭代) @@ -90,6 +92,7 @@ APK 输出在 `app/build/outputs/apk//debug/`: ## 文档 - `docs/setup.md` — 从零环境搭建手册(WSL2 用户态安装、AI 环境、镜像速查、故障排查) +- `docs/deploy.md` — 公网部署(`game.xiangsilian.com`,Nginx 静态,与简历站共存) - `docs/architecture.md` — 引擎架构(模块划分、音频三层时序、手势参数、已知限制) - `docs/engine-api.md` — 引擎 API(如何开发一款新游戏) - `docs/asset-pipeline.md` — 资产生产流水线(TTS / 音效 / BGM 生成与规格) diff --git a/docs/deploy.md b/docs/deploy.md new file mode 100644 index 00000000..276f017d --- /dev/null +++ b/docs/deploy.md @@ -0,0 +1,161 @@ +# SoundGame — 公网部署 + +线上地址: + +个人简历站 首页「深入了解」与页脚有入口。本机 Nginx +同时托管这两个站点:根域名仍是简历站,游戏走独立子域名,互不覆盖。 + +## 方案摘要 + +公网**只托管静态文件**,不启动 `web/server/server.js`。 + +原因:用户系统是家庭局域网玩具级认证(PIN 明文、token 永不过期、无速率限制), +见 `web/server/README.md`。游戏本身不依赖 API——未登录时设置和进度写在浏览器 +`localStorage`。大厅在 `https://*.xiangsilian.com` 下会隐藏登录面板 +(`web/index.html` 里的 `PUBLIC_STATIC`)。本地 `./web/serve.sh` 仍显示登录。 + +``` +手机浏览器 + │ HTTPS + ▼ +Nginx 80/443 + ├── xiangsilian.com → /var/www/xiangsilian (简历站,已有) + └── game.xiangsilian.com → /var/www/soundgame (本游戏) +``` + +证书是同一张 Let’s Encrypt(SAN:`xiangsilian.com`、`www`、`game`),webroot +验证目录 `/var/www/letsencrypt`。`certbot.timer` 负责续期。 + +## 本机路径 + +| 用途 | 路径 | +|---|---| +| 源码 | `/home/ubuntu/SoundGame/web/` | +| 线上静态根 | `/var/www/soundgame/`(`www-data` 可读;家目录 `750`,Nginx 读不了源码目录) | +| Nginx 站点 | `/etc/nginx/sites-available/soundgame.conf` → `sites-enabled/` | +| 简历站静态根 | `/var/www/xiangsilian/` | +| 简历站源码 | `/home/ubuntu/xiangsilian/` | + +未发布:`harness/`、`*/gen/`、`*/test/`、`server/`、`template/`,以及 `*.py` / +`*.md` / `*.sh`。Android 工程、`tools/`、研究文档也不在线上。 + +## 更新游戏文件 + +源码有改动后,在本机执行: + +```bash +sudo rsync -a --delete \ + --exclude harness/ --exclude gen/ --exclude test/ \ + --exclude server/ --exclude template/ \ + --exclude '*.py' --exclude '*.md' --exclude '*.sh' \ + /home/ubuntu/SoundGame/web/ /var/www/soundgame/ +sudo chown -R www-data:www-data /var/www/soundgame +``` + +静态文件即时生效,不必 reload Nginx。改了 `soundgame.conf` 才需要: + +```bash +sudo nginx -t && sudo systemctl reload nginx +``` + +## 从零再搭一遍(本服务器已完成,仅作记录) + +前置:DNSPod 增加 A 记录 `game` → 本机公网 IP(当前 `118.89.233.55`)。 +`xiangsilian.com` / `www` 的 Nginx + 证书应已存在。 + +1. 按上一节 rsync 到 `/var/www/soundgame`。 +2. 先写 **仅 HTTP** 的 `server_name game.xiangsilian.com`,包含 + `location /.well-known/acme-challenge/`(`root /var/www/letsencrypt`), + `nginx -t` 后 reload。此时还没有该主机名的证书,不能先开 443。 +3. 扩证书(会改同一张 live 证书,现站 HTTPS 不停): + + ```bash + sudo certbot certonly --webroot -w /var/www/letsencrypt \ + -d xiangsilian.com -d www.xiangsilian.com -d game.xiangsilian.com \ + --expand --non-interactive --agree-tos + ``` + + 扩完后确认 `/etc/letsencrypt/renewal/xiangsilian.com.conf` 的 + `[[webroot_map]]` 含三个域名(certbot 有时只留下新加的那条,缺了续期会掉名)。 +4. 换成完整配置(HTTP 301 → HTTPS,443 指 `/var/www/soundgame`),reload。 + 当前线上配置见下一节。 + +## Nginx 配置(`/etc/nginx/sites-available/soundgame.conf`) + +```nginx +# game.xiangsilian.com — SoundGame HTML5 static site +server { + listen 80; + listen [::]:80; + server_name game.xiangsilian.com; + + location /.well-known/acme-challenge/ { + root /var/www/letsencrypt; + } + + location / { + return 301 https://game.xiangsilian.com$request_uri; + } +} + +server { + listen 443 ssl http2; + listen [::]:443 ssl http2; + server_name game.xiangsilian.com; + + ssl_certificate /etc/letsencrypt/live/xiangsilian.com/fullchain.pem; + ssl_certificate_key /etc/letsencrypt/live/xiangsilian.com/privkey.pem; + include /etc/letsencrypt/options-ssl-nginx.conf; + ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; + + root /var/www/soundgame; + index index.html; + + add_header X-Content-Type-Options nosniff; + add_header Referrer-Policy strict-origin-when-cross-origin; + + location ~ /\. { + deny all; + } + + location / { + try_files $uri $uri/ =404; + } + + location ~* \.(ogg|m4a|mp3|wav|png|jpg|jpeg|gif|ico|svg|woff2?)$ { + expires 7d; + add_header Cache-Control "public"; + add_header X-Content-Type-Options nosniff; + access_log off; + } + + location ~* \.(js|css)$ { + expires 1d; + add_header Cache-Control "public"; + add_header X-Content-Type-Options nosniff; + } +} +``` + +音频走 Nginx 原生 Range(`Accept-Ranges`),不要反代到 Node。系统 +`mime.types` 已有 `audio/ogg` 与 `audio/x-m4a`。 + +## 以后若要开放用户系统 + +不要把 `server.js` 绑到 `0.0.0.0`。至少做到:监听 `127.0.0.1`、Nginx 只反代 +`/api/`、加 `limit_req`、PIN 改哈希、token 设过期。在此之前保持静态-only。 + +## 冒烟 + +```bash +curl -sI https://game.xiangsilian.com/ # 200 +curl -sI http://game.xiangsilian.com/ # 301 → https +curl -sI https://game.xiangsilian.com/rpg/ # 200 +curl -sI https://game.xiangsilian.com/api/login # 404 +curl -sI -H 'Range: bytes=0-1023' \ + https://game.xiangsilian.com/rpg/audio/bgm/boss.ogg # 206 +curl -sI https://xiangsilian.com/ # 200,简历站仍在 +``` + +真机:手机浏览器打开大厅 → 点进一款游戏 → 「轻触开始」后应出声(建议耳机)。 +iOS 用 m4a,Android 用 ogg。 diff --git a/web/index.html b/web/index.html index 5dd3dabe..3f7f78ea 100644 --- a/web/index.html +++ b/web/index.html @@ -354,11 +354,21 @@ } // ---------- 启动 ---------- + // 公网站点只托管静态文件,不跑用户 API(PIN 明文,不宜暴露)。 + // 本地 ./web/serve.sh(http + 非 443)仍显示登录。 + const PUBLIC_STATIC = + location.protocol === 'https:' && location.hostname.endsWith('xiangsilian.com'); + reflectSettings(); - renderUserArea(); - if (getAuth()) { - pullSettings(); - loadProgress(); + if (PUBLIC_STATIC) { + const userPanel = document.getElementById('user-panel'); + if (userPanel) userPanel.hidden = true; + } else { + renderUserArea(); + if (getAuth()) { + pullSettings(); + loadProgress(); + } } diff --git a/web/server/README.md b/web/server/README.md index 00a206eb..048febc1 100644 --- a/web/server/README.md +++ b/web/server/README.md @@ -26,7 +26,8 @@ PORT=8001 tools/node/bin/node web/server/server.js - token 永不过期,明文存于 `data/sessions.json`; - HTTP 明文传输,无 TLS、无防爆破、无速率限制。 -用途仅限于同一 WiFi 下的家庭成员各自存档。要公网部署请换正经认证方案。 +用途仅限于同一 WiFi 下的家庭成员各自存档。公网 `game.xiangsilian.com` **不跑本服务**, +只托管静态文件(见 `docs/deploy.md`)。要公网开用户系统请换正经认证方案。 ## API