100% Free Forever
AI-Powered Learning
Industry Expert Content
Certificates & Badges
Learn At Your Own Pace
DevOps

Nginx Security Headers

Learn how to configure HTTP response headers in Nginx to protect users from clickjacking, MIME-sniffing, XSS, and insecure transport.

SecurityIntermediate9 min readJul 10, 2026
Analogies

Why Security Headers Matter

HTTP security headers are instructions your Nginx server sends back with every response, telling the browser how to behave defensively when it renders your site. They don't change your application code at all; they simply add a layer of policy enforcement at the edge, closing off entire classes of attacks like clickjacking, MIME-type confusion, and script injection before they can succeed.

🏏

Cricket analogy: Think of security headers like the third umpire's protocols in cricket - the on-field umpire (your app) makes the call, but the third umpire (the browser) is instructed to double-check specific things like no-balls and boundary lines before the result stands.

Core Headers to Configure

The Strict-Transport-Security (HSTS) header tells the browser to only ever connect to your domain over HTTPS for a specified duration, preventing SSL-stripping attacks where a man-in-the-middle downgrades the connection to plain HTTP. X-Content-Type-Options: nosniff stops the browser from guessing a file's MIME type based on its content, which closes off attacks where a malicious file disguised as an image is executed as a script.

🏏

Cricket analogy: HSTS is like a batsman who, once he's decided to play only on true, well-covered pitches, refuses to walk out onto a substandard wicket even if the ground staff insists it's fine - the decision is locked in ahead of time.

nginx
# /etc/nginx/conf.d/security-headers.conf
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" 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=(), microphone=(), camera=()" always;
add_header Content-Security-Policy "default-src 'self'; script-src 'self'; object-src 'none'; frame-ancestors 'self';" always;

The always flag on add_header ensures the header is sent even on error responses (4xx/5xx), which is easy to forget and leaves error pages unprotected.

Content-Security-Policy in Depth

Content-Security-Policy (CSP) is the most powerful but also the most fragile header, because it whitelists exactly which sources scripts, styles, images, and frames may load from. A misconfigured default-src 'self' will silently break any inline script or third-party widget your site relies on, so CSP rollout should start in Content-Security-Policy-Report-Only mode to observe violations before enforcing them.

🏏

Cricket analogy: It's like a captain setting an extremely tight fielding ring for a death-over specialist - highly effective at stopping boundaries, but if misjudged it also chokes off the singles your own bowler needs to rotate strike.

Never deploy Content-Security-Policy directly to production without first testing in Content-Security-Policy-Report-Only mode - an overly strict policy can silently break login forms, payment widgets, or analytics scripts.

  • add_header directives in Nginx inject response headers that instruct the browser to defend itself, without requiring any application code changes.
  • Always use the always flag so headers are also sent on error responses (4xx/5xx), not just 2xx.
  • Strict-Transport-Security (HSTS) forces HTTPS-only connections for a specified max-age, preventing SSL-stripping downgrade attacks.
  • X-Content-Type-Options: nosniff stops browsers from MIME-sniffing content into an unintended, potentially executable type.
  • X-Frame-Options and frame-ancestors in CSP prevent clickjacking by controlling whether your site can be embedded in an iframe.
  • Content-Security-Policy is the most powerful header but also the easiest to misconfigure; roll it out in Report-Only mode first.
  • Headers set in a server block are not automatically inherited the same way in nested location blocks once any add_header appears in that location - all headers must be repeated.

Practice what you learned

Was this page helpful?

Topics covered

#DevOps#NginxStudyNotes#NginxSecurityHeaders#Nginx#Security#Headers#Matter#StudyNotes#SkillVeris#ExamPrep