Take the 2-minute tour ×
Server Fault is a question and answer site for system and network administrators. It's 100% free, no registration required.

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.

share|improve this question

migrated from stackoverflow.com Jun 8 '11 at 15:03

This question came from our site for professional and enthusiast programmers.

2  
why is passing the host header not an option? imo the host part of the header is made for such things. if you need to pass which proxy was used, you should supply additional headers. –  jojoo Sep 8 '11 at 14:28
1  
Suppose you have a legacy server that does virtual hosting and you want to put Nginx in front of it, to publish some of those services on a new domain. Suppose also you cannot (or don't want to) change the legacy server's configuration. Nginx contains all the tools needed to publish legacy services on new sites, except for the cookie domain issue. –  Tobia Aug 10 '12 at 14:03

3 Answers 3

up vote 10 down vote accepted

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

http://wiki.nginx.org/NginxHttpProxyModule#proxy_cookie_domain

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

share|improve this answer

The above answer 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 
    '; 
}
share|improve this answer

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

share|improve this answer
1  
Thank you for the correct answer, although I've had bad experience with ngx_lua in the past: bad memory leaks. I think Nginx needs some simple header manipulation primitives using its builtin regexp engine, if not a few more custom instructions such as cookie domain rewriting. –  Tobia Aug 10 '12 at 13:59

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.