Files
SoundGame/docs/deploy.md
T
xsl ec248e18da ops(deploy): 一键部署脚本 tools/deploy.sh + deploy.md 同步 no-cache 缓存策略
- tools/deploy.sh:git pull --ff-only → rsync web/ → /var/www/soundgame
  (排除开发用文件)→ chown www-data → 线上冒烟(大厅/子站/301/Range)。
  已在部署服务器实测全流程 PASS。
- docs/deploy.md:nginx 配置段同步为线上现行 no-cache 版本(原文档仍是
  expires+public,照抄会把「部署后旧 JS 在浏览器滞留 24h」的坑重新引回),
  并注明一键脚本入口。背景:2026-09-07 引擎句尾截断修复已正确部署,
  但旧 audio.js 被 max-age=86400 public 缓存,用户 24h 内仍执行旧代码。
2026-09-07 18:03:39 +08:00

174 lines
6.2 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.
# SoundGame — 公网部署
线上地址:<https://game.xiangsilian.com/>
个人简历站 <https://xiangsilian.com/> 首页「深入了解」与页脚有入口。本机 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/`、研究文档也不在线上。
## 更新游戏文件
上述流程已封装为一键脚本 `tools/deploy.sh`(git pull --ff-only + rsync +
chown + 冒烟验证),在部署服务器上执行:
```bash
bash tools/deploy.sh
```
等价的手动步骤(源码有改动后,在本机执行):
```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;配合全站 `no-cache` 缓存策略,用户下次
打开页面即可拿到新文件(2026-09-07 之前 js/css 曾是 24h 强缓存,部署后旧 JS
在用户浏览器里滞留一天,表现为"改了却没生效")。改了 `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;
# 全站 no-cache:可缓存但必须回源验证(ETag→304)。
# 2026-09-07 教训:此前 js/css 是 max-age=86400 public,引擎修复部署后
# 用户浏览器 24h 内仍执行旧 audio.js,句尾截断"修不好"。静态小站回源
# 验证成本可忽略,换取每次部署立即生效。
add_header Cache-Control "no-cache";
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?)$ {
add_header Cache-Control "no-cache";
add_header X-Content-Type-Options nosniff;
access_log off;
}
location ~* \.(js|css)$ {
add_header Cache-Control "no-cache";
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。