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