5 Commits

Author SHA1 Message Date
ac12f1ed5e Merge branch 'codex/wechat'
Some checks failed
CI / verify (push) Has been cancelled
2026-05-12 22:30:50 +08:00
36e134e323 merge codex/wechat into master
Some checks failed
CI / verify (push) Has been cancelled
2026-05-12 18:58:21 +08:00
9b72dbb3ea ci: load nginx dynamic modules for brotli probe
Some checks failed
CI / verify (push) Has been cancelled
2026-05-12 16:59:01 +08:00
188c6704db ci: detect nginx brotli via config test
Some checks failed
CI / verify (push) Has been cancelled
2026-05-12 16:53:53 +08:00
d641840098 ci: enable nginx compression in server provision
Some checks failed
CI / verify (push) Has been cancelled
2026-05-12 16:30:35 +08:00
4 changed files with 120 additions and 2 deletions

34
deploy/nginx/README.md Normal file
View File

@@ -0,0 +1,34 @@
# Genarrative Nginx compression policy
本配置片段由 `scripts/jenkins-server-provision.sh` 在安装 Nginx 站点配置时展开。
## gzip
- `deploy/nginx/genarrative.conf``deploy/nginx/genarrative-dev-http.conf` 默认开启 gzip。
- 覆盖 `application/json`,用于降低 `/api/runtime/*/gallery` 这类 JSON 列表接口的公网带宽占用。
- 当前推荐等级为 `gzip_comp_level 5`,兼顾 2C/2G 服务器 CPU 与压缩收益。
## Brotli
- Brotli 只在目标服务器 Nginx 接受 brotli 指令时开启。
- Provision 脚本通过临时配置执行 `nginx -t` 做能力探测;探测配置会先 `include /etc/nginx/modules-enabled/*.conf`,避免 Ubuntu 动态模块已安装但测试配置未加载模块导致误判。可用时把模板中的 `# __GENARRATIVE_BROTLI_DIRECTIVES__` 替换为 brotli 指令,不可用时保留注释说明。
- 不要直接在静态模板里无条件写 `brotli on;`,否则没有 brotli 模块的服务器会 `nginx -t` 失败并回滚。
- 不要用 `nginx -V | grep brotli` 判断 brotli 是否可用Ubuntu apt 安装的 brotli 是动态模块,可能只出现在 `nginx -T``load_module` 配置里。
## 验证
```bash
curl -sSI -H 'Accept-Encoding: gzip' \
http://<host>/api/runtime/puzzle/gallery \
| grep -iE 'content-encoding|vary|content-type|content-length'
curl -sSI -H 'Accept-Encoding: br' \
http://<host>/api/runtime/puzzle/gallery \
| grep -iE 'content-encoding|vary|content-type|content-length'
```
预期:
- gzip 可用时返回 `Content-Encoding: gzip`
- br 可用时返回 `Content-Encoding: br`
- 响应头应包含 `Vary: Accept-Encoding`

View File

@@ -5,6 +5,23 @@ server {
listen 80;
server_name genarrative.example.com;
gzip on;
gzip_vary on;
gzip_proxied any;
gzip_comp_level 5;
gzip_min_length 1024;
gzip_types
text/plain
text/css
text/javascript
application/javascript
application/json
application/xml
application/xml+rss
image/svg+xml;
# __GENARRATIVE_BROTLI_DIRECTIVES__
root /srv/genarrative/web;
index index.html;

View File

@@ -16,6 +16,23 @@ server {
listen 443 ssl http2;
server_name genarrative.example.com;
gzip on;
gzip_vary on;
gzip_proxied any;
gzip_comp_level 5;
gzip_min_length 1024;
gzip_types
text/plain
text/css
text/javascript
application/javascript
application/json
application/xml
application/xml+rss
image/svg+xml;
# __GENARRATIVE_BROTLI_DIRECTIVES__
ssl_certificate /etc/letsencrypt/live/genarrative.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/genarrative.example.com/privkey.pem;

View File

@@ -295,12 +295,62 @@ ensure_spacetime_owner_client_token() {
echo "[server-provision] 已同步 SpacetimeDB CLI 登录态;后续首次 publish 将使用同一 client identity。"
}
render_nginx_brotli_directives() {
if ! command -v nginx >/dev/null 2>&1; then
echo " # Brotli 未启用:目标服务器未找到 nginx 命令。"
return
fi
local brotli_snippet
brotli_snippet="$(mktemp)"
cat >"${brotli_snippet}" <<'EOF'
include /etc/nginx/modules-enabled/*.conf;
events {}
http {
brotli on;
brotli_comp_level 4;
brotli_min_length 1024;
brotli_types application/json;
}
EOF
if nginx -t -c "${brotli_snippet}" >/dev/null 2>&1; then
cat <<'EOF'
brotli on;
brotli_comp_level 4;
brotli_min_length 1024;
brotli_types
text/plain
text/css
text/javascript
application/javascript
application/json
application/xml
application/xml+rss
image/svg+xml;
EOF
else
echo " # Brotli 未启用nginx -t 不接受 brotli 指令。"
fi
rm -f "${brotli_snippet}"
}
render_nginx_template() {
local template="$1"
local rendered_brotli
rendered_brotli="$(render_nginx_brotli_directives)"
sed \
-e "s/genarrative.example.com/${SERVER_NAME}/g" \
-e "/# __GENARRATIVE_BROTLI_DIRECTIVES__/r /dev/stdin" \
-e "/# __GENARRATIVE_BROTLI_DIRECTIVES__/d" \
"${template}" <<<"${rendered_brotli}"
}
render_nginx_https_config() {
sed "s/genarrative.example.com/${SERVER_NAME}/g" deploy/nginx/genarrative.conf
render_nginx_template deploy/nginx/genarrative.conf
}
render_nginx_development_http_config() {
sed "s/genarrative.example.com/${SERVER_NAME}/g" deploy/nginx/genarrative-dev-http.conf
render_nginx_template deploy/nginx/genarrative-dev-http.conf
}
render_api_env_example() {