When using HAProxy as a load balancer, backend servers typically only see the proxy's IP address instead of the original client IP. This becomes problematic when you need to:
- Maintain accurate access logs
- Implement IP-based security rules
- Perform geolocation analysis
- Track user sessions accurately
Here's the proper way to configure HAProxy to preserve client IP information:
global
maxconn 100000
daemon
# Required for transparent proxy mode
tune.ssl.default-dh-param 2048
defaults
mode http
option forwardfor
option http-server-close
timeout connect 5000
timeout client 50000
timeout server 50000
frontend http-in
bind *:80
# Add X-Forwarded-For header
option forwardfor header X-Real-IP
# For transparent proxy (requires TPROXY)
source 0.0.0.0 usesrc clientip
default_backend servers
backend servers
balance roundrobin
server s1 192.168.1.117:80 check
server s2 192.168.1.116:80 check
server s3 192.168.1.118:80 check
option forwardfor: This is the primary directive that adds the X-Forwarded-For header containing the original client IP.
usesrc clientip: When combined with TPROXY support, this attempts to spoof the source IP at the TCP level.
To check if client IPs are being properly forwarded:
curl -I http://your-haproxy-address/
# Then check your web server logs for the X-Forwarded-For header
For environments where you need the original client IP in TCP connections (not just HTTP):
# Recompile HAProxy with:
make TARGET=linux-glibc USE_LINUX_TPROXY=1
# Then use in configuration:
source 0.0.0.0 usesrc clientip
Your backend servers need to be configured to read the forwarded headers:
For Nginx:
log_format main '$http_x_real_ip - $remote_user [$time_local] '
'"$request" $status $body_bytes_sent '
'"$http_referer" "$http_user_agent"';
access_log /var/log/nginx/access.log main;
For Apache:
LogFormat "%{X-Forwarded-For}i %l %u %t \"%r\" %>s %b" common
CustomLog /var/log/apache2/access.log common
- Ensure HAProxy was compiled with TPROXY support when using 'usesrc clientip'
- Verify kernel settings for transparent proxy: net.ipv4.ip_nonlocal_bind=1
- Check for network devices that might strip headers (like some firewalls)
- Confirm backend servers are configured to trust the proxy IP
When using HAProxy as a load balancer, one common challenge is maintaining visibility into the original client IP addresses. By default, backend servers only see the HAProxy instance's IP, which creates issues for:
- Access logging and analytics
- Geo-IP based functionality
- Security monitoring and rate limiting
- Personalization features
There are three primary methods to preserve client IP information:
# Method 1: X-Forwarded-For Header (Recommended for HTTP)
frontend http-in
mode http
option forwardfor
default_backend webservers
backend webservers
mode http
server s1 192.168.1.1:80 check
server s2 192.168.1.2:80 check
For true transparency (including non-HTTP traffic), you'll need:
# Requires Linux kernel support and TPROXY compilation
global
tune.options.extforward
frontend main
bind :80 transparent
source 0.0.0.0 usesrc clientip
default_backend apps
- Ensure your backend applications are configured to read X-Forwarded-For headers
- For Apache:
LogFormat "%{X-Forwarded-For}i ..." combined
- For Nginx:
set_real_ip_from
andreal_ip_header
directives
If you're still seeing the load balancer IP:
# Test header forwarding
curl -v http://yourlb.example.com -H "X-Forwarded-For: 1.2.3.4"
# Verify HAProxy compilation
haproxy -vv | grep -i tproxy
# Check kernel support
sysctl net.ipv4.ip_forward
sysctl net.ipv4.conf.all.send_redirects
When implementing IP forwarding:
- Always validate X-Forwarded-For headers to prevent spoofing
- Configure
option forwardfor if-none
to preserve existing headers - Set proper
acl
rules to filter malicious traffic