Optimizing HAProxy Configuration: Routing Multiple Subdomains to Single Backend with Regex and ACLs


2 views

When managing multiple subdomains in HAProxy, many administrators find themselves creating individual ACL entries for each subdomain. While this approach works, it becomes cumbersome when dealing with dozens or hundreds of subdomains that should route to the same backend.

# Current verbose configuration example
frontend http-in
    bind *:80
    
    # Multiple ACLs for similar subdomains
    acl sub1 hdr(host) -i apple.example.com
    acl sub2 hdr(host) -i banana.example.com
    acl sub3 hdr(host) -i cherry.example.com
    
    # Redundant backend assignments
    use_backend fruits_backend if sub1
    use_backend fruits_backend if sub2
    use_backend fruits_backend if sub3

The more efficient approach is to use regular expressions to match patterns of subdomains:

frontend http-in
    bind *:80
    
    # Match all fruit subdomains with a single regex
    acl fruits hdr_reg(host) -i ^(apple|banana|cherry|durian|elderberry|fig|grapefruit)\.example\.com
    
    # Match the main domain
    acl main_domain hdr(host) -i example.com
    
    # Route traffic based on ACLs
    use_backend fruits_backend if fruits
    use_backend main_backend if main_domain

For complex routing scenarios, you can combine different matching methods:

frontend http-in
    bind *:80
    
    # First method: Exact matches for critical domains
    acl admin hdr(host) -i admin.example.com
    
    # Second method: Wildcard subdomains
    acl api_subdomains hdr_end(host) -i .api.example.com
    
    # Third method: Regex patterns
    acl product_pages hdr_reg(host) -i ^product-[a-z0-9]+\.example\.com
    
    # Route traffic appropriately
    use_backend admin_backend if admin
    use_backend api_backend if api_subdomains
    use_backend products_backend if product_pages

When evaluating regex vs. multiple ACLs:

  • Regex becomes more efficient when matching 5+ subdomains
  • Simple exact matches (hdr()) are fastest for 1-4 specific subdomains
  • hdr_end() performs better than regex for matching all subdomains under a domain
  • Consider compiling regex patterns with -m reg for high-traffic setups

Here's a complete example implementing these techniques:

frontend http-in
    bind *:80
    bind *:443 ssl crt /etc/ssl/example.com.pem
    
    # Main domains
    acl primary hdr(host) -i example.com
    acl www hdr(host) -i www.example.com
    
    # Subdomain categories
    acl fruits hdr_reg(host) -i ^(apple|banana|cherry)\.example\.com
    acl vegs hdr_end(host) -i .vegetables.example.com
    acl legacy hdr_beg(host) -i legacy-
    
    # SSL redirect
    redirect scheme https if !{ ssl_fc }
    
    # Routing logic
    use_backend main_cluster if primary or www
    use_backend fruits_server if fruits
    use_backend vegetable_servers if vegs
    use_backend legacy_backend if legacy
    
    default_backend maintenance_page

backend main_cluster
    balance roundrobin
    server server1 10.0.0.1:80 check
    server server2 10.0.0.2:80 check

backend fruits_server
    server fruit1 10.0.1.1:8080 check

For more complex scenarios, you can use map files:

# In haproxy.cfg
frontend http-in
    bind *:80
    use_backend %[req.hdr(host),lower,map_dom(/etc/haproxy/domain_mappings.map,default_backend)]

# In /etc/haproxy/domain_mappings.map
alpha.com alpha_backend
beta.com beta_backend
*.gamma.com gamma_backend
# Catch-all
.example.com default_backend

When dealing with multiple subdomains that need to be routed to the same backend in HAProxy, many developers find themselves writing repetitive ACL entries like this:

acl gamma00   hdr(host) -i apple.gamma.com
acl gamma01   hdr(host) -i banana.gamma.com
acl gamma02   hdr(host) -i cherry.gamma.com

This approach becomes unwieldy when managing dozens of subdomains, making the configuration file unnecessarily long and harder to maintain.

A more elegant solution uses regular expressions to match patterns in the subdomains:

frontend http-in
    bind *:80
    
    # Match specific domains
    acl alpha hdr(host) -i alpha.com
    acl beta  hdr(host) -i beta.com
    acl gamma hdr(host) -i gamma.com
    
    # Match subdomains using regex
    acl fruits hdr_reg(host) -i ^(apple|banana|cherry|durian|elderberry|fig|grapefruit)\.gamma\.com$
    
    use_backend a if alpha
    use_backend b if beta
    use_backend g if gamma
    use_backend sub1 if fruits
    use_backend sub2 if other_condition
    
    default_backend default

While regex matching is slightly more CPU-intensive than exact string matching, the difference is negligible for most use cases. The maintenance benefits outweigh the minimal performance impact:

  • Simpler configuration files
  • Easier to add new subdomains
  • More readable at a glance

For even more flexibility, you can use wildcard matching for dynamic subdomains:

acl wildcard_fruits hdr_end(host) -i .fruits.gamma.com

This would match any subdomain ending with ".fruits.gamma.com" like "apple.fruits.gamma.com" or "banana.fruits.gamma.com".

For very large numbers of subdomains, consider using maps for better performance:

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

With a map file like:

alpha.com a
beta.com b
gamma.com g
apple.gamma.com sub1
banana.gamma.com sub1
cherry.gamma.com sub1
durian.gamma.com sub2
*.fruits.gamma.com sub3
  • Always test new regex patterns thoroughly
  • Consider performance impact when using complex patterns
  • Document your routing logic clearly
  • Use comments in your configuration