By server

All Security Headers for Nginx (One Server Block)

3 min read

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.

Open the full version (with copy buttons) ↗

← All recipes