- 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 内仍执行旧代码。
174 lines
6.2 KiB
Markdown
174 lines
6.2 KiB
Markdown
# 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。
|