# static-assets.conf — Compression + long-lived cache headers for static assets. # # Place at /etc/nginx/snippets/static-assets.conf and `include` it inside # the server { } block of the levineuwirth.org vhost: # # server { # server_name levineuwirth.org; # root /var/www/levineuwirth.org; # ... # include snippets/static-assets.conf; # include snippets/popup-proxy.conf; # } # # Pairs with tools/compress-assets.sh, which pre-generates .gz and .br # sidecars at build time so nginx never pays the compression cost at # request time. # ── On-the-fly gzip (fallback) ─────────────────────────────────────── # Covers dynamically generated responses and any file for which a .gz # sidecar was not produced (e.g. files smaller than compress-assets.sh's # MIN_SIZE threshold, or extensions not on its allow-list). gzip on; gzip_vary on; gzip_comp_level 6; gzip_min_length 256; gzip_proxied any; gzip_types text/plain text/css text/xml application/javascript text/javascript application/json application/xml application/xml+rss application/wasm image/svg+xml; # ── Pre-compressed sidecars ────────────────────────────────────────── # Serve .gz / .br when the client advertises a matching # Accept-Encoding. Zero request-time CPU; maximum compression ratio # because the sidecars were produced with gzip -9 / brotli -Z. gzip_static on; # brotli_static requires the ngx_brotli module: # Arch: pacman -S nginx-mod-brotli (or build nginx-mainline with the module) # Debian/Ubuntu: apt install libnginx-mod-brotli # If the module is absent, comment out the two brotli lines below; gzip_static # will still cover every modern browser. Chromium/Firefox/Safari all accept gzip. brotli_static on; brotli off; # we ship pre-compressed sidecars only, no on-the-fly brotli # ── Cache headers ──────────────────────────────────────────────────── # PDF.js viewer is version-pinned in tools/download-pdfjs.sh — bumping # the pin is a deploy, so `immutable` is safe and makes repeat visits # instantaneous. Same reasoning applies to fingerprinted fonts and the # locally vendored ML model files. location ^~ /pdfjs/ { add_header Cache-Control "public, max-age=31536000, immutable" always; access_log off; } location ^~ /fonts/ { add_header Cache-Control "public, max-age=31536000, immutable" always; access_log off; } location ^~ /models/ { add_header Cache-Control "public, max-age=31536000, immutable" always; access_log off; } # Per-extension caching for assets that live alongside HTML. CSS and JS # in this repo are not fingerprinted, so a 1-day cache with must-revalidate # keeps them responsive to deploys without forcing a fetch on every page. location ~* \.(?:css|js|mjs|woff2?|svg|webp|png|jpg|jpeg|ico)$ { add_header Cache-Control "public, max-age=86400, must-revalidate" always; access_log off; }