Reverse Proxying

After an unnamed vBulletin website fell over for the umpteenth time overnight, I suggested to its owner that we upgrade the Linux install that runs it to something vaguely recent. That  would allow us to make use of the varnish cache to speed things up.

When using reverse proxying, your web server will see all requests as coming from the proxy host - 127.0.0.1 in my case - and that makes for useless logs. If a website keeps track of failed logins by IP address, it can even prevent all users from logging in after only a handful of problems, as all users are deemed to be on the same IP.

Enter mod_rpaf for Apache. That module re-plumbs the Apache internals so that if an X-Forwarded-For header is present in the HTTP request, it will replace the proxy IP with whatever is set in the X-Forwarded-For header.

That means log entries once again get the end user's IP address and the REMOTE_ADDR environment variable is no longer set to the proxy's IP. Lovely!

One slight problem though is that it would seem Varnish doesn't set the X-Forwarded-For header by default and that most Google hits for how to set it give incorrect instructions.

Here is what I used and have found to actually work with Apache 2.2 and Varnish 2.1 on Ubuntu 10.04 (Lucid).

sub vcl_recv {
  unset req.http.X-Forwarded-For;
  set req.http.X-Forwarded-For = regsub(client.ip, ":.*", "");
}

The only giant caveat that I can see would be that the regex call cannot cope with IPv6 addresses at all. Patches welcome :-)

Comments

There's a slight problem with removing a present X-Forwarded-For header and replacing it with the IP address of the client: there's some disagreement on how to interpret the RFC (or whatever there is) for this header.

Some people claim it should contain the IP address of the last hop (and then its safe to replace it)
other people want to have the header contain a comma-seperated list of all hops it passed.

Where I work, we the use the second one: this way we can still determine the original IP address that X-Forwarded-For: had when it entered our Webfarm but we can still add our own proxies to it without losing the original information.

Yup, the original I found at https://wiki.fourkitchens.com/display/PF/Workaround+for+Varnish+X-Forwar... appends the client IP to what is already present:

if (req.http.X-Forwarded-For) {
// Append the client IP
set req.http.X-Real-Forwarded-For = req.http.X-Forwarded-For ", " regsub(client.ip, ":.*", "");
unset req.http.X-Forwarded-For;
}
else {
// Simply use the client IP
set req.http.X-Real-Forwarded-For = regsub(client.ip, ":.*", "");
}

Of course that's easily modifyable to append the IP to the header you need, but you will then need to make sure that mod_rpaf can handle multiple addresses in that header and do the right thing.

In my case, I didn't care, so I just overwrote the header. Varnish appears to not set the X-Forwarded-For header at all even though it should, so there is never anything in there.

Thanks your technique works great for me. I had a application that worked a certain way when requested with a certain client IP. Before I made this change all trafic appeared as if it was coming from 127.0.0.1. Now the client IP address is proxied through correctly.

Thank you for this information. I never have thought about using reverse proxying before even if I have been using a proxy. I got some errors at the start but fortunately after following the link you provided I got it right.