Javed A. Butt

@javedAB
22 Followers
1 Following
283 Posts

The one header I didn't add yet: CSP.

For sites that render untrusted input it mitigates an active surface. For a static site it guards against rarer-but-bigger events: a compromised analytics script, a poisoned CDN, a future change that adds an input path.

Astro 6 added an integration for what it emits; iframes, external fonts, and third-party services stay manual. Will inshallah follow when the audit fits.

#CSP #WebSecurity #Astro #StaticSite

Enabled HSTS with includeSubDomains and preload.

The cost is real and one-way: every current and future subdomain must serve HTTPS or become unreachable. Removal from the preload list is in browser-release hands, not yours.

Accepted because the site is HTTPS-only by intent and Caddy provisions certs for every subdomain automatically via Let's Encrypt.

#HSTS #WebSecurity #Caddy #SelfHosting

Skipped Permissions-Policy on the static site.

It disables browser APIs (camera, mic, geolocation) the site doesn't use. Disabling something you're not using doesn't protect you from anything.

Embedding YouTube with fullscreen would also mean carving exceptions back in. More config for zero gain.

The scanner score drops one notch. The site is no less safe.

#WebSecurity #Caddy #StaticSite

Most cache misconfiguration is not carelessness, it's a missing handshake.

Your build encodes assumptions: hashed filenames mean the URL changes whenever the content changes. The web server has to know that, or the assumption stays unused.

If the config doesn't reflect what the build produces, the framework's work gets quietly undone at the last layer of the chain.

#WebPerf #Caching #StaticSite #Astro #Caddy

Generic defaults cover the hard parts. The parts only you can configure (caching, headers, redirects) are the parts that signal intentionality, because only you know what your framework outputs and what your site actually needs.

Full write-up, including each rejected header and why:
https://javedab.com/en/pub/coding/web/astro-caddy-config/

Caddy Config for Astro Static Sites

Security headers, cache strategy, and compression for an Astro site on Caddy. What to add, what to skip, and why each decision depends on your build output.

Javed Arshad Butt

Three small things that quietly matter:

- www to apex 301 (Google sees one domain, not two)
- encode zstd gzip (safety net for files that slip past CI compression)
- ACME email (silent TLS-renewal failure becomes a warning before customers notice)

Cache strategy follows the build output:

- _astro/* (hashed filenames): immutable, 1 year
- HTML (stable URLs): no-cache, revalidate every visit
- Favicons: 1 hour, must-revalidate

Hashed names mean the URL changes whenever the content changes. So the browser can cache hashed assets forever, safely.

Four headers evaluated and skipped:

- Referrer-Policy (already the major browser default)
- Permissions-Policy (blocks browser APIs the site doesn't use)
- Cross-Origin-Opener-Policy (no auth, no tokens, no popups)
- CSP (deferred until the audit fits the schedule)

Adding them would have scored higher on scanners. None would have made the site safer.

Three security headers, three real attack vectors:

- Strict-Transport-Security (blocks HTTPS-to-HTTP downgrade on public WiFi)
- X-Content-Type-Options nosniff (no MIME-type guessing)
- X-Frame-Options DENY (no iframe embedding, no clickjacking)

No others. Static site, no auth, no forms.

Your site loads. From the outside it works. But: do returning visitors re-download everything on every click? Can the connection be downgraded from HTTPS to HTTP on public WiFi? Does your homepage count as one site in Google's eyes, or two?

For most static sites: no, yes, and yes. The web server config is the last layer most setups never touch.

#Astro #Caddy #WebPerf #SelfHosting #StaticSite