How to Modify URL Paths While Preserving Query Parameters in HAProxy


16 views

When migrating applications or restructuring endpoints, we often need to modify URL paths while preserving the original query parameters. The standard approach using path_dir and set-path might not work as expected due to HAProxy's path processing behavior.

Here's what typically doesn't work:

acl old_name path_dir -i /old_name
http-request set-path /new_name/%[query] if old_name

This would transform /old_name/Default.aspx?Id=123 into /new_name/?Id=123, losing the actual file path component.

We need to capture both the base path and subsequent path components. Here's the correct approach:

acl is_old_path path_beg -i /old_name/
http-request set-path /new_name%[path,regsub(^/old_name/,/)] if is_old_path

This solution:

  • Uses path_beg for more precise matching
  • Preserves the query parameters automatically
  • Maintains the file path after the base directory

For a production-ready setup:

frontend http_in
    bind *:80
    acl is_old_path path_beg -i /old_name/
    http-request redirect code 301 location /new_name%[path,regsub(^/old_name/,/)] unless { path_beg -i /new_name/ }
    http-request set-path /new_name%[path,regsub(^/old_name/,/)] if is_old_path
    use_backend app_servers

backend app_servers
    server s1 192.168.1.10:8080 check

For complex rewrites with multiple path components:

http-request set-path /new_name/v2%[path,regsub(^/old_name/v1/,/)] if { path_beg -i /old_name/v1/ }

This handles versioned API endpoints while maintaining all URL components.

Always verify your configuration with:

haproxy -c -f /etc/haproxy/haproxy.cfg

And test with curl:

curl -v "http://localhost/old_name/Default.aspx?Id=123"

When migrating applications with renamed endpoints in HAProxy, we often need to modify just part of the URL path while preserving all query parameters. A common case is when an application changes its base path from /old_name to /new_name but maintains the same file structure and query parameters.

The configuration you tried:

acl old_name path_dir -i /old_name
http-request set-path /new_name/%[query] if old_name

has several issues:

  • %[query] only includes the query string (everything after ?)
  • It completely replaces the path instead of modifying part of it
  • The original path components after /old_name/ are lost

Here's the correct approach using HAProxy 1.8+ syntax:

acl is_old_path path_beg -i /old_name/
http-request replace-path /old_name/(.*) /new_name/\1 if is_old_path

For HAProxy 2.0+, you can use more advanced regex:

http-request replace-path ^/old_name(/.*)?$ /new_name\1 if { path_beg /old_name/ }

Here's a full frontend configuration that handles the redirection:

frontend http-in
    bind *:80
    acl is_old_path path_beg -i /old_name/
    
    # Option 1: Simple path replacement
    http-request replace-path /old_name/(.*) /new_name/\1 if is_old_path
    
    # Option 2: Alternative using regex capture (HAProxy 2.2+)
    # http-request replace-path ^/old_name(/.*)?$ /new_name\1 if is_old_path
    
    # Send to backend
    use_backend app_servers if { path_beg /new_name/ }
    default_backend app_servers

The above configuration will transform:

http://www.site.com/old_name/Default.aspx?Id=123

into:

http://www.site.com/new_name/Default.aspx?Id=123

while preserving all path components after /old_name/ and all query parameters.

For more complex scenarios:

  1. Multiple path changes: Chain multiple replace-path rules
  2. Host-based routing: Combine with req.hdr(host) conditions
  3. 301 Redirects: Use 'redirect' instead for permanent changes