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;
}
}