Server Fault is a question and answer site for system and network administrators. It's 100% free, no registration required.

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

So I have a setup like Nginx -> varnish -> apache2 If I get a request with a static file it is sent through nginx to varnish and back to nginx again since its a lot faster than letting apache2 server it. My problem is that when I do a

sub vcl_fetch {

        set beresp.http.X-Tabulex-Client = client.ip;

to see what the clients ip address is I am being told its (X-Tabulex-Client In the vcl_recv I have:

sub vcl_recv {

    if((!req.url ~ "^/typo3temp/*" && !req.url ~ "^/typo3/*") && req.url ~ "\.(jpg|css|gif|png|js)(\?.*|)$") {
            set req.backend = aurum;
            set client.identity = req.http.X-Forwarded-For;
    } elseif(client.ip == "") {
            /* Traffic from the other Varnish server, serve using real backends */
            set req.backend = balance;
            /* Set client.identity to the X-Forwarded-For (the real IP) */
            set client.identity = req.http.X-Forwarded-For;
    } else {
            /* Traffic coming from internet, use the other Varnish as backend */
            set req.backend = iridium;

The nginx config contains

      proxy_set_header  X-Real-IP  $remote_addr;
      proxy_set_header Host $host;
      proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
      proxy_intercept_errors on;

when sending to varnish the first time and nothing when receiving from varnish again.

Im not sure where the problem is. I would expect the client.ip to contain the external ip address so I could use it for acl. Any ideas?

share|improve this question
up vote 3 down vote accepted

The value of client.ip is because nginx is the client. It wouldn't make sense for Varnish to mask this value -- even in situations like yours where Varnish is sitting behind a front-end proxy, you often want to base decisions on the ip address of the thing actually making the connecting to Varnish.

What you really want to do is have nginx put the remote client ip address into a dedicated header (which you're already doing with X-Real-IP) and use that for making connection decisions. We do exactly this in our environment where we have Apache provided SSL connectivity in front of varnish, and then we use this header to make access decisions.

It's not as nice as using client.ip (you can't match it using acls), but it works. We do something like this:

if (! (
        req.http.X-Real-IP ~ "^10\." ||
        req.http.X-Real-IP ~ "^100\.100\." ||
        req.http.X-Real-IP ~ "^200\.200\."
)) {
        error 403 "Forbidden";

Varnish doesn't provide a native mechanism for overriding client.ip with a custom header, but it is possible to solve the problem anyway because you can insert arbitrary C code into your configuration.

Here is an example that exactly parallels your situation that includes an example of replacing client.ip with another value so that it can be used in Varnish ACLs.

share|improve this answer
Makes sence. I couldnt find any documentation on how the client works. Am I able to overwrite client.ip somehow? As you said yourself its the normal way of doing ACL :) – Ronnie Jespersen May 24 '12 at 7:09
So I tried your approach but I cant seem to get it working. if (req.http.Cache-Control ~ "no-cache" && req.http.X-Real-IP ~ "^111\.111\.111\.111") { ban(req.url); return (pass); } also tried ip address just using "" – Ronnie Jespersen May 24 '12 at 22:18
Are these rules matching? What does your varnishlog output show for a single request? – larsks May 25 '12 at 0:19
Sorry it is working. It does recognize my IP address but it dosent ban the file. I think this is due to the communication between the two varnish caches. I get the new file when doing a no-cache hit but as soon as I make a normal request I get the old file. – Ronnie Jespersen May 26 '12 at 21:19

If you're using Varnish as your front-end webserver (our backend is NGINX) behind a Rackspace Cloud Load Balancer, then you need to use a pattern like the following:

if (!(
    req.http.X-Forwarded-For ~ "1\.2\.3\.4" || 
    req.http.X-Forwarded-For ~ "2\.3\.4\.5" 
    )) {
    # IP-based Rules

Rackspace Cloud Load Balancer won't pass anything but to Varnish as client.ip. Also, I tried using a more restrictive pattern, like ^2\.3\.4\.5$ but it wouldn't match. I think the load balancer was adding extra characters to the X-Forwarded-For header.

share|improve this answer

Your Answer


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.