Custom HTTP headers not showing up on 404 response status

Written by - 0 comments

Published on - last updated on April 22nd 2022 - Listed in Linux Nginx


One of the OWASP recommendations for SSL/TLS connections is to enable HSTS (HTTP Strict Transport Security). OWASP describes HSTS as:

HTTP Strict Transport Security (HSTS) is an opt-in security enhancement that is specified by a web application through the use of a special response header. Once a supported browser receives this header that browser will prevent any communications from being sent over HTTP to the specified domain and will instead send all communications over HTTPS. It also prevents HTTPS click through prompts on browsers. 

The mentioned HTTP header is called "Strict-Transport-Security" which I of course added into my nginx config:

  add_header Strict-Transport-Security max-age=2678400;

I've been using this header already since 2014. So I was pretty surprised when a developer contacted me today and mentioned that the header doesn't appear on a 404 status page. He was right:

$ curl https://www.claudiokuenzler.com -I
HTTP/1.1 200 OK
Server: nginx
Date: Mon, 23 Jan 2017 14:31:11 GMT
Content-Type: text/html
Connection: keep-alive
X-Powered-By: PHP/5.4.19
Vary: Accept-Encoding
Strict-Transport-Security: max-age=2678400

$ curl https://www.claudiokuenzler.com/i-do-not-exist/ -I
HTTP/1.1 404 Not Found
Server: nginx
Date: Mon, 23 Jan 2017 14:31:39 GMT
Content-Type: text/html; charset=iso-8859-1
Connection: keep-alive
Vary: Accept-Encoding

Frankly, I couldn't explain it at first but after reading again the nginx documentation of add_header it is all explained:

Adds the specified field to a response header provided that the response code equals 200, 201, 204, 206, 301, 302, 303, 304, or 307.

Oops, 404 is not mentioned there. The documentation provides the solution to this, too:

 If the always parameter is specified (1.7.5), the header field will be added regardless of the response code.

So if your nginx is recent enough (at least 1.7.5) you can simply add the "always" parameter like this:

  add_header Strict-Transport-Security max-age=2678400 always;

And the HTTP header is added no matter what HTTP status is returned.

Update 2022

Even though I wrote that article back in 2017 - it is still valid until today. And I forgot, that I wrote this article and ran into the same issue again: Nginx add_header not working, headers not showing up or disappearing in response. Should have searched on my own blog first >.<.


Add a comment

Show form to leave a comment

Comments (newest first)

No comments yet.

RSS feed

Blog Tags:

  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   Observability   Office   OpenSearch   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