How to Configure HAProxy URL Path-Based Routing with ACL and path_beg for URI Substring Matching


2 views

When working with HAProxy as a load balancer, we often need to route requests to different backend servers based on URI patterns. In this scenario, we need to distinguish between two types of requests:


http://example.com/answers/submit
http://example.com/tag-02/answers/submit

The key difference is the presence of /tag-02/ in the path. We'll use HAProxy's ACL (Access Control List) feature combined with the path_beg matching method to implement this logic.

Here's the complete configuration that implements the routing logic:


global
    log /dev/log local0
    log /dev/log local1 notice
    chroot /var/lib/haproxy
    stats socket /run/haproxy/admin.sock mode 660 level admin
    stats timeout 30s
    user haproxy
    group haproxy
    daemon

defaults
    log global
    mode http
    option httplog
    option dontlognull
    timeout connect 5000
    timeout client 50000
    timeout server 50000

frontend http-in
    bind *:80
    acl has_tag path_beg /tag-02/
    use_backend tagged_backend if has_tag
    default_backend default_backend

backend default_backend
    balance roundrobin
    server server1 192.168.1.10:80 check
    server server2 192.168.1.11:80 check

backend tagged_backend
    balance roundrobin
    server server3 192.168.1.12:80 check
    server server4 192.168.1.13:80 check

The critical part of this configuration is in the frontend section:


acl has_tag path_beg /tag-02/
use_backend tagged_backend if has_tag
default_backend default_backend

This creates an ACL named has_tag that matches any request where the path begins with /tag-02/. The path_beg matching method is perfect for our use case as it checks the beginning of the URL path.

HAProxy offers several path matching options depending on your needs:


# Exact path match
acl exact_match path /exact/path

# Beginning of path (what we used)
acl path_beg_match path_beg /prefix

# Directory-like match (contains)
acl path_dir_match path_dir /directory

# Regular expression match
acl path_regex_match path_reg ^/regex/pattern

After implementing the configuration, test it with curl commands:


# This will go to default_backend
curl http://example.com/answers/submit

# This will go to tagged_backend
curl http://example.com/tag-02/answers/submit

When using ACLs for routing:

  • path_beg is generally faster than regex matches
  • Place more frequently matched ACLs first
  • Consider using path_dir if you need to match a whole directory structure
  • For complex routing, combine multiple ACLs with logical operators

You can extend this approach with additional conditions:


frontend http-in
    bind *:80
    acl has_tag path_beg /tag-02/
    acl is_api path_beg /api/
    acl is_post method POST
    
    # Route /tag-02/api/ POST requests to special backend
    use_backend special_api_backend if has_tag is_api is_post
    
    # Default routing rules
    use_backend tagged_backend if has_tag
    default_backend default_backend

When working with HAProxy, a common requirement is to route traffic based on specific patterns in the request URI. In this scenario, we need to direct requests either to backend server A or B depending on whether the URI contains the '/tag-02/' substring.

Here's the fundamental structure of our HAProxy configuration:

frontend http_in
    bind *:80
    mode http
    
    # Routing rules will go here
    
    default_backend default_backend

backend backend_a
    server server1 192.168.1.10:80 check

backend backend_b
    server server2 192.168.1.11:80 check

backend default_backend
    server server3 192.168.1.12:80 check

The key to solving this is using ACLs (Access Control Lists) with path pattern matching:

frontend http_in
    bind *:80
    mode http
    
    # Define ACL for our specific path pattern
    acl has_tag_02 path_sub /tag-02/
    
    # Route based on ACL
    use_backend backend_b if has_tag_02
    use_backend backend_a if !has_tag_02
    
    default_backend default_backend

HAProxy offers several ways to match path patterns. Here are three common approaches:

# Method 1: Exact path match
acl is_exact_path path /answers/submit

# Method 2: Path begins with
acl starts_with_path path_beg /tag-02/

# Method 3: Regular expression match
acl regex_path path_reg ^/tag-[0-9]+/

Here's a full configuration file demonstrating the solution:

global
    log /dev/log local0
    log /dev/log local1 notice
    daemon
    maxconn 256

defaults
    log global
    mode http
    timeout connect 5000ms
    timeout client 50000ms
    timeout server 50000ms

frontend http_front
    bind *:80
    acl has_tag path_sub /tag-02/
    use_backend tag_backend if has_tag
    default_backend main_backend

backend main_backend
    balance roundrobin
    server main1 10.0.0.1:80 check
    server main2 10.0.0.2:80 check

backend tag_backend
    server tag1 10.0.0.3:80 check
    server tag2 10.0.0.4:80 check

When implementing path-based routing:

  • path_beg is generally faster than path_sub
  • For complex patterns, consider using maps for better performance
  • Too many ACLs can impact performance - keep them minimal

After implementing, test with these curl commands:

# Should go to backend_a
curl http://localhost/answers/submit

# Should go to backend_b
curl http://localhost/tag-02/answers/submit

If you have multiple tags to handle, consider using maps:

frontend http_front
    bind *:80
    use_backend %[path,map(/etc/haproxy/tag_map.map)] if { path,map(/etc/haproxy/tag_map.map) -m found }
    default_backend main_backend

With tag_map.map containing:

/tag-01/ tag_backend
/tag-02/ tag_backend
/special/ special_backend