39

I have a simple nginx reverse proxy:

server {
  server_name external.domain.com;
  location / {
    proxy_pass http://backend.int/;
  }
}

The problem is that Set-Cookie response headers contain ;Domain=backend.int, because the backend does not know it is being reverse proxied.

How can I make nginx rewrite the content of the Set-Cookie response headers, replacing ;Domain=backend.int with ;Domain=external.domain.com?

Passing the Host header unchanged is not an option in this case.

Apache httpd has had this feature for a while, see ProxyPassReverseCookieDomain, but I cannot seem to find a way to do the same in nginx.

Tobia
  • 1,273

3 Answers3

39

Starting in 1.1.15, proxy_cookie_domain option was added to address this issue.

http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_cookie_domain

This is an example with many domains. Your service might be accessible as service.foo.com and service.bar.com and you need to put foo.com or bar.com in Set-Cookie header accordingly while your backend service always puts backend_host.com in the cookie header:

server {
  server_name ~^service\.(?<domain>.+)$;
  location / {
    proxy_pass http://backend.int/;
    proxy_cookie_domain backend_host.com $domain;
  }
}
rrehbein
  • 518
5

The answer from @shamer works fine with multiple Set-Cookie response headers, but it fails if there's just one. As agentzh points out at the end of the referenced thread, if type(cookies) ~= "table" then cookies = {cookies} end is needed to handle that case.

Here's the whole thing:

location / { 
    proxy_pass http://backend.int/;

    header_filter_by_lua '
        local cookies = ngx.header.set_cookie 
        if not cookies then return end
        if type(cookies) ~= "table" then cookies = {cookies} end
        local newcookies = {}
        for i, val in ipairs(cookies) do
            local newval = string.gsub(val, "([dD]omain)=[%w_-\\\\.]+", 
                      "%1=external.domain.com") 
            table.insert(newcookies, newval) 
        end 
        ngx.header.set_cookie = newcookies 
    '; 
}
lhagan
  • 51
2

This question came up in the nginx mailing list [1]. There's no way to directly do this in nginx. You have to resort to using the ngx_lua module (>=v0.3.1).

The user "agentzh" has an example of what this would look like inlined in the config file:

    server_name external.domain.com; 

    location / { 
        proxy_pass http://backend.int/;

        header_filter_by_lua ' 
            local cookies = ngx.header.set_cookie 
            if not cookies then return end 
            local newcookies = {} 
            for i, val in ipairs(cookies) do 
                local newval = string.gsub(val, "([dD]omain)=[%w_-\\\\.]+", 
                          "%1=external.domain.com") 
                table.insert(newcookies, newval) 
            end 
            ngx.header.set_cookie = newcookies 
        '; 
    } 

[1] http://nginx.2469901.n2.nabble.com/Rewriting-the-domain-part-of-Set-Cookie-in-a-proxy-pass-td6453554.html

shamer
  • 121