Bird
Raised Fist0
Nginxdevops~15 mins

Adding response headers (add_header) in Nginx - Deep Dive

Choose your learning style10 modes available

Start learning this pattern below

Jump into concepts and practice - no test required

or
Recommended
Test this pattern10 questions across easy, medium, and hard to know if this pattern is strong
Overview - Adding response headers (add_header)
What is it?
Adding response headers in nginx means instructing the server to include extra information in the replies it sends to clients. These headers can control browser behavior, security settings, or caching rules. The add_header directive is the command used in nginx configuration to specify these headers. It helps customize how browsers and other clients handle the server's responses.
Why it matters
Without the ability to add response headers, websites would lack important controls for security, performance, and user experience. For example, you couldn't tell browsers to avoid caching sensitive data or to allow cross-site requests safely. This could lead to slower sites, security risks, or broken features. Adding headers lets site owners shape how their content is treated, improving safety and speed.
Where it fits
Before learning add_header, you should understand basic nginx configuration and how HTTP headers work. After mastering add_header, you can explore advanced security headers, caching strategies, and how to debug HTTP responses. This fits into the broader journey of web server management and web security.
Mental Model
Core Idea
Adding response headers with add_header is like attaching instruction notes to every package your server sends, guiding the receiver on how to handle it.
Think of it like...
Imagine sending a letter with a sticky note that says 'Handle with care' or 'Keep refrigerated.' The add_header directive sticks these notes (headers) onto your server's responses so browsers know what to do.
┌─────────────────────────────┐
│ Client Request              │
└─────────────┬───────────────┘
              │
              ▼
┌─────────────────────────────┐
│ nginx Server                │
│  add_header directive adds  │
│  extra headers to response  │
└─────────────┬───────────────┘
              │
              ▼
