server { listen 80; # 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; location / { root /usr/share/nginx/html; index index.html index.htm; try_files $uri /index.html =404; } # 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; 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; add_header Cache-Control "no-cache"; } include /etc/nginx/extra-conf.d/*.conf; }