[{"data":1,"prerenderedAt":85},["ShallowReactive",2],{"hub:tools-nginx":3},{"path":4,"key":5,"title":6,"h1":7,"description":8,"crumbs":9,"blocks":18},"\u002Ftools\u002Fnginx\u002F","tools-nginx","Nginx Guides for Serving Static Sites","Nginx","Guides for serving static sites with Nginx: cache headers, Brotli and gzip precompression, Docker images, clean URLs and how it compares with Caddy.",[10,13,16],[11,12],"Home","\u002F",[14,15],"Tools","\u002Ftools\u002F",[17,4],"nginx",[19,22,24,27,40,42,66,68],{"k":20,"text":21},"p","Nginx is still the most common way to self-host a static site, and it is fast and frugal at it. It also has a few configuration traps that matter more for static sites than anything else: add_header directives that silently stop applying in nested locations, try_files patterns copied from single-page apps that turn every missing page into a soft 404, and on-the-fly compression doing work a build could do once.",{"k":20,"text":23},"The guides below cover a production configuration end to end: caching headers per file type, precompressed Brotli and gzip served with the static modules, a small unprivileged container image for container platforms, and a measured comparison with Caddy for teams deciding between the two.",{"k":25,"html":26},"fig","\u003Cfigure>\n\u003Csvg viewBox=\"0 0 760 383\" role=\"img\" aria-labelledby=\"hub-nginx-hero-title hub-nginx-hero-desc\" xmlns=\"http:\u002F\u002Fwww.w3.org\u002F2000\u002Fsvg\">\n  \u003Ctitle id=\"hub-nginx-hero-title\">Layers of a production Nginx configuration for a static site\u003C\u002Ftitle>\n  \u003Cdesc id=\"hub-nginx-hero-desc\">Four layers. URL mapping with try_files and a real 404. Caching headers per file type, repeated in each location. Precompressed Brotli and gzip files served by the static modules. TLS and security headers.\u003C\u002Fdesc>\n  \u003Crect x=\"0\" y=\"0\" width=\"760\" height=\"383\" fill=\"#ffffff\"\u002F>\n  \u003Cg style=\"font-family:system-ui, sans-serif;font-size:12px\">\n    \u003Crect x=\"40.0\" y=\"60.0\" width=\"440.0\" height=\"57.2\" rx=\"8\" fill=\"#f8fafc\" stroke=\"#d9e2ef\" style=\"stroke-width:1.5px\"\u002F>\n    \u003Cpath d=\"M260.0 119.2 L260.0 139.2\" fill=\"none\" stroke=\"#556071\" style=\"stroke-width:2px;marker-end:url(#hub-nginx-hero-arrow)\"\u002F>\n    \u003Crect x=\"40.0\" y=\"143.2\" width=\"440.0\" height=\"57.2\" rx=\"8\" fill=\"#1982c4\" opacity=\"0.14\" stroke=\"#1982c4\" style=\"stroke-width:1.5px\"\u002F>\n    \u003Cpath d=\"M260.0 202.4 L260.0 222.4\" fill=\"none\" stroke=\"#556071\" style=\"stroke-width:2px;marker-end:url(#hub-nginx-hero-arrow)\"\u002F>\n    \u003Crect x=\"40.0\" y=\"226.4\" width=\"440.0\" height=\"57.2\" rx=\"8\" fill=\"#8ac926\" opacity=\"0.2\" stroke=\"#5a8a16\" style=\"stroke-width:1.5px\"\u002F>\n    \u003Cpath d=\"M260.0 285.6 L260.0 305.6\" fill=\"none\" stroke=\"#556071\" style=\"stroke-width:2px;marker-end:url(#hub-nginx-hero-arrow)\"\u002F>\n    \u003Crect x=\"40.0\" y=\"309.6\" width=\"440.0\" height=\"57.2\" rx=\"8\" fill=\"#6a4c93\" opacity=\"0.14\" stroke=\"#6a4c93\" style=\"stroke-width:1.5px\"\u002F>\n    \u003Ctext x=\"380.0\" y=\"30.0\" fill=\"#1f2937\" style=\"font-size:16px;text-anchor:middle;font-weight:700\">What an Nginx static site configuration covers\u003C\u002Ftext>\n    \u003Ctext x=\"260.0\" y=\"86.4\" fill=\"#1f2937\" style=\"font-size:13px;text-anchor:middle;font-weight:700\">URL mapping\u003C\u002Ftext>\n    \u003Ctext x=\"260.0\" y=\"103.3\" fill=\"#556071\" style=\"font-size:11px;text-anchor:middle\">try_files + real 404\u003C\u002Ftext>\n    \u003Ctext x=\"504.0\" y=\"92.6\" fill=\"#556071\" style=\"font-size:11.5px;text-anchor:start\">no SPA fallback\u003C\u002Ftext>\n    \u003Ctext x=\"260.0\" y=\"169.5\" fill=\"#1f2937\" style=\"font-size:13px;text-anchor:middle;font-weight:700\">Caching headers\u003C\u002Ftext>\n    \u003Ctext x=\"260.0\" y=\"186.4\" fill=\"#556071\" style=\"font-size:11px;text-anchor:middle\">per file type\u003C\u002Ftext>\n    \u003Ctext x=\"504.0\" y=\"175.8\" fill=\"#556071\" style=\"font-size:11.5px;text-anchor:start\">repeated per location\u003C\u002Ftext>\n    \u003Ctext x=\"260.0\" y=\"252.7\" fill=\"#1f2937\" style=\"font-size:13px;text-anchor:middle;font-weight:700\">Precompression\u003C\u002Ftext>\n    \u003Ctext x=\"260.0\" y=\"269.6\" fill=\"#556071\" style=\"font-size:11px;text-anchor:middle\">brotli_static, gzip_static\u003C\u002Ftext>\n    \u003Ctext x=\"504.0\" y=\"259.0\" fill=\"#556071\" style=\"font-size:11.5px;text-anchor:start\">built once\u003C\u002Ftext>\n    \u003Ctext x=\"260.0\" y=\"335.9\" fill=\"#1f2937\" style=\"font-size:13px;text-anchor:middle;font-weight:700\">TLS and security\u003C\u002Ftext>\n    \u003Ctext x=\"260.0\" y=\"352.8\" fill=\"#556071\" style=\"font-size:11px;text-anchor:middle\">certificates, headers\u003C\u002Ftext>\n    \u003Ctext x=\"504.0\" y=\"342.2\" fill=\"#556071\" style=\"font-size:11.5px;text-anchor:start\">or Caddy instead\u003C\u002Ftext>\n  \u003C\u002Fg>\n  \u003Cdefs>\n    \u003Cmarker id=\"hub-nginx-hero-arrow\" viewBox=\"0 0 10 10\" refX=\"8\" refY=\"5\" markerWidth=\"7\" markerHeight=\"7\" orient=\"auto-start-reverse\">\n      \u003Cpath d=\"M0 0 L10 5 L0 10 z\" fill=\"#556071\"\u002F>\n    \u003C\u002Fmarker>\n  \u003C\u002Fdefs>\n\u003C\u002Fsvg>\n\u003Cfigcaption>Each layer has its own guide below.\u003C\u002Ffigcaption>\n\u003C\u002Ffigure>",{"k":28,"h":29,"items":30},"group","Core Web Vitals Optimization for SSGs",[31,36],{"t":32,"u":33,"d":34,"y":35},"Cache-Control Headers for Static Sites in Nginx","\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fcdn-caching-rules-for-ssgs\u002Fcache-control-headers-for-static-sites-in-nginx\u002F","Set Cache-Control in Nginx for a static site: immutable hashed assets, revalidated HTML, short-lived 404s and the add_header inheritance trap.","How-to",{"t":37,"u":38,"d":39,"y":35},"Precompressing Assets with Brotli and Zstd","\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fcss-and-javascript-asset-optimization\u002Fprecompressing-assets-with-brotli-and-zstd\u002F","Precompress static site output at build time with brotli 11 and zstd 19, serve the variants from Caddy, nginx or Cloudflare, and measure the transfer saving.",{"k":25,"html":41},"\u003Cfigure>\n\u003Csvg viewBox=\"0 0 760 295\" role=\"img\" aria-labelledby=\"hub-nginx-kinds-title hub-nginx-kinds-desc\" xmlns=\"http:\u002F\u002Fwww.w3.org\u002F2000\u002Fsvg\">\n  \u003Ctitle id=\"hub-nginx-kinds-title\">Number of nginx guides of each kind\u003C\u002Ftitle>\n  \u003Cdesc id=\"hub-nginx-kinds-desc\">Vertical bars: How-tos 6, Fixes 0, Comparisons 1 and Concepts 0.\u003C\u002Fdesc>\n  \u003Crect x=\"0\" y=\"0\" width=\"760\" height=\"295\" fill=\"#ffffff\"\u002F>\n  \u003Cg style=\"font-family:system-ui, sans-serif;font-size:12px\">\n    \u003Crect x=\"80.0\" y=\"76.0\" width=\"90.0\" height=\"170.0\" rx=\"3\" fill=\"#1982c4\" opacity=\"0.3\" stroke=\"#1982c4\" style=\"stroke-width:1px\"\u002F>\n    \u003Crect x=\"250.0\" y=\"243.0\" width=\"90.0\" height=\"3.0\" rx=\"3\" fill=\"#ff595e\" opacity=\"0.3\" stroke=\"#d83b41\" style=\"stroke-width:1px\"\u002F>\n    \u003Crect x=\"420.0\" y=\"217.7\" width=\"90.0\" height=\"28.3\" rx=\"3\" fill=\"#ffca3a\" opacity=\"0.45\" stroke=\"#a97b00\" style=\"stroke-width:1px\"\u002F>\n    \u003Crect x=\"590.0\" y=\"243.0\" width=\"90.0\" height=\"3.0\" rx=\"3\" fill=\"#6a4c93\" opacity=\"0.3\" stroke=\"#6a4c93\" style=\"stroke-width:1px\"\u002F>\n    \u003Cpath d=\"M30.0 246.0 L730.0 246.0\" fill=\"none\" stroke=\"#556071\" style=\"stroke-width:1.5px\"\u002F>\n    \u003Ctext x=\"380.0\" y=\"30.0\" fill=\"#1f2937\" style=\"font-size:16px;text-anchor:middle;font-weight:700\">nginx guides by kind\u003C\u002Ftext>\n    \u003Ctext x=\"125.0\" y=\"69.0\" fill=\"#1f2937\" style=\"font-size:12px;text-anchor:middle;font-weight:700\">6\u003C\u002Ftext>\n    \u003Ctext x=\"125.0\" y=\"264.0\" fill=\"#556071\" style=\"font-size:11.5px;text-anchor:middle\">How-tos\u003C\u002Ftext>\n    \u003Ctext x=\"295.0\" y=\"236.0\" fill=\"#b32b30\" style=\"font-size:12px;text-anchor:middle;font-weight:700\">0\u003C\u002Ftext>\n    \u003Ctext x=\"295.0\" y=\"264.0\" fill=\"#556071\" style=\"font-size:11.5px;text-anchor:middle\">Fixes\u003C\u002Ftext>\n    \u003Ctext x=\"465.0\" y=\"210.7\" fill=\"#1f2937\" style=\"font-size:12px;text-anchor:middle;font-weight:700\">1\u003C\u002Ftext>\n    \u003Ctext x=\"465.0\" y=\"264.0\" fill=\"#556071\" style=\"font-size:11.5px;text-anchor:middle\">Comparisons\u003C\u002Ftext>\n    \u003Ctext x=\"635.0\" y=\"236.0\" fill=\"#1f2937\" style=\"font-size:12px;text-anchor:middle;font-weight:700\">0\u003C\u002Ftext>\n    \u003Ctext x=\"635.0\" y=\"264.0\" fill=\"#556071\" style=\"font-size:11.5px;text-anchor:middle\">Concepts\u003C\u002Ftext>\n  \u003C\u002Fg>\n\u003C\u002Fsvg>\n\u003Cfigcaption>7 guides use nginx in depth; each is listed below under the section it belongs to.\u003C\u002Ffigcaption>\n\u003C\u002Ffigure>",{"k":28,"h":43,"items":44},"Production-Ready Deployment & CI\u002FCD for SSGs",[45,50,54,58,62],{"t":46,"u":47,"d":48,"y":49},"Nginx vs Caddy for Serving Static Sites","\u002Fproduction-ready-deployment-cicd-workflows\u002Fself-hosting-static-sites\u002Fnginx-vs-caddy-for-serving-static-sites\u002F","Nginx and Caddy compared serving the same static site: throughput, latency, memory, TLS automation, config size, compression and the mistakes each one invites.","Comparison",{"t":51,"u":52,"d":53,"y":35},"Brotli and Gzip Precompression Served by Nginx","\u002Fproduction-ready-deployment-cicd-workflows\u002Fself-hosting-static-sites\u002Fbrotli-and-gzip-precompression-served-by-nginx\u002F","Serve build-time Brotli and gzip files from Nginx with brotli_static and gzip_static, verify negotiation and Vary headers, and measure bytes and CPU saved.",{"t":55,"u":56,"d":57,"y":35},"Serving a Static Site From a Docker Container With Nginx","\u002Fproduction-ready-deployment-cicd-workflows\u002Fself-hosting-static-sites\u002Fserving-a-static-site-from-a-docker-container-with-nginx\u002F","Package a static site in a small Nginx container: multi-stage build, non-root user, read-only filesystem, health checks and running behind a proxy.",{"t":59,"u":60,"d":61,"y":35},"Serving a Static Site with Caddy","\u002Fproduction-ready-deployment-cicd-workflows\u002Fself-hosting-static-sites\u002Fserving-a-static-site-with-caddy\u002F","Host a static site on Caddy with automatic HTTPS, clean URLs, precompressed files, cache tiers, security headers and per-pull-request preview subdomains.",{"t":63,"u":64,"d":65,"y":35},"Serving a Static Site with Nginx","\u002Fproduction-ready-deployment-cicd-workflows\u002Fself-hosting-static-sites\u002Fserving-a-static-site-with-nginx\u002F","A production nginx config for a static site: clean URLs, two cache tiers, brotli, security headers that survive nested blocks, redirects, TLS and the 404 page.",{"k":25,"html":67},"\u003Cfigure>\n\u003Csvg viewBox=\"0 0 760 176\" role=\"img\" aria-labelledby=\"hub-nginx-topics-title hub-nginx-topics-desc\" xmlns=\"http:\u002F\u002Fwww.w3.org\u002F2000\u002Fsvg\">\n  \u003Ctitle id=\"hub-nginx-topics-title\">Topics with the most nginx guides\u003C\u002Ftitle>\n  \u003Cdesc id=\"hub-nginx-topics-desc\">Horizontal bars, largest first: Self-Hosting Static Sites on S3, Nginx and Caddy 5, CSS and JavaScript Asset Optimization 1 and CDN Caching Rules for SSGs 1.\u003C\u002Fdesc>\n  \u003Crect x=\"0\" y=\"0\" width=\"760\" height=\"176\" fill=\"#ffffff\"\u002F>\n  \u003Cg style=\"font-family:system-ui, sans-serif;font-size:12px\">\n    \u003Crect x=\"350.0\" y=\"65.0\" width=\"365.6\" height=\"20.0\" rx=\"3\" fill=\"#6a4c93\" opacity=\"0.3\" stroke=\"#6a4c93\" style=\"stroke-width:1px\"\u002F>\n    \u003Crect x=\"350.0\" y=\"99.0\" width=\"73.1\" height=\"20.0\" rx=\"3\" fill=\"#6a4c93\" opacity=\"0.3\" stroke=\"#6a4c93\" style=\"stroke-width:1px\"\u002F>\n    \u003Crect x=\"350.0\" y=\"133.0\" width=\"73.1\" height=\"20.0\" rx=\"3\" fill=\"#6a4c93\" opacity=\"0.3\" stroke=\"#6a4c93\" style=\"stroke-width:1px\"\u002F>\n    \u003Cpath d=\"M350.0 60.0 L350.0 158.0\" fill=\"none\" stroke=\"#556071\" style=\"stroke-width:1.5px\"\u002F>\n    \u003Ctext x=\"380.0\" y=\"30.0\" fill=\"#1f2937\" style=\"font-size:16px;text-anchor:middle;font-weight:700\">Where nginx comes up\u003C\u002Ftext>\n    \u003Ctext x=\"20.0\" y=\"79.2\" fill=\"#1f2937\" style=\"font-size:12px;text-anchor:start\">Self-Hosting Static Sites on S3, Nginx…\u003C\u002Ftext>\n    \u003Ctext x=\"723.6\" y=\"79.5\" fill=\"#1f2937\" style=\"font-size:12px;text-anchor:start;font-weight:700\">5\u003C\u002Ftext>\n    \u003Ctext x=\"20.0\" y=\"113.2\" fill=\"#1f2937\" style=\"font-size:12px;text-anchor:start\">CSS and JavaScript Asset Optimization\u003C\u002Ftext>\n    \u003Ctext x=\"431.1\" y=\"113.5\" fill=\"#1f2937\" style=\"font-size:12px;text-anchor:start;font-weight:700\">1\u003C\u002Ftext>\n    \u003Ctext x=\"20.0\" y=\"147.2\" fill=\"#1f2937\" style=\"font-size:12px;text-anchor:start\">CDN Caching Rules\u003C\u002Ftext>\n    \u003Ctext x=\"431.1\" y=\"147.5\" fill=\"#1f2937\" style=\"font-size:12px;text-anchor:start;font-weight:700\">1\u003C\u002Ftext>\n  \u003C\u002Fg>\n\u003C\u002Fsvg>\n\u003Cfigcaption>Topic pages give the wider context for each group; the numbers count only guides that use this tool in depth.\u003C\u002Ffigcaption>\n\u003C\u002Ffigure>",{"k":28,"h":69,"items":70},"Often used with nginx",[71,76,81],{"t":72,"u":73,"d":74,"y":75},"Caddy","\u002Ftools\u002Fcaddy\u002F","Self-hosted serving with automatic HTTPS.","3 shared guides",{"t":77,"u":78,"d":79,"y":80},"Eleventy","\u002Ftools\u002Feleventy\u002F","Incremental builds, image pipelines and the data cascade.","1 shared guides",{"t":82,"u":83,"d":84,"y":80},"Cloudflare","\u002Ftools\u002Fcloudflare\u002F","Pages and Workers hosting, cache rules and edge functions.",1790943190468]