133

I want to add a custom header for the response received from the server behind nginx.

While add_header works for nginx-processed responses, it does nothing when the proxy_pass is used.

Dmitry Minkovsky
  • 36,185
  • 26
  • 116
  • 160
sorin
  • 161,544
  • 178
  • 535
  • 806
  • So you pass request to proxy and that proxy set response and on this response you would like to add your custom header before it will be send to user, that's correct? – Michał Kupisiński Jan 24 '13 at 17:11

5 Answers5

223

add_header works as well with proxy_pass as without. I just today set up a configuration where I've used exactly that directive. I have to admit though that I've struggled as well setting this up without exactly recalling the reason, though.

Right now I have a working configuration and it contains the following (among others):

server {
    server_name  .myserver.com
    location / {
        proxy_pass  http://mybackend;
        add_header  X-Upstream  $upstream_addr;
    }
}

Before nginx 1.7.5 add_header worked only on successful responses, in contrast to the HttpHeadersMoreModule mentioned by Sebastian Goodman in his answer.

Since nginx 1.7.5 you can use the keyword always to include custom headers even in error responses. For example:

add_header X-Upstream $upstream_addr always;

Limitation: You cannot override the server header value using add_header.

Oliver
  • 9,239
  • 9
  • 69
  • 100
  • 54
    Since nginx 1.7.5 you can use "always" to include custom headers in error responses using add_header: `add_header X-Upstream $upstream_addr always;` – Shane May 21 '15 at 17:08
  • Anyway to have similar functionality w/o exposing the IP/port combination of the proxied server? e.g. `X-Upstream: 10.10.10.10` vs `X-Upstream: 53c2d28edefdf501ab7c92e02a0c1687` (md5 is probably not helpful in masking the infrastructure, but it conveys the idea). – zamnuts Oct 03 '15 at 02:04
  • @zamnuts: Passing the upstream IP and port numbers is just an example of using the `add_header` directive. You **do not have** to send them at all. – Oliver Oct 05 '15 at 09:37
  • @Oliver, I'm aware of that, but I was inquiring about an alternate individual/unique upstream identifier other than the IP/port numbers, or an obfuscation thereof. Perhaps my question is out of scope and I should create a new post :) – zamnuts Oct 05 '15 at 10:16
  • @zamnuts: I would suggest asking a new question, too :-) – Oliver Oct 06 '15 at 08:37
  • So placed inside a server location using add header it doesn't work, is that right? – Edmondo Feb 22 '18 at 17:35
  • @Edmondo1984 It should work inside a `server` block, as well. With the `server` header I mean the HTTP header "Server". – Oliver Feb 22 '18 at 22:12
  • The server to location block inheritance of `add_header` will not work if there is already an `add_header` in the `location` block. In that case, the `add_header` in the `server` block seems to just be ignored. – trinalbadger587 Apr 14 '23 at 09:14
50

Hide response header and then add a new custom header value

Adding a header with add_header works fine with proxy pass, but if there is an existing header value in the response it will stack the values.

If you want to set or replace a header value (for example replace the Access-Control-Allow-Origin header to match your client for allowing cross origin resource sharing) then you can do as follows:

# 1. hide the Access-Control-Allow-Origin from the server response
proxy_hide_header Access-Control-Allow-Origin;
# 2. add a new custom header that allows all * origins instead
add_header Access-Control-Allow-Origin *;

So proxy_hide_header combined with add_header gives you the power to set/replace response header values.

Similar answer can be found here on ServerFault

UPDATE:

Note: proxy_set_header is for setting request headers before the request is sent further, not for setting response headers (these configuration attributes for headers can be a bit confusing).

Wilt
  • 41,477
  • 12
  • 152
  • 203
  • 6
    your comment about `proxy_set_header` there helped me understand the difference between the two calls, thanks :) – JonnyRaa Jun 23 '21 at 08:53
  • 1
    Explanation on add_header and proxy_hide_header helped me. I had been struggling to see additional content-security-policy in one of the responses and this helped on why that was the case. – ExpectoPatronum Sep 02 '22 at 10:32
39

As oliver writes:

add_header works as well with proxy_pass as without.

However, as Shane writes, as of Nginx 1.7.5, you must pass always in order to get add_header to work for error responses, like so:

add_header  X-Upstream  $upstream_addr always;
Dmitry Minkovsky
  • 36,185
  • 26
  • 116
  • 160
  • 6
    I spent a long time wondering why my headers weren't showing, trying to move them in the server block, location block, ... and here was the reason : nginx doesn't add them on error responses :F Thanks – Shautieh Sep 15 '16 at 08:50
  • 1
    Me too :) and despite this answer this just happened to me the other day again. Had to review my own answer. – Dmitry Minkovsky Jan 20 '18 at 16:00
  • See http://nginx.org/en/docs/http/ngx_http_headers_module.html#add_header for details – Steve Eynon Jul 10 '19 at 10:03
37

There is a module called HttpHeadersMoreModule that gives you more control over headers. It does not come with Nginx and requires additional installation. With it, you can do something like this:

location ... {
  more_set_headers "Server: my_server";
}

That will "set the Server output header to the custom value for any status code and any content type". It will replace headers that are already set or add them if unset.

accounted4
  • 1,685
  • 1
  • 11
  • 13
  • is it possible to add `Secure` and `HttpOnly` flags on a **response cookie**? The target response cookie **only** have the cookie `name` and `expire` attributes though. – JPaulPunzalan Jun 16 '17 at 05:01
  • 2
    You don't necessarily need a library to be able to change or add response headers and in contrary to the most up-voted answer you can override a header, you simply have to remove it first. Check [my answer below](https://stackoverflow.com/a/55692346/1697459) for details. – Wilt Sep 05 '19 at 12:43
17

You could try this solution :

In your location block when you use proxy_pass do something like this:

location ... {

  add_header yourHeaderName yourValue;
  proxy_pass xxxx://xxx_my_proxy_addr_xxx;

  # Now use this solution:
  proxy_ignore_headers yourHeaderName // but set by proxy

  # Or if above didn't work maybe this:
  proxy_hide_header yourHeaderName // but set by proxy

}

I'm not sure would it be exactly what you need but try some manipulation of this method and maybe result will fit your problem.

Also you can use this combination:

proxy_hide_header headerSetByProxy;
set $sent_http_header_set_by_proxy yourValue;
Michał Kupisiński
  • 3,765
  • 1
  • 19
  • 23
  • 8
    I had to use this method as nginx was adding a duplicate header rather than overwriting the exiting one. `location / { proxy_pass http://127.0.0.1:8080/; proxy_hide_header "Access-Control-Allow-Origin"; if ($http_origin ~* "^https://(example.com|www.example.com)$") { add_header Access-Control-Allow-Origin "$http_origin"; } }` – ether6 Apr 10 '18 at 22:51