A complete Nginx baseline. Paste into your server { } block. Every header uses always so it’s
also sent on error responses.
server {
# ... your existing listen / server_name / ssl config ...
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 Cross-Origin-Opener-Policy "same-origin" always;
# Tune CSP per site — start report-only (see the CSP recipe):
add_header Content-Security-Policy "default-src 'self'; object-src 'none'; base-uri 'self'; frame-ancestors 'self'" always;
}
Hide the version string in the http { } block:
http {
server_tokens off;
}
The inheritance trap
If any location in this server has its own add_header, it loses all of the above. Repeat
them in that location, or switch to the headers-more module which inherits:
location /api/ {
more_set_headers "Cache-Control: no-store"; # security headers above still apply
}
Test and reload
sudo nginx -t && sudo systemctl reload nginx
Verify
curl -sI https://yourdomain.com
curl -sI https://yourdomain.com/nonexistent # error pages must carry headers too (that's what 'always' is for)
See the per-header recipes to tune each value, and the CSP recipe before enabling
Content-Security-Policy in enforcing mode.