How to Route Specific URIs to Different Backend Servers Using HAProxy ACL Rules


9 views

When implementing HAProxy as a load balancer, there are scenarios where you need to route traffic based on URI patterns rather than just distributing requests across a server farm. This is particularly useful when certain endpoints require specialized handling or when you're gradually migrating services.

To route requests with URI '/special' to a dedicated server while maintaining the existing round-robin distribution for other requests, we'll use ACL (Access Control List) rules in HAProxy. Here's how to modify the configuration:

listen webfarm 10.254.23.225:80
    mode http
    balance roundrobin
    cookie SERVERID insert
    option httpclose
    option forwardfor
    option httpchk HEAD /check.txt HTTP/1.0
    
    # Define ACL for special URI
    acl is_special_path path_beg /special
    
    # Use dedicated server for special path
    use_backend special_backend if is_special_path
    
    # Original server definitions
    server webA 10.254.23.4:80 cookie A check
    server webB 10.248.23.128:80 cookie B check

backend special_backend
    mode http
    option httpclose
    option forwardfor
    server webSpecial 10.254.23.200:80 check

For more complex routing scenarios, consider these additional examples:

# Multiple path patterns
acl is_api_path path_beg /api /rest /graphql
use_backend api_backend if is_api_path

# Regular expression matching
acl is_legacy_path path_reg ^/legacy/.*$
use_backend legacy_backend if is_legacy_path

# Host-based routing combined with path
acl is_special_host hdr(host) -i special.example.com
use_backend special_backend if is_special_host || is_special_path

When implementing URI-based routing:

  • Place more specific rules before generic ones
  • Use simple string matches (path_beg) before regex when possible
  • Monitor ACL hit ratios to optimize rule ordering
  • Consider using maps for large numbers of routing rules

Here's a full configuration demonstrating various routing techniques:

frontend http_in
    bind *:80
    mode http
    
    # Define ACLs
    acl is_static path_beg /static /images /css /js
    acl is_api path_beg /api /v1 /v2
    acl is_admin path_beg /admin
    acl is_special path_beg /special
    
    # Routing logic
    use_backend static_servers if is_static
    use_backend api_servers if is_api
    use_backend admin_servers if is_admin
    use_backend special_server if is_special
    default_backend web_servers

backend static_servers
    server static1 10.0.0.10:80 check
    server static2 10.0.0.11:80 check

backend api_servers
    server api1 10.0.0.20:80 check
    server api2 10.0.0.21:80 check

backend admin_servers
    server admin1 10.0.0.30:80 check

backend special_server
    server special1 10.0.0.40:80 check

backend web_servers
    balance roundrobin
    server web1 10.0.0.50:80 check
    server web2 10.0.0.51:80 check

When working with HAProxy as a load balancer, there are cases where you need to route specific URI paths to designated backend servers while maintaining general traffic distribution for other paths. This is particularly useful when:

  • Certain paths require special processing
  • You need to offload specific functionality to dedicated servers
  • Implementing canary releases for specific routes

Here's a typical HAProxy configuration that we'll enhance:

listen webfarm 10.254.23.225:80
    mode http
    balance roundrobin
    cookie SERVERID insert
    option httpclose
    option forwardfor
    option httpchk HEAD /check.txt HTTP/1.0
    server webA 10.254.23.4:80 cookie A check
    server webB 10.248.23.128:80 cookie B check

To route /special path to a third server while maintaining existing routing:

frontend http_in
    bind 10.254.23.225:80
    mode http
    
    # Route /special to dedicated server
    acl is_special path_beg /special
    use_backend special_backend if is_special
    
    # Default traffic goes to webfarm
    default_backend webfarm

backend webfarm
    balance roundrobin
    cookie SERVERID insert
    option httpclose
    option forwardfor
    option httpchk HEAD /check.txt HTTP/1.0
    server webA 10.254.23.4:80 cookie A check
    server webB 10.248.23.128:80 cookie B check

backend special_backend
    server webSpecial 10.254.23.50:80 check

For more complex routing needs:

# Multiple path-based routing
acl api_path path_beg /api/
acl admin_path path_beg /admin/
acl static_path path_beg /static/

use_backend api_servers if api_path
use_backend admin_servers if admin_path
use_backend static_servers if static_path

HAProxy provides several path matching methods:

  • path_beg: Match beginning of path
  • path_end: Match end of path
  • path: Exact path match
  • path_sub: Substring match anywhere in path

When implementing path-based routing:

  • Order ACLs from most specific to least specific
  • Place frequently matched paths earlier
  • Consider using req.uri for more complex matching
  • Monitor performance impact with show sess command

Here's a production-ready configuration snippet:

frontend main
    bind *:80
    mode http
    
    # Health check endpoint
    acl health path /health
    monitor-uri /health
    
    # Special paths routing
    acl static path_beg /static/
    acl api path_beg /api/
    acl admin path_beg /admin/
    
    use_backend static_servers if static
    use_backend api_servers if api
    use_backend admin_servers if admin
    
    default_backend web_servers

backend web_servers
    balance leastconn
    cookie SERVERID insert
    server web1 192.168.1.10:80 cookie s1 check
    server web2 192.168.1.11:80 cookie s2 check

backend static_servers
    server static1 192.168.1.20:80 check
    
backend api_servers
    server api1 192.168.1.30:8080 check
    server api2 192.168.1.31:8080 check
    
backend admin_servers
    server admin1 192.168.1.40:80 check