┌─────────────────────────────┐
│ Response with headers       │
│ (instructions for browser) │
└─────────────────────────────┘
Build-Up - 7 Steps
1
FoundationUnderstanding HTTP Response Headers
🤔
Concept: Learn what HTTP response headers are and why they matter.
HTTP response headers are pieces of information sent by a web server along with the content. They tell the browser things like content type, caching rules, or security policies. For example, a header can say 'Content-Type: text/html' to tell the browser to treat the response as a webpage.
Result
You understand that headers are extra data sent with web pages that control browser behavior.
Knowing what response headers do is essential before you can add or modify them effectively.
2
FoundationBasic nginx Configuration Structure
🤔
Concept: Understand where and how to write configuration directives in nginx.
nginx configuration files have blocks like 'http', 'server', and 'location' where you define settings. Directives like add_header go inside these blocks to apply to all or some responses. For example, inside a 'server' block, you can add headers for all responses from that server.
Result
You know where to place add_header commands to affect responses.
Understanding nginx config structure prevents misplacement of directives that would cause errors or no effect.
3
IntermediateUsing add_header Directive Syntax
🤔Before reading on: do you think add_header can add multiple headers in one line or requires separate lines? Commit to your answer.
Concept: Learn the syntax and usage rules of the add_header directive.
The add_header directive syntax is: add_header [always]; Each header must be added with its own add_header line. The optional 'always' parameter ensures the header is added even on error responses. For example: add_header X-Frame-Options "DENY"; add_header Cache-Control "no-store" always;
Result
You can write correct add_header lines to add custom headers.
Knowing the syntax and the 'always' flag helps you control when headers appear, avoiding common mistakes.
4
IntermediateScope and Inheritance of add_header
🤔Before reading on: do you think add_header directives in a parent block automatically apply inside nested blocks? Commit to your answer.
Concept: Understand how add_header behaves in nested nginx blocks and inheritance rules.
add_header directives apply only in the block where they are declared and do not inherit into nested blocks. If you define add_header in 'http' block, it applies globally. But if you define it in a 'location' block, it overrides or replaces headers from parent blocks. This means you must repeat add_header in nested blocks if you want headers there.
Result
You know how to place add_header directives to cover all desired responses.
Understanding scope prevents missing headers in some responses due to block nesting.
5
IntermediateControlling Headers on Error Responses
🤔Before reading on: do you think add_header adds headers to error pages by default? Commit to your answer.
Concept: Learn how to ensure headers are added even when nginx returns error pages.
By default, add_header does NOT add headers to responses with status codes 4xx or 5xx. To force headers on all responses, use the 'always' parameter: add_header X-Content-Type-Options "nosniff" always; This ensures security headers are present even on error pages.
Result
You can guarantee headers appear on all responses, improving security.
Knowing this prevents security holes where error pages lack important headers.
6
AdvancedConditional Headers with if and map
🤔Before reading on: do you think add_header supports conditions directly? Commit to your answer.
Concept: Explore how to add headers conditionally using nginx features like if and map.
add_header itself does not support conditions. To add headers only for certain requests, use 'if' blocks or 'map' variables. For example: map $http_user_agent $add_header_flag { default 0; "BadBot" 1; } server { if ($add_header_flag) { add_header X-Blocked "true"; } } This adds a header only if the user agent matches 'BadBot'.
Result
You can customize headers dynamically based on request properties.
Understanding this workaround allows flexible header control despite add_header limitations.
7
ExpertInteraction with HTTP/2 and Caching Proxies
🤔Before reading on: do you think add_header behaves identically with HTTP/1.1 and HTTP/2? Commit to your answer.
Concept: Learn how add_header works with HTTP/2 and caching proxies, and potential pitfalls.
HTTP/2 multiplexes requests, but add_header works the same way adding headers to each response. However, caching proxies may ignore or strip some headers unless properly configured. Also, some headers like 'Cache-Control' affect caching behavior and must be set carefully to avoid stale content. Understanding how add_header interacts with these layers is crucial for production.
Result
You can avoid subtle bugs with headers in modern web environments.
Knowing these interactions prevents performance and security issues in complex deployments.
Under the Hood
When nginx processes a client request, it builds the HTTP response including status, body, and headers. The add_header directive tells nginx to insert specified header lines into the response before sending it out. Internally, nginx stores these headers in a data structure linked to the response. The 'always' flag modifies the logic to include headers even on error responses, overriding default behavior that skips headers on errors.
Why designed this way?
nginx was designed for high performance and flexibility. add_header was made simple to add static headers efficiently without complex logic. The default behavior to skip headers on errors avoids sending misleading headers, but the 'always' flag was added later to meet security needs. The lack of direct conditional support keeps the core simple, pushing complex logic to other directives like 'if' and 'map'.
┌───────────────┐
│ Client sends  │
│ HTTP request  │
└──────┬────────┘
       │
       ▼
┌─────────────────────────────┐
│ nginx request processing    │
│ - Matches server/location   │
│ - Prepares response headers │
│ - Applies add_header rules  │
└──────┬──────────────────────┘
       │
       ▼
