Re: Client behind tproxied haproxy server

From: Willy Tarreau <w#1wt.eu>
Date: Thu, 8 Apr 2010 23:18:41 +0200


Hi Toni,

On Wed, Apr 07, 2010 at 04:51:36PM +0300, Toni Mattila wrote:
> Hi,
>
> Has anyone solved the issue where you have haproxy compiled with TPROXY
> support and use "source 0.0.0.0 usesrc clientip" configuration when
> client is behind the tproxied server.
>
> Scenario:
> Haproxy server with:
> 10.0.0.1/24 IP address this is the "public" side
> 10.1.0.1/24 IP address this is the tproxy side
>
> Web server with:
> 10.1.0.2/24 IP address (using 10.1.0.1 as default gateway)
>
> Configuration:
> listen www 10.0.0.1:80
> mode http
> option http-server-close
> option abortonclose
> mode http
> balance leastconn
> source 0.0.0.0 usesrc clientip
> server server1 10.1.0.2:80 weight 1 check maxconn 270
> option redispatch
>
> Let's say www.example.com is mapped to 10.0.0.1 and you try to access
> www.example.com from webserver using lynx/links/wget you just get:
> HTTP/1.0 503 Service Unavailable
> Cache-Control: no-cache
> Connection: close
> Content-Type: text/html

This is expected, it cannot work because your webserver would have to reply to itself directly without going back through haproxy, so the connection does not match at all. It's amusing, because 10 years ago, people had this issue with NAT-based load balancers. So editors have added a "proxy" feature so that the LB could translate the source address to put theirs when reaching the server. Now you have a proxy which works in this proxy mode by default, and you're trying to make it work like those old NAT-based LBs and are encountering the same routing issues.

Since you're using HTTP, it's a real waste of simplicity and performance to try to work in transparent mode. You'd better work in a normal proxy mode and configure your web server to report the client's IP address in the logs instead of relying on haproxy and your kernel to spoof the client.

If for any reason you absolutely want to do that anyway, here are two possibilities :

  1. use two different backends, one for local connections, and another one for external ones. The local one must not do transparent proxying :

listen www 10.0.0.1:80

        mode    http
        option http-server-close
        option abortonclose
	use_backend from-lan if { src 10.1.0.0/24 }
        balance leastconn
        source 0.0.0.0 usesrc clientip
        server server1 10.1.0.2:80 weight 1 check maxconn 270
        option redispatch

backend from-lan
        mode    http
        option http-server-close
        option abortonclose
        balance leastconn
        server server1 10.1.0.2:80 weight 1 maxconn 270 track www/server1
        option redispatch

2) The second option is very dirty. Since 1.4.4 you can make haproxy bind to a source address presented in an HTTP header. You just have to enable the x-forwarded-for header except from the LAN. It will then bind to the client's IP when it comes from outside the LAN and not do any specific binding when it comes from the LAN :

listen www 10.0.0.1:80

        mode    http
        option http-server-close
        option abortonclose
	reqidel ^X-Forwarded-For  # just in case your servers would set one
	option forwardfor except 10.1.0.0/24
        balance leastconn
        source 0.0.0.0 usesrc hdr_ip(x-forwarded-for)
        server server1 10.1.0.2:80 weight 1 check maxconn 270
        option redispatch


Hoping this helps,
Willy Received on 2010/04/08 23:18

This archive was generated by hypermail 2.2.0 : 2010/04/08 23:30 CEST