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.