Nginx's header module allows to add specific headers (add_header) to a server response. This can be pretty helpful, for example to add security related headers.
The following example shows an additional header in the server context:
server {
listen 443 ssl http2;
server_name api.example.com;
access_log /var/log/nginx/api.example.com.access.log;
error_log /var/log/nginx/api.example.com.error.log;
[... ssl settings ... ]
add_header Strict-Transport-Security max-age=2678400;
location / {
proxy_pass http://127.0.0.1:8080;
}
}
But in certain situations the header is not shown in the response:
ck@mint ~ $ curl -I https://api.example.com
HTTP/2 404
server: nginx
date: Tue, 08 Feb 2022 12:53:59 GMT
content-type: text/plain; charset=utf-8
content-length: 9
The Strict-Transport-Security header is clearly missing in the server response.
A review of the add_header documentation shows why:
Adds the specified field to a response header provided that the response code equals 200, 201 (1.3.10), 204, 206, 301, 302, 303, 304, 307 (1.1.16, 1.0.13), or 308 (1.13.0).
As the response code was 404, the additional header is ignored. To enforce the header anyway, regardless of the response code, use the additional 'always' string:
server {
listen 443 ssl http2;
server_name api.example.com;
access_log /var/log/nginx/api.example.com.access.log;
error_log /var/log/nginx/api.example.com.error.log;
[... ssl settings ... ]
add_header Strict-Transport-Security max-age=2678400 always;
location / {
proxy_pass http://127.0.0.1:8080;
}
}
The additional header now shows up, even on a 404 response:
ck@mint ~ $ curl -I https://api.example.com
HTTP/2 404
server: nginx
date: Tue, 08 Feb 2022 13:13:17 GMT
content-type: text/plain; charset=utf-8
content-length: 9
strict-transport-security: max-age=2678400
Another problem can show up, when add_header is defined several times in different contexts.
In the following example, add_header is used once in the server and once in the location context:
server {
listen 443 ssl http2;
server_name api.example.com;
access_log /var/log/nginx/api.example.com.access.log;
error_log /var/log/nginx/api.example.com.error.log;
[... ssl settings ... ]
add_header Strict-Transport-Security max-age=2678400 always;
location / {
add_header X-Debug true always;
proxy_pass http://127.0.0.1:8080;
}
}
But a http request to / now only shows the X-Debug header in the response:
ck@mint ~ $ curl -I https://api.example.com/
HTTP/2 404
server: nginx
date: Tue, 08 Feb 2022 13:48:32 GMT
content-type: text/plain; charset=utf-8
content-length: 9
x-debug: true
Where did the Strict-Transport-Security header go?!
The documentation mentions the following:
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.
But frankly, the meaning of it is quite difficult to understand. A much better explanation can be found on Peter Bengtsson's blog post:
When you use add_header in a location block in Nginx, it undoes all "parent" add_header directives
The easiest fix is to move all add_header lines to the server context. They will then be applied across all locations within this server context.
The more complex (and rather annoying) solution would be to define all the additional headers in each location.
No comments yet.
AWS Android Ansible Apache Apple Atlassian BSD Backup Bash Bluecoat CMS Chef Cloud Coding Consul Containers CouchDB DB DNS Database Databases Docker ELK Elasticsearch Filebeat FreeBSD Galera Git GlusterFS Grafana Graphics HAProxy HTML Hacks Hardware Icinga Influx Internet Java KVM Kibana Kodi Kubernetes LVM LXC Linux Logstash Mac Macintosh Mail MariaDB Minio MongoDB Monitoring Multimedia MySQL NFS Nagios Network Nginx OSSEC OTRS Office PGSQL PHP Perl Personal PostgreSQL Postgres PowerDNS Proxmox Proxy Python Rancher Rant Redis Roundcube SSL Samba Seafile Security Shell SmartOS Solaris Surveillance Systemd TLS Tomcat Ubuntu Unix VMWare VMware Varnish Virtualization Windows Wireless Wordpress Wyse ZFS Zoneminder