58 lines
1.9 KiB
Plaintext
58 lines
1.9 KiB
Plaintext
# nginx config for the static teaching site, baked into the image.
|
|
# Base: nginxinc/nginx-unprivileged (uid 101, listens on 8080).
|
|
# Read-only rootfs in k8s: /tmp and /var/cache/nginx are emptyDir mounts.
|
|
|
|
server {
|
|
listen 8080;
|
|
server_name _;
|
|
root /usr/share/nginx/html;
|
|
index index.html;
|
|
|
|
server_tokens off;
|
|
|
|
# Behind the Cloudflare Tunnel on :443 while nginx listens on :8080 — without these,
|
|
# nginx emits ABSOLUTE redirects to http://host:8080/... and breaks every link.
|
|
absolute_redirect off;
|
|
port_in_redirect off;
|
|
|
|
include /etc/nginx/security-headers.conf;
|
|
|
|
# ---- Caching -------------------------------------------------------------
|
|
# Scene images are content-hashed at build time → safe to cache hard.
|
|
location /assets/ {
|
|
include /etc/nginx/security-headers.conf;
|
|
expires 1y;
|
|
add_header Cache-Control "public, immutable" always;
|
|
}
|
|
|
|
# Scripts are NOT fingerprinted yet — revalidate so a deploy actually propagates.
|
|
location ~* \.js$ {
|
|
include /etc/nginx/security-headers.conf;
|
|
add_header Cache-Control "no-cache" always;
|
|
}
|
|
|
|
location ~* \.html$ {
|
|
include /etc/nginx/security-headers.conf;
|
|
add_header Cache-Control "no-cache" always;
|
|
}
|
|
|
|
# Probe endpoint - no file IO, no cache headers, invisible to the CDN.
|
|
location = /healthz {
|
|
access_log off;
|
|
return 200 "ok";
|
|
}
|
|
|
|
# ---- Routing -------------------------------------------------------------
|
|
location / {
|
|
try_files $uri $uri/ $uri.html =404;
|
|
}
|
|
|
|
# ---- Compression ---------------------------------------------------------
|
|
# WebP/PNG are already compressed — gzipping them burns CPU for nothing.
|
|
gzip on;
|
|
gzip_comp_level 6;
|
|
gzip_min_length 1024;
|
|
gzip_types text/plain text/css application/javascript application/json image/svg+xml;
|
|
gzip_vary on;
|
|
}
|