← back

NGINX Might Be Silently Dropping Your Headers

October 3, 2026

The add_header directive is how most NGINX configs set security headers. It's also easy to get wrong.

For example, here's a config that sets a Content Security Policy (CSP) at the server level and a Cache-Control header for /dashboard/:

server {
    listen 80;
    server_name example.com;
    root /var/www/html;

    add_header Content-Security-Policy "default-src 'self';" always;

    location /dashboard/ {
        add_header Cache-Control "no-store" always;
    }
}

Looks fine, right? It isn't. Every response under /dashboard/ is missing the CSP.

This is the default behavior, and it might catch you by surprise. According to NGINX's documentation:

There could be several add_header directives. These directives are inherited from the previous configuration level if and only if there are no add_header directives defined on the current level.

A block that defines any add_header ignores all add_header directives from the levels above it. They're only inherited when the block defines none of its own.

NGINX added the add_header_inherit directive in version 1.29.3 (October 28, 2025). You must set it to merge to append headers from the levels above instead of dropping them:

server {
    listen 80;
    server_name example.com;
    root /var/www/html;

    # Inherit add_header directives from the levels above.
    add_header_inherit merge;

    add_header Content-Security-Policy "default-src 'self';" always;

    location /dashboard/ {
        add_header Cache-Control "no-store" always;
    }
}

Now /dashboard/ returns both the CSP and Cache-Control.

On versions before 1.29.3, the workaround was to keep the shared headers in a snippet and include them into every block with include. This wasn't very convenient and I'm surprised they only added add_header_inherit in 2025.

# headers.conf
add_header Content-Security-Policy "default-src 'self';" always;
# nginx.conf
server {
    listen 80;
    server_name example.com;
    root /var/www/html;

    include headers.conf;

    location /dashboard/ {
        include headers.conf;
        add_header Cache-Control "no-store" always;
    }
}