When using HAProxy for path-based routing, you might encounter situations where you need to strip URI prefixes before forwarding requests to backend servers. A common scenario is when you have multiple applications under different path prefixes but want to serve them from the root context on backend servers.
Here's the current HAProxy configuration that's not working as expected:
frontend webVIP_80
mode http
bind :80
acl web1_path path_beg /web1
acl web2_path path_beg /web2
use_backend webfarm1 if web1_path
use_backend webfarm2 if web2_path
default_backend webfarm1
backend webfarm1
mode http
reqrep ^([^\ ]*)\ /web1/(.*) \1\ /\2
balance roundrobin
option httpchk HEAD /index HTTP/1.1\r\nHost:\ example.com
server webtest1 10.0.0.10:80 weight 5 check slowstart 5000ms
server webtest2 10.0.0.20:80 weight 5 check slowstart 5000ms
backend webfarm2
mode http
reqrep ^([^\ ]*)\ /web2/(.*) \1\ /\2
balance roundrobin
option httpchk HEAD /index HTTP/1.1\r\nHost:\ example.com
server webtest1-farm2 10.0.0.110:80 weight 5 check slowstart 5000ms
server webtest2-farm2 10.0.0.120:80 weight 5 check slowstart 5000ms
The issue lies in the regular expression pattern matching. Here's how to fix it:
backend webfarm1
mode http
reqrep ^([^\ ]*)\ /web1(.*) \1\ \2
# rest of the configuration...
backend webfarm2
mode http
reqrep ^([^\ ]*)\ /web2(.*) \1\ \2
# rest of the configuration...
Another modern approach is to use the 'http-request set-path' directive in newer HAProxy versions:
backend webfarm1
mode http
http-request set-path %[path,regsub(^/web1/,/)]
# rest of the configuration...
backend webfarm2
mode http
http-request set-path %[path,regsub(^/web2/,/)]
# rest of the configuration...
To verify your configuration is working:
curl -v http://domain/web1/test.html
curl -v http://domain/web2/test.html
Check your backend server logs to confirm the requests are arriving without the /web1 or /web2 prefixes.
1. The regex must match the exact path prefix
2. Beware of trailing slashes in your paths
3. Check HAProxy logs for regex compilation errors
4. Ensure your backend servers can handle the modified paths
For high-traffic environments, consider:
- Using newer 'http-request' directives instead of reqrep
- Minimizing regex complexity
- Testing with real traffic patterns
When working with HAProxy as a reverse proxy, a common requirement is to route requests to different backend pools based on URI prefixes while stripping those prefixes before forwarding to the backend servers. Here's what's happening in the current setup:
http://domain/web1 → should go to webfarm1 as /
http://domain/web2 → should go to webfarm2 as /
The existing configuration has two issues:
# This works for routing but not for URI rewriting
reqrep ^([^\\ ]*)\\ /web1/(.*) \\1\\ /\\2
The regular expression fails because:
- It expects a trailing slash after /web1 or /web2
- It doesn't handle cases where the path ends at /web1 without subsequent characters
Here's the corrected configuration that properly handles URI rewriting:
frontend webVIP_80
mode http
bind :80
acl web1_path path_beg /web1
acl web2_path path_beg /web2
use_backend webfarm1 if web1_path
use_backend webfarm2 if web2_path
default_backend webfarm1
backend webfarm1
mode http
# Handle both /web1/... and /web1 cases
reqrep ^([^\ ]*)\ /web1(/.*)? \1\ \2
balance roundrobin
server webtest1 10.0.0.10:80 check
backend webfarm2
mode http
reqrep ^([^\ ]*)\ /web2(/.*)? \1\ \2
balance roundrobin
server webtest1-farm2 10.0.0.110:80 check
The modified regex pattern makes two critical changes:
^([^\ ]*)\ /web1(/.*)? \1\ \2
- Makes the trailing path optional with
(/.*)?
- Properly handles spaces in the match with
[^\ ]
instead of[\\ ]
Verify the behavior with curl:
curl -I http://domain/web1
curl -I http://domain/web2/some/path
Check the backend access logs to confirm the received paths are correctly modified.
For HAProxy 1.7+, consider using http-request replace-path
:
backend webfarm1
http-request replace-path /web1(/)?(.*) /\2