Security headers are a handful of lines your server sends with every page. They tell browsers to always use HTTPS, refuse to guess file types, block your site from being framed by scammers (clickjacking), and limit what data leaks to other sites. Most take one line of config, and missing ones are among the first things scanners and security reviewers flag.
curl -sI https://yourdomain.com
Or open your site, press F12, go to the Network tab, reload, click the first request, and read Response Headers. Check the final URL your visitors land on, after any redirect from http:// or www.
| Header | Good starting value | What it protects against |
|---|---|---|
Strict-Transport-Security | max-age=31536000; includeSubDomains | Downgrades to insecure HTTP |
X-Content-Type-Options | nosniff | Browsers running a file as the wrong type |
X-Frame-Options | DENY or SAMEORIGIN | Clickjacking via hidden iframes |
Referrer-Policy | strict-origin-when-cross-origin | Full URLs (and anything in them) leaking to other sites |
Permissions-Policy | camera=(), microphone=(), geolocation=() | Embedded scripts using device features |
Content-Security-Policy | Site-specific; start in report-only | Injected scripts (XSS) |
X-XSS-Protection is deprecated. You don't need to add it, and some graders now count it against you.
Vercel: in vercel.json at your project root, then redeploy:
{
"headers": [
{
"source": "/(.*)",
"headers": [
{ "key": "Strict-Transport-Security", "value": "max-age=31536000; includeSubDomains" },
{ "key": "X-Content-Type-Options", "value": "nosniff" },
{ "key": "X-Frame-Options", "value": "DENY" },
{ "key": "Referrer-Policy", "value": "strict-origin-when-cross-origin" },
{ "key": "Permissions-Policy", "value": "camera=(), microphone=(), geolocation=()" }
]
}
]
}Netlify: a _headers file or a [[headers]] block in netlify.toml. Full copy-paste config is in our Netlify security headers guide.
Cloudflare: under Rules, create a Response Header Transform Rule that sets each header for all incoming requests. This works no matter where your site is hosted.
nginx: inside your server block:
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always; 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;
Apache (.htaccess with mod_headers on):
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"
X-Content-Type-Options, X-Frame-Options, and Referrer-Policy: seconds to add, almost never break anything. (Use SAMEORIGIN if your own site embeds its pages in iframes.)Strict-Transport-Security: once HTTPS works on the domain and every subdomain. Not sure? Start with max-age=300 and raise it after a day.Content-Security-Policy: last. Deploy it as Content-Security-Policy-Report-Only first, fix what it reports, then switch to enforcing, or you can break analytics, chat widgets, and payment forms.Re-run curl -sI after deploying and confirm each header appears once. Duplicate headers with different values (for example, one set by your app and one by your host) are a common cause of confusing results.
Want the answer without the terminal? Scan your site free with SiteShield. It checks every one of these headers, plus HTTPS and email security in under a minute and shows your score and every issue found. If you'd rather skip the trial and error, the $14 fix bundle gives you copy-paste fixes written for your exact site.
SiteShield by Telekeen · Telekeen Communications