A solid baseline for almost any site: HSTS, no MIME sniffing, no framing, a tight referrer policy, and locked-down browser features. (Content-Security-Policy is the one header you must tune per site — see the CSP recipe — so it’s noted but not forced on here.)
Nginx
In your server { } block. The always flag matters (sends on error responses too):
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-Frame-Options "SAMEORIGIN" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
add_header Permissions-Policy "geolocation=(), camera=(), microphone=()" always;
# add_header Content-Security-Policy "default-src 'self'" always; # tune first — see CSP recipe
Nginx gotcha: if a
locationblock has its ownadd_header, it drops all inherited ones. Repeat the headers there, or set them once atserverlevel with noadd_headerinside locations.
Apache (mod_headers)
In the vhost or .htaccess (needs a2enmod headers):
Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains"
Header always set X-Content-Type-Options "nosniff"
Header always set X-Frame-Options "SAMEORIGIN"
Header always set Referrer-Policy "strict-origin-when-cross-origin"
Header always set Permissions-Policy "geolocation=(), camera=(), microphone=()"
Caddy (v2)
Inside the site block:
header {
Strict-Transport-Security "max-age=31536000; includeSubDomains"
X-Content-Type-Options "nosniff"
X-Frame-Options "SAMEORIGIN"
Referrer-Policy "strict-origin-when-cross-origin"
Permissions-Policy "geolocation=(), camera=(), microphone=()"
}
Cloudflare Pages / Netlify (_headers)
A _headers file at the site root:
/*
Strict-Transport-Security: max-age=31536000; includeSubDomains
X-Content-Type-Options: nosniff
X-Frame-Options: SAMEORIGIN
Referrer-Policy: strict-origin-when-cross-origin
Permissions-Policy: geolocation=(), camera=(), microphone=()
Verify
curl -sI https://yourdomain.com | grep -iE 'strict-transport|x-content-type|x-frame|referrer-policy|permissions-policy'
Before HSTS in production: make sure HTTPS works on every subdomain first — includeSubDomains
forces them all onto HTTPS, and HSTS is cached by browsers for the full max-age. See the HSTS
recipe for preload and the rollback caveats.