When it comes to server configuration, especially in the context of NGINX, the devil is often in the details. One such detail is the management of HTTP headers. Although NGINX’s native add_header
directive is commonly used for this purpose, it comes with a particular limitation concerning inheritance that could lead to unintended behavior. The more_set_headers
directive, part of the third-party ngx_http_headers_more_module
, solves this problem elegantly. This article will focus exclusively on this crucial difference, illustrating why more_set_headers
might be a better fit for complex configurations.
The Inheritance Problem with add_header
In NGINX, configurations are often set up in a hierarchical manner using various blocks like server
, location
, and even nested location
blocks. This is where add_header
runs into problems. If you define a header at a higher-level block using add_header
, and then again in a nested block, the latter will “overwrite” the former entirely, ignoring any parent settings.
Consider this example:
server {
add_header X-Server "NGINX";
location / {
add_header X-Location "Root";
}
}
In this configuration, if you access a URL that matches the location /
block, only the X-Location: Root
header will be in the HTTP response. The X-Server: NGINX
header set in the parent server block will be missing, overridden by the inner location block. This often leads to unexpected behavior and makes managing headers in large configurations challenging.
Why this is happening, is because add_header
belongs to a set of NGINX directives which represent array-like data. To solve it in NGINX non-intuitive way, you have to repeat previous array members if you want all its data to be applied. Here’s configuration that will work as expected:
server {
add_header X-Server "NGINX";
location / {
add_header X-Server "NGINX";
add_header X-Location "Root";
}
}
In this case, the X-Server
header will be applied for all requests, as expected. This however, illustrates the non-intuitive behavior of this core NGINX directives, and how it makes configuring NGINX troublesome for even simple scenarios.
The Inheritance Solution with more_set_headers
directive
The more_set_headers
directive remedies the inheritance issue and non-intuitive behavior of the core NGINX directive. When you set a header with it once in a parent block and then another in a nested block, both headers will be present in the final HTTP response.
Here’s an example:
server {
more_set_headers "X-Server: NGINX";
location / {
more_set_headers "X-Location: Root";
}
}
With this configuration, accessing a URL that matches the location /
block will produce a response with both X-Server: NGINX
and X-Location: Root
headers. The more_set_headers
directive retains the parent’s header settings and simply augments them with the child block’s settings.
Installing more_set_headers
via GetPageSpeed RPM Repositories
Since more_set_headers
is not included by default in NGINX, you’ll need to install an additional module. If you’re using GetPageSpeed RPM repositories, the installation is straightforward:
Enable the Repository:
sudo yum install -y https://extras.getpagespeed.com/release-latest.rpm
Install the Module
sudo yum -y install nginx-module-headers-more
Enable the Module
Open your nginx.conf
file and add the following line at the top:
load_module modules/ngx_http_headers_more_filter_module.so;
Reload NGINX
sudo systemctl reload nginx
To recap, the primary difference between add_header
and more_set_headers
is how they handle inheritance in nested configuration blocks. The more_set_headers
directive offers a far more intuitive and foolproof way to manage HTTP headers, especially in complex, multi-level configurations. If you find yourself running into issues with header inheritance, switching to more_set_headers
might be a wise decision.