When load balancing across servers with different hostnames, HAProxy's default health check behavior can cause issues since it uses the server's address rather than the application's virtual host. The http-send-name-header Host
directive doesn't apply to health checks in HAProxy 1.5, requiring workarounds.
Here's the core challenge: We want a single listen section while maintaining proper host header validation during health checks. The key components needed:
option httpchk HEAD / HTTP/1.1\r\nHost: example.com
http-send-name-header Host
For HAProxy 1.5, we need separate listen blocks for each server when different host headers are required. Here's an optimized version:
global
log 127.0.0.1 local0 notice
maxconn 2000
user haproxy
group haproxy
defaults
log global
mode http
option httplog
option dontlognull
retries 3
option redispatch
timeout connect 5000
timeout client 10000
timeout server 10000
stats enable
stats uri /haproxy?stats
stats refresh 5s
balance roundrobin
option httpclose
frontend main
bind *:80
use_backend bk_app1 if { hdr(host) -i www.example.com }
use_backend bk_app2 if { hdr(host) -i www.bing.com }
backend bk_app1
option httpchk HEAD / HTTP/1.1\r\nHost:\ www.example.com
server s1 127.0.0.101:80 check
backend bk_app2
option httpchk HEAD / HTTP/1.1\r\nHost:\ www.bing.com
server s2 127.0.0.102:80 check
For newer HAProxy versions (1.6+), you can use more elegant solutions:
backend servers
option httpchk
http-check send meth HEAD uri / hdr Host example.com
server s1 127.0.0.101:80 check
server s2 127.0.0.102:80 check hdr Host bing.com
- Health check intervals should match application requirements
- Different rise/fall thresholds per backend if needed
- SSL termination adds complexity to host header handling
- Consider using ACLs for more complex routing logic
When load balancing across multiple backend servers that each have different hostnames (and where you can't configure identical virtual hosts), HAProxy's health check mechanism requires special consideration. The core issue is that standard HTTP health checks won't properly validate servers that require specific Host headers.
While http-send-name-header Host
works for regular traffic forwarding, it doesn't automatically apply to health checks. In HAProxy 1.5 (and even in newer versions), health checks need explicit Host header configuration.
Here's an optimized approach that maintains clean configuration while properly handling health checks:
global
log 127.0.0.1 local0 notice
maxconn 2000
user haproxy
group haproxy
defaults
log global
mode http
option httplog
option dontlognull
retries 3
option redispatch
timeout connect 5000
timeout client 10000
timeout server 10000
stats enable
stats uri /haproxy?stats
stats refresh 5s
balance roundrobin
option httpclose
listen inbound :80
option httpchk
server instance1 127.0.0.101 check inter 3000 fall 1 rise 1
server instance2 127.0.0.102 check inter 3000 fall 1 rise 1
backend instance1_backend
option forwardfor
http-send-name-header Host
option httpchk HEAD / HTTP/1.1\r\nHost:\ www.example.com
server www.example.com www.example.com:80 check inter 5000 fall 3 rise 2
backend instance2_backend
option forwardfor
http-send-name-header Host
option httpchk HEAD / HTTP/1.1\r\nHost:\ www.bing.com
server www.bing.com www.bing.com:80 check inter 5000 fall 3 rise 2
1. Using backend
sections instead of multiple listen
blocks for cleaner organization
2. Explicit Host headers in health checks for each backend
3. Maintaining separate check intervals and thresholds based on server requirements
If you can upgrade to HAProxy 1.6 or later, you can use the http-check send
directive for more flexibility:
backend example_backend
option forwardfor
http-send-name-header Host
http-check send meth HEAD uri / hdr Host www.example.com
server www.example.com www.example.com:80 check inter 5000 fall 3 rise 2
After implementing this configuration, verify your health checks are working properly by:
- Checking HAProxy stats page
- Examining logs for health check failures
- Using curl -I
to manually test backend responses