# The live socket carries its credential as `?token=`, and so does a password # reset link, which then rides along as the Referer of everything that page # loads. nginx's own format logs both as sent; this one masks the value. map $request $request_masked { "~^(?.*?[?&][\w-]*token=)[^&\s]*(?.*)$" "${request_head}***${request_tail}"; default $request; } map $http_referer $referer_masked { "~^(?.*?[?&][\w-]*token=)[^&\s]*(?.*)$" "${referer_head}***${referer_tail}"; default $http_referer; } log_format masked '$remote_addr - $remote_user [$time_local] "$request_masked" ' '$status $body_bytes_sent "$referer_masked" ' '"$http_user_agent" "$http_x_forwarded_for"'; server { listen 80; access_log /var/log/nginx/access.log masked; # nginx's mime.types predates the manifest, so without this it goes out as # application/octet-stream. types { application/manifest+json webmanifest; } include /etc/nginx/mime.types; # The bundle is ~770 kB of JavaScript and ~85 kB of CSS, and nginx's base # image ships gzip commented out — so every first load shipped all of it # uncompressed. Roughly a third of the bytes with this on. gzip on; gzip_vary on; gzip_min_length 1024; gzip_proxied any; gzip_types application/javascript application/json application/manifest+json application/wasm image/svg+xml text/css text/plain; include /etc/nginx/security-headers.conf; # The fallback is the last argument, so it is an internal redirect to the # exact location below and `/` and every SPA route get its no-cache too; as # a middle argument it was served from here, without one. location / { root /usr/share/nginx/html; index index.html index.htm; try_files $uri /index.html; } # Vite puts a content hash in every asset's name, so one can never change # under its URL. Without this each of the ~50 of them cost a 304 round trip # on every reload. location /assets/ { root /usr/share/nginx/html; include /etc/nginx/security-headers.conf; add_header Cache-Control "public, max-age=31536000, immutable"; } # The one file that must not be cached: it is what names the current # assets, so a stale copy pins the browser to the previous build. location = /index.html { root /usr/share/nginx/html; include /etc/nginx/security-headers.conf; add_header Cache-Control "no-cache"; } include /etc/nginx/extra-conf.d/*.conf; }