┌─────────────────────────────┐
│ Response sent with headers   │
│ including add_header entries │
└─────────────────────────────┘
Myth Busters - 4 Common Misconceptions
Quick: Does add_header add headers to all responses including errors by default? Commit yes or no.
Common Belief:add_header always adds headers to every response, no matter the status code.
Tap to reveal reality
Reality:By default, add_header does NOT add headers to responses with status codes 4xx or 5xx unless the 'always' parameter is used.
Why it matters:Without 'always', security headers might be missing on error pages, exposing vulnerabilities or inconsistent behavior.
Quick: If you add_header in a parent block, does it automatically apply inside nested location blocks? Commit yes or no.
Common Belief:Headers added in a parent block automatically apply to all nested blocks and locations.
Tap to reveal reality
Reality:add_header directives do NOT inherit into nested blocks; you must repeat them in each block where you want headers.
Why it matters:Missing headers in nested locations can cause security or caching issues that are hard to debug.
Quick: Can you add multiple headers in one add_header directive line? Commit yes or no.
Common Belief:You can add several headers in one add_header line separated by spaces.
Tap to reveal reality
Reality:Each add_header directive adds only one header; multiple headers require multiple add_header lines.
Why it matters:Trying to add multiple headers in one line causes configuration errors or missing headers.
Quick: Does add_header support conditional logic directly? Commit yes or no.
Common Belief:add_header supports conditions to add headers only for certain requests.
Tap to reveal reality
Reality:add_header does not support conditions; you must use other nginx features like 'if' or 'map' to control when headers are added.
Why it matters:Assuming direct conditions leads to failed configurations and inability to customize headers dynamically.
Expert Zone
1
add_header directives are evaluated at response time, so variables in header values can be used but require careful syntax.
2
The 'always' parameter was introduced in nginx 1.7.5; older versions do not support it, causing silent header omissions on errors.
3
Headers added by add_header can be overridden or removed by proxy servers or browsers caching policies, so testing end-to-end is essential.
When NOT to use
Avoid using add_header for dynamic or complex header logic; instead, use Lua scripts with ngx_http_lua_module or external middleware. Also, do not rely on add_header alone for security; combine with proper server and application configurations.
Production Patterns
In production, add_header is commonly used to add security headers like X-Frame-Options, Content-Security-Policy, and caching controls. It is often combined with conditional logic using map to tailor headers per client or path. Headers are tested with tools like curl or browser DevTools to ensure correct delivery.
Connections
HTTP Headers
builds-on
Understanding HTTP headers is essential to know what add_header modifies and why those headers matter for web communication.
Web Security
builds-on
Adding headers like Content-Security-Policy or X-Frame-Options directly impacts web security, making add_header a key tool in defense strategies.
Postal Service Instructions
analogy
Just like postal instructions guide how a package is handled, response headers guide browsers on handling content, showing how communication protocols rely on metadata.
Common Pitfalls
#1Headers missing on error pages
Wrong approach:add_header X-Content-Type-Options "nosniff";
Correct approach:add_header X-Content-Type-Options "nosniff" always;
Root cause:Not using the 'always' flag causes headers to be skipped on 4xx/5xx responses.
#2Headers not applied in nested location blocks
Wrong approach:http { add_header X-Test "value"; server { location / { # no add_header here } } }
Correct approach:http { add_header X-Test "value"; server { location / { add_header X-Test "value"; } } }
Root cause:add_header does not inherit into nested blocks; must be repeated.
#3Trying to add multiple headers in one line
Wrong approach:add_header X-Frame-Options "DENY" Cache-Control "no-store";
Correct approach:add_header X-Frame-Options "DENY"; add_header Cache-Control "no-store";
Root cause:Each add_header directive adds only one header; multiple headers need separate lines.
Key Takeaways
The add_header directive in nginx lets you attach extra information to HTTP responses that control browser behavior and security.
Headers added with add_header do not apply to error responses unless you use the 'always' parameter.
add_header directives do not inherit into nested blocks, so you must add them explicitly where needed.
You cannot add multiple headers in one add_header line; each header requires its own directive.
For conditional header logic, use nginx features like 'if' or 'map' since add_header itself lacks condition support.

Practice

(1/5)
1. What is the main purpose of the add_header directive in nginx?
easy
A. To configure server listening ports
B. To add extra information to HTTP responses
C. To redirect HTTP requests to HTTPS
D. To define server root directory

Solution

  1. Step 1: Understand the role of add_header

    The add_header directive is used to add extra HTTP headers to responses sent by nginx.
  2. Step 2: Compare with other options

    Redirecting requests, configuring ports, and defining root directories are unrelated to adding headers.
  3. Final Answer:

    To add extra information to HTTP responses -> Option B
  4. Quick Check:

    add_header adds headers [OK]
Hint: Remember: add_header adds info to HTTP responses [OK]
Common Mistakes:
  • Confusing add_header with redirect directives
  • Thinking add_header sets server ports
  • Assuming add_header changes root directory
2. Which of the following is the correct syntax to add a custom header named X-Custom-Header with value MyValue in nginx?
easy
A. add_header "X-Custom-Header: MyValue";
B. add_header X-Custom-Header = MyValue;
C. add_header X-Custom-Header MyValue;
D. add_header X-Custom-Header => MyValue;

Solution

  1. Step 1: Recall nginx add_header syntax

    The correct syntax is add_header name value; without extra symbols like = or =>.
  2. Step 2: Validate each option

    add_header X-Custom-Header MyValue; matches correct syntax. Options A, C, and D use invalid syntax with quotes or symbols.
  3. Final Answer:

    add_header X-Custom-Header MyValue; -> Option C
  4. Quick Check:

    Syntax is add_header name value; [OK]
Hint: Use simple syntax: add_header name value; [OK]
Common Mistakes:
  • Adding quotes around header name and value
  • Using = or => symbols incorrectly
  • Missing semicolon at the end
3. Given this nginx config snippet inside a server block:
add_header X-Test "Hello";

location /error {
  return 404;
}

What happens when a client requests /error?
medium
A. The server throws a configuration error
B. The response includes header X-Test: Hello with 404 status
C. The response returns 200 OK with X-Test header
D. The response returns 404 without X-Test header

Solution

  1. Step 1: Understand default add_header behavior on errors

    By default, add_header does NOT add headers on error responses like 404.
  2. Step 2: Analyze the config and request

    The location returns 404, so X-Test header is omitted unless always is used.
  3. Final Answer:

    The response returns 404 without X-Test header -> Option D
  4. Quick Check:

    Headers not added on errors without always [OK]
Hint: Headers need 'always' to appear on error responses [OK]
Common Mistakes:
  • Assuming headers always appear on error responses
  • Confusing return status with header presence
  • Expecting 200 OK instead of 404
4. You want to add a security header X-Frame-Options: DENY to all responses including errors. Which nginx config fixes this incorrect snippet?
add_header X-Frame-Options DENY;

But headers are missing on 404 pages.
medium
A. Change to add_header X-Frame-Options DENY always;
B. Add always; on a separate line
C. Use add_header X-Frame-Options DENY on_error;
D. Move add_header inside error_page block

Solution

  1. Step 1: Identify why headers are missing on errors

    By default, add_header skips error responses unless always is added.
  2. Step 2: Fix syntax to include headers on all responses

    Adding always on the same line ensures headers appear even on errors.
  3. Final Answer:

    Change to add_header X-Frame-Options DENY always; -> Option A
  4. Quick Check:

    Use 'always' on same line to add headers on errors [OK]
Hint: Add 'always' on same line to include headers on errors [OK]
Common Mistakes:
  • Placing 'always' on a separate line
  • Using invalid keywords like 'on_error'
  • Moving add_header inside unrelated blocks
5. You want to add two headers: Cache-Control: no-store for all responses, and Strict-Transport-Security: max-age=31536000 only for successful responses (status 200-299). Which nginx config achieves this correctly?
hard
A. add_header Cache-Control no-store always; add_header Strict-Transport-Security max-age=31536000;
B. add_header Cache-Control no-store; add_header Strict-Transport-Security max-age=31536000 always;
C. add_header Cache-Control no-store; add_header Strict-Transport-Security max-age=31536000;
D. add_header Cache-Control no-store always; add_header Strict-Transport-Security max-age=31536000 always;

Solution

  1. Step 1: Understand 'always' effect on headers

    The always flag makes headers appear on all responses including errors.
  2. Step 2: Apply 'always' only to Cache-Control

    We want Cache-Control on all responses, so add always there. For Strict-Transport-Security, omit always to restrict to 2xx responses.
  3. Final Answer:

    add_header Cache-Control no-store always; add_header Strict-Transport-Security max-age=31536000; -> Option A
  4. Quick Check:

    'always' for all responses, omit for success-only [OK]
Hint: Use 'always' only for headers needed on errors [OK]
Common Mistakes:
  • Adding 'always' to all headers causing unwanted error headers
  • Omitting 'always' for headers needed on errors
  • Misunderstanding which responses get headers without 'always'