diff --git a/deploy/nginx/README.md b/deploy/nginx/README.md new file mode 100644 index 00000000..25a27161 --- /dev/null +++ b/deploy/nginx/README.md @@ -0,0 +1,33 @@ +# 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 -V` 和 `nginx -t` 做探测;可用时把模板中的 `# __GENARRATIVE_BROTLI_DIRECTIVES__` 替换为 brotli 指令,不可用时保留注释说明。 +- 不要直接在静态模板里无条件写 `brotli on;`,否则没有 brotli 模块的服务器会 `nginx -t` 失败并回滚。 + +## 验证 + +```bash +curl -sSI -H 'Accept-Encoding: gzip' \ + http:///api/runtime/puzzle/gallery \ + | grep -iE 'content-encoding|vary|content-type|content-length' + +curl -sSI -H 'Accept-Encoding: br' \ + http:///api/runtime/puzzle/gallery \ + | grep -iE 'content-encoding|vary|content-type|content-length' +``` + +预期: + +- gzip 可用时返回 `Content-Encoding: gzip`。 +- br 可用时返回 `Content-Encoding: br`。 +- 响应头应包含 `Vary: Accept-Encoding`。 diff --git a/deploy/nginx/genarrative-dev-http.conf b/deploy/nginx/genarrative-dev-http.conf index 4e566377..824a8f5a 100644 --- a/deploy/nginx/genarrative-dev-http.conf +++ b/deploy/nginx/genarrative-dev-http.conf @@ -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; diff --git a/deploy/nginx/genarrative.conf b/deploy/nginx/genarrative.conf index 3db856ed..06a3bf86 100644 --- a/deploy/nginx/genarrative.conf +++ b/deploy/nginx/genarrative.conf @@ -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; diff --git a/scripts/jenkins-server-provision.sh b/scripts/jenkins-server-provision.sh index fd8f6df1..cff23e7b 100755 --- a/scripts/jenkins-server-provision.sh +++ b/scripts/jenkins-server-provision.sh @@ -295,12 +295,66 @@ 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 + + if ! nginx -V 2>&1 | grep -qi brotli; then + echo " # Brotli 未启用:当前 nginx 未编译或加载 brotli 模块。" + return + fi + + local brotli_snippet + brotli_snippet="$(mktemp)" + cat >"${brotli_snippet}" <<'EOF' +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() {