How to Set Response Headers in Nginx on Debian

Debian Linux Nginx

Using the Nginx `add_header` directive can lead to duplicate header entries. Here's how to fix it.

Contents

Add Header

Consider the following configuration file:

server {
    ...
    location = /ok {
        add_header Content-Type application/json;
        return 200 '{"result":"ok"}';
    }
}

For me this resulted in the following response:

$ curl -iI https://api.primesite.dev/ok
HTTP/1.1 200 OK
Date: Sat, 10 Oct 2020 03:40:20 GMT
Content-Type: application/octet-stream
Content-Type: application/json
Content-Length: 15

Notice the duplicate Content-Type headers above. The first one with the value of “application/octet-stream” comes from my main nginx.conf file:

default_type application/octet-stream;

But why are those headers duplicated? That’s a problem and especially confusing since the documentation says headers are inherited from other levels only if the current level (location in my case) does not contain the directive, which it does!

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.

Headers More

There is a module called ngx_headers_more that can be easily installed to help untangle the mess that Nginx headers can become.

My system is Debian 10:

$ cat /etc/os-release |grep PRETTY
PRETTY_NAME="Debian GNU/Linux 10 (buster)"

Here’s what I did to install it:

$ sudo apt-get install libnginx-mod-http-headers-more-filter

And that added the file:

/etc/nginx/modules-enabled/50-mod-http-headers-more-filter.conf

which is already in an included folder from nginx.conf:

include /etc/nginx/modules-enabled/*.conf;

Virtual Host

So all I had to do in my site config was to add the custom headers directive and reload the server config:

server {
    ...
    location = /ok {
        more_set_headers 'Content-Type: application/json';
        return 200 '{"result":"ok"}';
    }
}
$ sudo systemctl reload nginx.service

Now it works fine, no more dupes:

$ curl -iI https://api.primesite.dev/ok
HTTP/1.1 200 OK
Date: Sat, 10 Oct 2020 04:16:20 GMT
Content-Type: application/json
Content-Length: 15