How to Configure HAProxy Host Headers for Multiple IIS Backends with Virtual Hosting


2 views

When working with IIS servers configured for virtual hosting (where multiple sites share the same IP and port), HAProxy must preserve or modify the Host header to ensure requests reach the correct backend application. Unlike simpler setups where backends have dedicated ports, IIS relies heavily on host headers for routing.

The key is to dynamically set the Host header based on which backend server is selected. Here's a complete configuration example:

frontend http-in
    bind *:80
    mode http
    acl is_node1 hdr(host) -i node1.myapp.mycompany.com
    acl is_node2 hdr(host) -i node2.myapp.mycompany.com
    
    use_backend node1_servers if is_node1
    use_backend node2_servers if is_node2
    default_backend nodes

backend node1_servers
    mode http
    server web01 node1.myapp.mycompany.com:80 check
    http-request set-header Host node1.myapp.mycompany.com

backend node2_servers
    mode http
    server web02 node2.myapp.mycompany.com:80 check
    http-request set-header Host node2.myapp.mycompany.com

backend nodes
    mode http
    balance roundrobin
    option forwardfor
    http-request set-header Host myapp.mycompany.com
    server web01 node1.myapp.mycompany.com:80 check
    server web02 node2.myapp.mycompany.com:80 check

For health checks to work properly with IIS virtual hosts, we need to configure them with the correct Host headers:

option httpchk GET /healthcheck HTTP/1.1\r\nHost:\ node1.myapp.mycompany.com
http-check expect status 200

For larger deployments, consider using HAProxy maps for dynamic host header assignment:

frontend http-in
    bind *:80
    mode http
    use_backend %[req.hdr(host),lower,map(/etc/haproxy/host_backend.map,nodes)]

backend nodes
    mode http
    http-request set-header Host %[req.hdr(host),lower,map(/etc/haproxy/host_header.map,myapp.mycompany.com)]

Sample map file contents:

# host_backend.map
node1.myapp.mycompany.com node1_servers
node2.myapp.mycompany.com node2_servers
  • Enable HAProxy logging with option httplog to verify headers
  • Use curl -v to inspect request headers
  • Test with set-server-ssl if using HTTPS backends

When working with IIS servers that use host headers for virtual hosting, HAProxy configurations require special attention to properly forward requests. The core issue emerges when multiple backend nodes need distinct host headers while serving the same frontend domain.

In our infrastructure, we have:

Frontend: myapp.mycompany.com → HAProxy
Backends:
- node1.myapp.mycompany.com (IIS with host header binding)
- node2.myapp.mycompany.com (IIS with host header binding)

The initial HAProxy configuration fails because:

  1. Static host header rewriting affects all backend servers
  2. Health checks don't verify with proper host headers

Here's the proper configuration approach using HAProxy 1.7.9+:

frontend http-in
    bind *:80
    acl is_node1 hdr(host) -i myapp.mycompany.com
    use_backend nodes if is_node1

backend nodes
    mode http
    balance roundrobin
    option forwardfor
    
    # Dynamic host header based on selected server
    http-request set-header Host %[srv_name].myapp.mycompany.com
    
    server web01 node1.myapp.mycompany.com:80 check
    server web02 node2.myapp.mycompany.com:80 check

For more complex scenarios, consider these variations:

1. Using Server Templates

backend nodes
    mode http
    balance roundrobin
    
    server-template web 2 node{}.myapp.mycompany.com:80 \
        check resolvers dns1 init-addr none \
        source 0.0.0.0 usesrc clientip \
        ssl verify none

2. Separate Backends with ACLs

frontend http-in
    bind *:80
    acl is_node1 path_beg /api/v1
    acl is_node2 path_beg /api/v2
    
    use_backend node1_backend if is_node1
    use_backend node2_backend if is_node2

backend node1_backend
    server web01 node1.myapp.mycompany.com:80 check
    http-request set-header Host node1.myapp.mycompany.com

backend node2_backend
    server web02 node2.myapp.mycompany.com:80 check
    http-request set-header Host node2.myapp.mycompany.com

Proper health checks require matching host headers:

option httpchk GET /health
http-check send hdr Host node1.myapp.mycompany.com

For dynamic health checks per server:

backend nodes
    server web01 node1.myapp.mycompany.com:80 \
        check send-proxy-v2 \
        check-send-proxy hdr Host node1.myapp.mycompany.com
    
    server web02 node2.myapp.mycompany.com:80 \
        check send-proxy-v2 \
        check-send-proxy hdr Host node2.myapp.mycompany.com
  • Enable HAProxy debug logging with option log-health-checks
  • Verify headers using curl -v -H "Host: myapp.mycompany.com" http://haproxy-ip/
  • Check IIS logs for received host headers