How to add security headers (Nginx, Apache, Cloudflare)
If a scan just told you your site is missing HSTS, a Content-Security-Policy, X-Content-Type-Options or X-Frame-Options, this is the copy-paste fix. Add the safe ones first, test HTTPS before HSTS, and treat CSP with care. Configs for the three most common setups are below.
The headers, in the order to add them
| Header | What it stops | Risk of breaking your site |
|---|---|---|
| X-Content-Type-Options | MIME-sniffing attacks | None — add it now |
| X-Frame-Options | Clickjacking | Low (only if you embed yourself) |
| Referrer-Policy | URL/data leakage | None |
| Strict-Transport-Security (HSTS) | HTTPS downgrade / SSL-strip | Only if HTTPS isn't fully working |
| Content-Security-Policy | Cross-site scripting (XSS) | High if untuned — do last |
Nginx
Add inside the server { } block (or a shared snippets/ include), then reload:
add_header X-Content-Type-Options "nosniff" always;
add_header X-Frame-Options "DENY" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
add_header Content-Security-Policy "default-src 'self'; img-src 'self' data:; script-src 'self'; style-src 'self'" always;
The always keyword matters — without it, headers are skipped on error responses. Reload with nginx -t && systemctl reload nginx.
Apache
Enable headers (a2enmod headers), then in your vhost or .htaccess:
Header always set X-Content-Type-Options "nosniff"
Header always set X-Frame-Options "DENY"
Header always set Referrer-Policy "strict-origin-when-cross-origin"
Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains"
Header always set Content-Security-Policy "default-src 'self'; img-src 'self' data:; script-src 'self'; style-src 'self'"
Cloudflare
No server access needed. Go to your domain → Rules → Transform Rules → Modify Response Header, and add each header with "Set static". Cloudflare applies them at the edge for every response. This is the fastest option if you're on Cloudflare and can't touch the origin.
About HSTS and CSP — the two that bite
HSTS forces browsers to use HTTPS and remembers it. Only add it once your site works fully over HTTPS with no mixed content, or visitors can get locked out. Start with a small max-age, confirm, then raise to 31536000 (a year). Add preload only when you're certain — see what HSTS and preload actually do.
CSP is the most powerful and the most likely to break your own site by blocking scripts and styles. Start in report-only mode, watch what it would block, then tighten. The security headers guide covers a safe rollout.
The part people forget: headers regress
Here's the trap. You add these today, the scan goes green, everyone's happy — and three months later a redeploy, a stack migration, or a new CDN rule silently drops one of them. The site still works, so nobody notices, until a customer's security review flags it. Adding headers is a one-time job; keeping them is continuous. That's the whole reason to monitor: get an email the moment a header that was there disappears.
Confirm your headers landed — then keep them that way
Run your domain to see which headers are present now. Perimeter then re-checks daily and emails you the moment one regresses after a deploy.
Monitor headers continuously → · from $29/mo, no signup to check