🧱 Nginx Security Headers Generator

Check the headers you want and copy the generated add_header lines for your Nginx server block.

The lines it produces

Ticked boxes become config text in your browser; nothing is fetched or tested. The five defaults give:

server_tokens off;
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;

Every line ends in always, which is what makes Nginx attach the header to error and redirect responses too. Without it, a 404 or a 500 goes out bare - and an error page is exactly where a framing or sniffing problem tends to land.

The inheritance rule that undoes this

The HSTS line belongs only in a server block that listens on 443. Browsers ignore the header over plain HTTP, so on your port 80 block it does nothing at all - send a redirect there instead.

Frequently asked questions

Why are my security headers missing on some URLs?

Look for an add_header inside the location that handles those URLs - a proxy pass or a static-files block that sets its own cache header is the usual culprit. Repeat the full set there, or move to more_set_headers from the headers-more module, which does merge.

Do I need to repeat these in every server block?

You can lift them into the http block and every server inherits them, subject to the same rule about child blocks. Keep HSTS out of that arrangement if any server block still answers on port 80 only.

Is X-Frame-Options still needed alongside a CSP?

Only for old browsers. Anything that understands frame-ancestors ignores X-Frame-Options completely, so if you set both, make sure they agree - SAMEORIGIN here means frame-ancestors 'self'.