Caddy snippet for security headers in one place
Caddy’s (name) { ... } snippets are the feature I miss most when I am forced back to nginx. I keep a headers.caddy file with the baseline security headers for every site I host, and import it into each site block. When I want to tighten CSP for one site, I override that single header inside the site and leave the rest alone.
# /etc/caddy/headers.caddy
(security_headers) {
header {
# Force HTTPS in supporting browsers for 1 year.
Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"
# No MIME sniffing, no framing by default, no referrer to non-HTTPS.
X-Content-Type-Options "nosniff"
X-Frame-Options "DENY"
Referrer-Policy "strict-origin-when-cross-origin"
# Disable a pile of browser features I do not use.
Permissions-Policy "camera=(), microphone=(), geolocation=(), interest-cohort=()"
# Hide Caddy's version banner from 200 and error responses.
-Server
}
}
And in a site block:
example.com {
import security_headers
# Per-site CSP override, since CSP really depends on what you serve.
header Content-Security-Policy "default-src 'self'; img-src 'self' data:; style-src 'self' 'unsafe-inline'"
root * /srv/www/example
file_server
}
caddy fmt --overwrite will keep the indentation sane. See also /posts/caddy-vs-nginx-switch/.