skip to Main Content

my setup is HAPROXY -> Varnish -> Origin

Haproxy with forwardfor option, forward the client original IP to Varnish:

option forwardfor header X-HEADER-IP

I want that Varnish print an header Remote-IP in the response, so I have defined:

set beresp.http.Remote-IP = bereq.http.X-HEADER-IP;

inside the function vcl_backend_response

When I make the first request with CURL from the Machine1 (IP1) I have a MISS with the correct Remote IP address:

 Machine1 (IP1)$ curl -I https://foo.bar
 HTTP/2 200
 server: nginx
 content-type: text/html; charset=utf-8
 **remote-ip: IP1**
 via: 1.1 varnish (Varnish/6.6)
 vary: Accept-Encoding, Cookie, User-Agent
 x-varnish-beresp: 200
 x-varnsih-cache: MISS

If I make the same request from another machine (located in another network IP2), I receive an HIT but the remote IP is the same of the first request, because (I think) has been cached from Varnish.

Machine2 (IP2)$ curl -I https://foo.bar
HTTP/2 200
server: nginx
content-type: text/html; charset=utf-8
**remote-ip: IP1**
via: 1.1 varnish (Varnish/6.6)
vary: Accept-Encoding, Cookie, User-Agent
x-varnish-beresp: 200
x-varnsih-cache: HIT

I want that the second request gives me an HIT, but I want that inside the Remote-IP header there is the correct IP Address (IP2)

How can I do?

Thanks in advance

2

Answers


  1. Chosen as BEST ANSWER

    Thanks to Thijs Feryn answer I've solved! I've followed the suggestion to use X-Forwarded-For and I've also enabled the Proxy Protocol in HAProxy and Varnish. So they now are working with that feature enabled. But, also using the X-Forwarded-For header instead of the custom one, my problem was the same as I have described.

    Instead I have definitely solved the issue when I've moved my code to vcl_deliver function, as suggested in the section Quick & Dirty.

    My final goal was to have a cookie __cc with the country code where the IP Address come from.

    import geoip2;
    import header;
    
    
    sub vcl_deliver {
      ...
      set resp.http.Remote-IP = req.http.X-Forwarded-For; #Just for test
    
      set req.http.X-Country-Code = country.lookup("country/iso_code", std.ip(req.http.X-Forwarded-For, "0.0.0.0"));
      set req.http.Set-CookieCC = "__cc="+req.http.X-Country-Code+"; path=/; Max-Age=300; SameSite=none; Secure";
      set resp.http.set-cookie = header.get(req.http.set-cookieCC,"__cc");
    }
    

    In this way everything works.

    Thanks a lot!


  2. The best way to identify the original client IP address in Varnish is through the conventional X-Forwarded-For header, which is automatically set by Varnish.

    The problem with X-Forwarded-For

    The problem that people often experience, is that they have another server in front of Varnish (HaProxy in your case), so the X-Forwarded-For value is always the same.

    PROXY Protocol to the rescue

    Varnish supports the PROXY protocol. This protocol extends the TCP/IP packets and stores connection information from the original client IP, regardless of the number of hops the traffic had to go through.

    If Varnish is configured with PROXY protocol support, it will automatically set the X-Forwarded-For value to the original client IP.

    Enabling PROXY protocol support in Varnish

    Varnish can listen for incoming PROXY connections if you configure the right listening interface.

    Typically you’ll have a Varnish configuration like this one:

    varnishd -a :6081 -p feature=+http2 -f /etc/varnish/default.vcl -s malloc,256m
    

    You can enable PROXY support by adding the following listening interface:

    -a :8443,PROXY
    

    The complete process would look like this:

    varnishd -a :6081 -a :8443,PROXY -p feature=+http2 -f /etc/varnish/default.vcl -s malloc,256m
    

    With that extra listening interface in place, it’s now a matter of configuring HaProxy

    Enabling PROXY protocol in HaProxy

    The great thing about HaProxy is that they invented the PROXY protocol. Enabling it is super easy.

    Imagine having the following Varnish backend configuration in HaProxy:

    backend varnish
     mode http
     server varnish 127.0.0.1:6081 check
    

    It’s just a matter of adding send-proxy-v2 to the server definition.

    The end result looks like this:

    backend varnish
     mode http
     server varnish 127.0.0.1:6081 check send-proxy-v2
    

    Problem solved

    Once both Varnish & HaProxy communicate over through the PROXY protocol, you can rely on your X-Forwarded-For header to always show the original client IP address.

    Quick & dirty

    So that was the best way to configure it. There’s also a quick & dirty way.

    Assuming the X-HEADER-IP request header is sent by HaProxy and contains the original client IP, you can also use the following VCL snippet to have the remote IP calculated upon every request:

    sub vcl_deliver {
        set resp.http.Remote-IP = req.http.X-HEADER-IP;
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search