Configuring HAProxy for Subdomain Routing with SSL Passthrough and Termination


4 views

I recently encountered a situation where I needed to route traffic from three subdomains (sub1.mydomain.com, sub2.mydomain.com, and sub3.mydomain.com) to the same HAProxy instance, with different backend ports and SSL handling requirements. Here's how I approached the solution.

The setup consists of:

  • HAProxy server with IP 10.10.10.100 (haproxy01.mydomain.com)
  • Three CNAME records pointing to the HAProxy
  • Two backend servers (10.10.10.101 and 10.10.10.102)
  • Different ports for each subdomain (8081, 8082, 8083)

The key challenge was handling SSL differently for each subdomain:

  • sub1.mydomain.com: Requires SSL passthrough (TCP mode)
  • sub2.mydomain.com and sub3.mydomain.com: Can terminate SSL at HAProxy

Initially, I tried using TCP mode for all traffic, which led to connection issues. The logs showed:

localhost haproxy[6097]: x.x.x.x:51241 [20/Mar/2015:12:19:38.720] mytraffic mytraffic/ -1/-1/0 0 SC 0/0/0/0/0 0/0

Here's the corrected configuration that handles both SSL passthrough and termination:

frontend https-in
    # SSL termination for sub2 and sub3
    bind *:443 ssl crt /etc/haproxy/certs/mydomain.com.pem
    
    # ACLs for subdomain routing
    acl is_sub1 hdr(host) -i sub1.mydomain.com
    acl is_sub2 hdr(host) -i sub2.mydomain.com
    acl is_sub3 hdr(host) -i sub3.mydomain.com
    
    # Route to appropriate backends
    use_backend sub1_backend if is_sub1
    use_backend sub2_backend if is_sub2
    use_backend sub3_backend if is_sub3

# TCP mode for SSL passthrough (sub1)
frontend sub1_tcp
    bind *:8081
    mode tcp
    default_backend sub1_backend

backend sub1_backend
    mode tcp
    balance roundrobin
    server node1 10.10.10.101:8081 check
    server node2 10.10.10.102:8081 check

backend sub2_backend
    mode http
    balance roundrobin
    server node1 10.10.10.101:8082 check ssl verify none
    server node2 10.10.10.102:8082 check ssl verify none

backend sub3_backend
    mode http
    balance roundrobin
    server node1 10.10.10.101:8083 check ssl verify none
    server node2 10.10.10.102:8083 check ssl verify none
  • Separate frontends for HTTP and TCP traffic
  • SSL certificate bundled for the main domain and subdomains
  • TCP mode for SSL passthrough (sub1)
  • HTTP mode with SSL termination for other subdomains
  • SSL verification disabled for backend connections (verify none)

If you encounter issues:

  1. Check HAProxy logs: tail -f /var/log/haproxy.log
  2. Verify DNS resolution for all subdomains
  3. Test backend connectivity: curl -vk https://sub2.mydomain.com
  4. Check certificate chain: openssl s_client -connect sub2.mydomain.com:443

For production environments:

  • Enable SSL session caching
  • Consider using SSL offloading hardware if traffic is heavy
  • Implement proper health checks for backends
  • Monitor connection queues and adjust timeouts as needed

When implementing HAProxy with multiple subdomains pointing to different backend ports, we need to carefully handle both the routing logic and SSL requirements. Your current setup has three key requirements:

  1. Subdomain-based routing (sub1/sub2/sub3.mydomain.com)
  2. Mixed SSL handling (pass-through vs termination)
  3. Port-based backend distribution (8081/8082/8083)

The SC (Session Closed) error in your logs suggests HAProxy isn't properly establishing the TCP connection to your backends. Let's analyze the critical issues in your current setup:

# Main problem areas in original config:
1. Incorrect backend section indentation (sub1_nodes is misaligned)
2. Missing proper SSL certificate configuration
3. Potential SNI requirement for host header inspection

Here's the corrected version that handles both SSL passthrough and termination scenarios:

# Global SSL certificates (for termination)
global
    ssl-default-bind-ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256
    ssl-default-bind-options no-sslv3 no-tlsv10 no-tlsv11

# Frontend for SSL traffic
frontend https_in
    bind *:443 ssl crt /etc/haproxy/certs/mydomain.com.pem alpn h2,http/1.1
    mode tcp
    option tcplog
    
    # TLS inspection for host-based routing
    tcp-request inspect-delay 5s
    tcp-request content accept if { req_ssl_hello_type 1 }
    
    # ACLs for subdomain routing
    acl sub1 req_ssl_sni -i sub1.mydomain.com
    acl sub2 req_ssl_sni -i sub2.mydomain.com
    acl sub3 req_ssl_sni -i sub3.mydomain.com
    
    # Routing logic
    use_backend sub1_servers if sub1
    use_backend sub2_servers if sub2
    use_backend sub3_servers if sub3

# Backend for SSL passthrough (sub1)
backend sub1_servers
    mode tcp
    balance roundrobin
    option ssl-hello-chk
    server node1 10.10.10.101:8081 check send-proxy
    server node2 10.10.10.102:8081 check send-proxy

# Backend for SSL termination (sub2)
backend sub2_servers
    mode http
    balance roundrobin
    option forwardfor
    http-request set-header X-Forwarded-Port %[dst_port]
    http-request add-header X-Forwarded-Proto https
    server node1 10.10.10.101:8082 check ssl verify none
    server node2 10.10.10.102:8082 check ssl verify none

# Backend for SSL termination (sub3)
backend sub3_servers
    mode http
    balance roundrobin
    option forwardfor
    http-request set-header X-Forwarded-Port %[dst_port]
    http-request add-header X-Forwarded-Proto https
    server node1 10.10.10.101:8083 check ssl verify none
    server node2 10.10.10.102:8083 check ssl verify none

1. SSL Certificates: Combine all certificates into a single PEM file for HAProxy:

cat sub1.mydomain.com.crt sub1.mydomain.com.key \
    sub2.mydomain.com.crt sub2.mydomain.com.key \
    sub3.mydomain.com.crt sub3.mydomain.com.key \
    > /etc/haproxy/certs/mydomain.com.pem

2. Debugging Tips: Enable detailed logging by adding to your global section:

global
    log /dev/log local0 debug
    log-tag HAProxy

For high-traffic environments, consider these optimizations:

  • Enable SSL session caching
  • Implement connection rate limiting
  • Use separate frontends for HTTP/HTTPS if needed
# SSL performance tuning example
global
    tune.ssl.default-dh-param 2048
    ssl-default-bind-ciphers ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384
    ssl-default-server-ciphers ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384