# Rewriting the domain part of Set-Cookie in a proxy\_pass

**URL:** <https://www.ruby-forum.com/t/rewriting-the-domain-part-of-set-cookie-in-a-proxy-pass/208025>\
**Category:** NGINX\
**Created:** [June 8, 2011, 3:16pm UTC](https://www.ruby-forum.com/t/rewriting-the-domain-part-of-set-cookie-in-a-proxy-pass/208025 "2011-06-08T15:16:52Z")\
**Posts on this page:** 11\
**Page:** 1

<div class="post-metadata">

**Author:** ![luislavena](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/l/0ea827/32.png) [@luislavena](https://www.ruby-forum.com/u/luislavena)\
**Post date:** [June 8, 2011, 3:16pm UTC](https://www.ruby-forum.com/t/rewriting-the-domain-part-of-set-cookie-in-a-proxy-pass/208025/1 "2011-06-08T15:16:52Z")

</div>

Hello

Does nginx (or a module) provide functionality equivalent to httpd’s  
ProxyPassReverseCookieDomain?

Long explanation: I have a simple nginx reverse proxy

server {  
server\_name [external.domain.com](http://external.domain.com);  
location / {  
proxy\_pass [http://backend.int/](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. Therefore the users’ browsers dutifully reject such bad  
cookies.

How can I rewrite the content of the Set-Cookie response headers,  
replacing “;Domain=backend.int” with “;[Domain=external.domain.com](http://Domain=external.domain.com)”?

Unfortunately passing the Host header unchanged and reconfiguring the  
virtual host table of the backend is not an option in this case.

Best,  
Tobia

Posted at Nginx Forum:

> **[Rewriting the domain part of Set-Cookie in a proxy\_pass](https://forum.nginx.org/read.php?2,204971,204971#msg-204971)**
>
> Hello Does nginx (or a module) provide functionality equivalent to httpd's ProxyPassReverseCookieDomain? Long explanation: I have a simple nginx reverse proxy server { server\_name external.domain.com; location / { proxy\_pass h

---

<div class="post-metadata">

**Author:** ![tobia](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/t/6f9a4e/32.png) [@tobia](https://www.ruby-forum.com/u/tobia)\
**Post date:** [June 8, 2011, 3:36pm UTC](https://www.ruby-forum.com/t/rewriting-the-domain-part-of-set-cookie-in-a-proxy-pass/208025/2 "2011-06-08T15:36:04Z")

</div>

On 8 Jun 2011 14h16 WEST, [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:

> proxy\_pass [http://backend.int/](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. Therefore the users’ browsers dutifully reject such  
> bad cookies.
> 
> How can I rewrite the content of the Set-Cookie response headers,  
> replacing “;Domain=backend.int” with “;[Domain=external.domain.com](http://Domain=external.domain.com)”?

AFAIK you’ll need to use 3rd party modules. Either  
[GitHub - nginxinc/nginx-wiki: ARCHIVED -- Source for the now archived NGINX Wiki section of https://www.nginx.com · GitHub](http://wiki.nginx.org/HttpHeadersMoreModule) and/or  
[GitHub - openresty/lua-nginx-module: Embed the Power of Lua into NGINX HTTP servers · GitHub](http://github.com/chaoslawful/lua-nginx-module)

Probably the Embedded Perl module let’s you do that also. You’ll have to  
try it out.

— appa

---

<div class="post-metadata">

**Author:** ![tobia](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/t/6f9a4e/32.png) [@tobia](https://www.ruby-forum.com/u/tobia)\
**Post date:** [June 8, 2011, 4:03pm UTC](https://www.ruby-forum.com/t/rewriting-the-domain-part-of-set-cookie-in-a-proxy-pass/208025/3 "2011-06-08T16:03:16Z")

</div>

António P. P. Almeida Wrote:

> > How can I rewrite the content of the Set-Cookie  
> > response headers, replacing “;Domain=backend.int”  
> > with “;[Domain=external.domain.com](http://Domain=external.domain.com)”?
> 
> AFAIK you’ll need to use 3rd party modules. Either  
> [GitHub - nginxinc/nginx-wiki: ARCHIVED -- Source for the now archived NGINX Wiki section of https://www.nginx.com · GitHub](http://wiki.nginx.org/HttpHeadersMoreModule) and/or  
> [GitHub - openresty/lua-nginx-module: Embed the Power of Lua into NGINX HTTP servers · GitHub](http://github.com/chaoslawful/lua-nginx-module)
> 
> Probably the Embedded Perl module let’s you do  
> that also. You’ll have to try it out.

Thanks for the pointers.

HttpHeadersMoreModule doesn’t seem to let me replace parts of headers.

Lua doesn’t seem to have it either:

> Reading values from ngx.header.HEADER is not  
> implemented yet, and usually you shouldn’t need it.

That leaves me with the Perl module…

Tobia

Posted at Nginx Forum:  
[http://forum.nginx.org/read.php?2,204971,204989#msg-204989](http://forum.nginx.org/read.php?2,204971,204989#msg-204989)

---

<div class="post-metadata">

**Author:** ![tobia](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/t/6f9a4e/32.png) [@tobia](https://www.ruby-forum.com/u/tobia)\
**Post date:** [June 8, 2011, 4:07pm UTC](https://www.ruby-forum.com/t/rewriting-the-domain-part-of-set-cookie-in-a-proxy-pass/208025/4 "2011-06-08T16:07:36Z")

</div>

I wrote:

> That leaves me with the Perl module…

…which apparently cannot do it either: you can only set response  
headers from scratch.

> $r-\>header\_out(header, value) - set a response header.

Does anybody have any idea?

Tobia

Posted at Nginx Forum:  
[http://forum.nginx.org/read.php?2,204971,204992#msg-204992](http://forum.nginx.org/read.php?2,204971,204992#msg-204992)

---

<div class="post-metadata">

**Author:** ![tobia](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/t/6f9a4e/32.png) [@tobia](https://www.ruby-forum.com/u/tobia)\
**Post date:** [June 8, 2011, 4:19pm UTC](https://www.ruby-forum.com/t/rewriting-the-domain-part-of-set-cookie-in-a-proxy-pass/208025/5 "2011-06-08T16:19:58Z")

</div>

Hello!

On Wed, Jun 08, 2011 at 10:06:59AM -0400, tobia wrote:

> I wrote:
> 
> > That leaves me with the Perl module…
> 
> …which apparently cannot do it either: you can only set response  
> headers from scratch.
> 
> > $r-\>header\_out(header, value) - set a response header.
> 
> Does anybody have any idea?

You may get upstream response header via $upstream\_http\_\*  
variable, and set one (rewritten with perl\_set) with add\_header  
directive.

The problem is still here though: you can’t iterate over multiple  
Set-Cookie headers if there are more than one present in upstream  
response.

Maxim D.

---

<div class="post-metadata">

**Author:** ![tobia](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/t/6f9a4e/32.png) [@tobia](https://www.ruby-forum.com/u/tobia)\
**Post date:** [June 8, 2011, 4:18pm UTC](https://www.ruby-forum.com/t/rewriting-the-domain-part-of-set-cookie-in-a-proxy-pass/208025/6 "2011-06-08T16:18:07Z")

</div>

On Wed, Jun 8, 2011 at 3:02 PM, tobia [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:

> > that also. You’ll have to try it out.
> 
> Thanks for the pointers.
> 
> HttpHeadersMoreModule doesn’t seem to let me replace parts of headers.
> 
> Lua doesn’t seem to have it either:
> 
> > Reading values from ngx.header.HEADER is not  
> > implemented yet, and usually you shouldn’t need it.
> 
> I think you need to read the headers you get back from ngx.location.capture  
> in Lua (retrieve the backend response), then set the outbound headers  
> with  
> ngx.HEADER, so you should be able to do this in Lua.

So your content\_by\_lua block calls ngx.location.capture to get the  
backend  
response, reads the headers it gets from there, then sets the outbound  
headers…

Justin

---

<div class="post-metadata">

**Author:** ![tobia](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/t/6f9a4e/32.png) [@tobia](https://www.ruby-forum.com/u/tobia)\
**Post date:** [June 9, 2011, 4:09am UTC](https://www.ruby-forum.com/t/rewriting-the-domain-part-of-set-cookie-in-a-proxy-pass/208025/7 "2011-06-09T04:09:47Z")

</div>

On Thu, Jun 9, 2011 at 3:30 AM, 杨镭 [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:

> I am curious when there is an output\_by\_lua/output\_by\_luafle directive in  
> nginx-lua module.

We will probably have header\_filter\_by\_lua and body\_filter\_by\_lua  
directives by this Christmas 😉

For simplicity, I’ll just borrow the mechanism used by  
set\_by\_lua(\_file) and disable subrequest support like  
ngx.location.capture() in lua output filters.

> Currently, if one want to set/modify response header, the  
> only possible way is to do a subrequest using ngx.capture.  
> I think this is really cumbersome compared to declarative configuration such  
> as: output\_by\_lua\_file.

Agreed 🙂

Regards,  
-agentzh

---

<div class="post-metadata">

**Author:** ![tobia](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/t/6f9a4e/32.png) [@tobia](https://www.ruby-forum.com/u/tobia)\
**Post date:** [June 8, 2011, 9:30pm UTC](https://www.ruby-forum.com/t/rewriting-the-domain-part-of-set-cookie-in-a-proxy-pass/208025/8 "2011-06-08T21:30:57Z")

</div>

I am curious when there is an output\_by\_lua/output\_by\_luafle directive  
in  
nginx-lua module. Currently, if one want to set/modify response header,  
the  
only possible way is to do a subrequest using ngx.capture.

I think this is really cumbersome compared to declarative configuration  
such  
as: output\_by\_lua\_file.

cc’ed agentzh

On Wed, Jun 8, 2011 at 10:17 PM, Justin Cormack \<

---

<div class="post-metadata">

**Author:** ![tobia](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/t/6f9a4e/32.png) [@tobia](https://www.ruby-forum.com/u/tobia)\
**Post date:** [June 27, 2011, 10:51am UTC](https://www.ruby-forum.com/t/rewriting-the-domain-part-of-set-cookie-in-a-proxy-pass/208025/9 "2011-06-27T10:51:12Z")

</div>

agentzh wrote:

> We will probably have header\_filter\_by\_lua and  
> body\_filter\_by\_lua directives by this Christmas 😉

That will be great.

I still think Nginx should have plain C equivalents to Apache’s  
ProxyPassReverseCookieDomain and ProxyPassReverseCookiePath. It’s a  
problem that comes up fairly often when proxying legacy servers.

Nginx could even do it by default, when there is a proxy\_pass with a  
path component (which means: “process the request host and path”, as  
opposed to a proxy\_pass without trailing slash, which means “pass the  
request unprocessed”)

What do you think?

Tobia

Posted at Nginx Forum:  
[http://forum.nginx.org/read.php?2,204971,210374#msg-210374](http://forum.nginx.org/read.php?2,204971,210374#msg-210374)

---

<div class="post-metadata">

**Author:** ![tobia](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/t/6f9a4e/32.png) [@tobia](https://www.ruby-forum.com/u/tobia)\
**Post date:** [September 14, 2011, 10:50am UTC](https://www.ruby-forum.com/t/rewriting-the-domain-part-of-set-cookie-in-a-proxy-pass/208025/10 "2011-09-14T10:50:16Z")

</div>

On Wed, Jun 8, 2011 at 9:16 PM, tobia [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:

> }
> 
> The problem is that Set-Cookie response headers contain  
> “;Domain=backend.int”, because the backend does not know it is being  
> reverse proxied. Therefore the users’ browsers dutifully reject such bad  
> cookies.
> 
> How can I rewrite the content of the Set-Cookie response headers,  
> replacing “;Domain=backend.int” with “;[Domain=external.domain.com](http://Domain=external.domain.com)”?

Now with the latest ngx\_lua v0.3.1rc3, we can implement this with a  
little inlined Lua in nginx.conf:

```
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](http://1=external.domain.com)”)  
table.insert(newcookies, newval)  
end  
ngx.header.set\_cookie = newcookies  
';  
}

We can surely make this more portable by avoiding hard-coding the  
“[external.domain.com](http://external.domain.com)” literal in our Lua code and reference  
ngx.var.server\_name (i.e., the nginx variable $server\_name) instead 😉

See the ngx\_lua documentation for more details:

```
http://wiki.nginx.org/HttpLuaModule

```

The most relevant sections are

```
http://wiki.nginx.org/HttpLuaModule#header_filter_by_lua

```

and

```
http://wiki.nginx.org/HttpLuaModule#ngx.header.HEADER

```

Have fun!  
-agentzh

---

<div class="post-metadata">

**Author:** ![tobia](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/t/6f9a4e/32.png) [@tobia](https://www.ruby-forum.com/u/tobia)\
**Post date:** [September 14, 2011, 11:24am UTC](https://www.ruby-forum.com/t/rewriting-the-domain-part-of-set-cookie-in-a-proxy-pass/208025/11 "2011-09-14T11:24:58Z")

</div>

On Wed, Sep 14, 2011 at 4:49 PM, agentzh [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:

> server\_name [external.domain.com](http://external.domain.com);
> 
> location / {  
> proxy\_pass [http://backend.int/](http://backend.int/);
> 
> header\_filter\_by\_lua ’  
> local cookies = ngx.header.set\_cookie  
> if not cookies then return end

Sorry, one line of Lua should be inserted right here for the case of a  
single Set-Cookie response header:

```
        if type(cookies) ~= "table" then cookies = {cookies} end

```

that is, ngx.header.set\_cookie will just return a single Lua string  
instead of a Lua table if there’s only one Set-Cookie header.

Regards,  
-agentzh
