20

I'm testing a new web server setup which is having a couple of issues. Essentially, we have a web server, where the code uses the remote IP for some interesting things, and also some apache directories secured down to some certain IP's (our office etc).

However, we've just chucked this behind ha_proxy so we can look at adding some more app servers, but now the remote IP is always coming through as the proxy ip, not the real remote user. This means we can't get to some locations, and our app is behaving a little oddly where user IP is important.

Our config is as follows:

global
      maxconn 4096
      pidfile /var/run/haproxy.pid
      daemon

defaults
      mode http
      retries 3
      option redispatch
      maxconn 2000
      contimeout 5000
      clitimeout 50000
      srvtimeout 50000

listen farm xxx.xxx.xxx.xxx:80
      mode http
      cookie GALAXY insert
      balance roundrobin
      option httpclose
      option forwardfor
      stats enable
      stats auth username:userpass

      server app1 xxx.xxx.xxx.xxx:80 maxconn 1 check

8 Answers 8

33

Quoted from the HAProxy doc at haproxy.1wt.eu.

- if the application needs to log the original client's IP, use the
  "forwardfor" option which will add an "X-Forwarded-For" header with the
  original client's IP address. You must also use "httpclose" to ensure
  that you will rewrite every requests and not only the first one of each
  session:
        option httpclose
        option forwardfor

It is stated that the application must treat the X-Forwarded-For HTTP Header to know the client IP adress. Seems like the only way to go in your case.

Updated for HAProxy 1.4

Haproxy 1.4 introduced a new mode with "option http-server-close". It still closed the connection to the server but maintains keep-alive towards the client if possible and used. On most setups, you probably want to use that as it helps with latency on the single high-latency part of your connection (between Haproxy and the client).

   option http-server-close
   option forwardfor
3
  • 2
    Better use option forwardfor header X-Real-IP and reqidel ^X-Real-IP:, this stops faking IPs in your logs. FYI: X-Real-IP is the default header for NginX' option set_real_ip_from.
    – Tino
    Aug 30, 2012 at 23:44
  • The question doesn't mention nginx. X-Real-IP would not work. Oct 12, 2016 at 16:05
  • 1. do these two options have to be set in the frontend or backend config section? (Because they don't seem to work here) 2. Is any type of configuration required at Tomcat-level as well?
    – yglodt
    Apr 6, 2017 at 15:07
6

There is a way to recompile HAproxy to include Tproxy which will allow forwarding of the source address.

There's a blog post here about it: http://blog.loadbalancer.org/configure-haproxy-with-tproxy-kernel-for-full-transparent-proxy/

A few notes:

The latest linux kernel (2.6.28-11-server) includes support for TProxy, so recompiling the kernel is not necessary.

Make sure to configure the servers in your web farm with a default gateway address which points to the HAProxy server.

2

Use rpaf apache module http://stderr.net/apache/rpaf/ I know this is and old post but it took me days to find this. This will present to any application the x-forwarded-for ip.

1

Note that it would appear that you can override what the application see's my changing the Apache headers:

SetEnvIf X-Forwarded-For (.*) REMOTE_ADDR=$1
SetEnvIf X-Forwarded-For (.*) REMOTE_IP=$1

However, this doesn't work for Apache access via "Allow from" etc.

1
  • This might cause unpredictable results if the client sends an existing X-Forwarded-For header as the new IP address is added to the end of the existing list, separated by a comma and a space. Change the (.*) to ([^ ]*)$ to only grab the last IP... or use mod_rpaf or mod_remoteip for Apache 2.4 or later.
    – Ladadadada
    Aug 24, 2012 at 15:45
1

HAProxy, by design, can't forward the original IP address to the real server, pretty much like any other proxy.

One solution may be, if your only problem is with a web server, to look into the X-forwarded-for HTTP header, which should contain the client's address. Now, that's pretty much application/language specific, but take a look at this example in php:

$headers = apache_request_headers();

$real_client_ip = $headers["X-Forwarded-For"];

If you also want to log the original address, you can modify the LogFormat in httpd.conf to look something like this:

LogFormat "%h %l %u %t \"%r\" %>s %b \"%{X-Forwarded-For}i\"" common

2
  • wrong, you can with the option "forwardfor"
    – wittwerch
    Jun 23, 2009 at 15:18
  • Yes, and this option comes on by default, but what it does is setting the X-Forwarded-For HTTP header. What I was saying, and it looks to me that is what the asker was actually asking, was about the actual source address of the IP packet
    – Thiagodrv
    Jun 23, 2009 at 15:40
0

Well, it seems that the X-Forwarded-for doesn't work well for your setup. So, is there any special reason for you to stick with haproxy? It seems that IPVS is more aproppriate for your needs (I actually use ldirector which in turn uses ipvs).

Take a look at:

http://kb.linuxvirtualserver.org/wiki/IPVS

and

http://www.vergenet.net/linux/ldirectord/

Using IPVS in 'IP Tunneling' or 'Direct Routing' mode preserves the client's address.

0

Try mod_extract_forwarded from http://www.openinfo.co.uk/apache/

LoadModule extract_forwarded_module modules/mod_extract_forwarded.so
MEFOrder refuse,accept
MEFRefuse all
MEFAccept xxx.xxx.xxx.xxx
-1

Easy way with haproxy in mode tcp and nginx :

add send-proxy as server option:

haproxy.conf:

.

.

listen ssl 0.0.0.0:443

mode tcp

balance leastconn

option httpchk GET /ping

option log-health-checks

server w1 192.168.1.1:443 send-proxy check check-ssl verify none

server w2 192.168.1.1:443 send-proxy check check-ssl verify none

.

.

Nginx need support proxy-protocol

nginx.conf:

.

.

listen 192.168.1.1:443 ssl proxy_protocol;

.

.

set_real_ip_from 192.168.1.0/24;

real_ip_header proxy_protocol;

.

.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .