HAProxy community

Reqrep after acl definition?

HA-Proxy version 1.8.15 2018/12/13

I need a url to:
a) redirect to the correct back end
b) be rewritten for the back end request

I use acls to check that the path is one to be redirected and rewritten. the acl is also used to select the appropriate back end. then i use reqrep to rewrite the request url. However, it seems as though I can only do one or the other, but not both.

Example:
https://www.example.com/path/abc/to/rewrite --> should go to back end A
https://www.example.com/path/def/to/rewrite --> should go to back end B
both urls should be rewritten as /path/to/rewrite on the back end.

If I use an acl to redirect to the appropriate back end, it works but the url is of course not rewritten.
If I use reqrep to rewrite the back end request, it rewrites the url but goes to my default back end.

Am I correct in thinking that ACLs are checked using the original path, and not the rewritten one? Or are ACLs checked after any reqrep?

I’ll post my full config in a reply.

global
log 127.0.0.1 local0

chroot      /var/lib/haproxy
pidfile     /var/run/haproxy.pid
maxconn     4000
user        haproxy
group       haproxy
daemon

# turn on stats unix socket
stats socket /var/lib/haproxy/stats

# utilize system-wide crypto-policies
ssl-default-bind-ciphers PROFILE=SYSTEM
ssl-default-server-ciphers PROFILE=SYSTEM

tune.ssl.default-dh-param 2048

defaults
mode http
log global
option httplog
option dontlognull
#option http-server-close
option forwardfor except 127.0.0.0/8
option redispatch
retries 3
timeout http-request 5m
timeout queue 1m
timeout connect 30s
timeout client 60s
timeout server 600s
timeout tunnel 600s
timeout http-keep-alive 10s
timeout check 10s
maxconn 3000

frontend main
bind *:80
bind *:443 ssl crt /etc/ssl/www.[redacted].com/www.[redacted].com.pem

# Test URI to see if its a letsencrypt request
acl letsencrypt-acl path_beg /.well-known/acme-challenge/

acl is_root path -i /
acl is_dashboard path_beg /tools/
acl is_profit_report path_sub /Amazon/amzfba_daily_sales
acl is_hc_profit_report path_beg /tools/uploads/hc/Amazon/amzfba_daily_sales
acl is_yne_profit_report path_beg /tools/uploads/yne/Amazon/amzfba_daily_sales
acl dash_sess_cookie_set cook(dashboard) -m found   # has dashboard session ever started?
acl dash_which_cookie_set cook(which) -m found      # dashboard instance chosen
acl lp_cookie_set cook(LP) -m found                 # has the landing page cookie been set

http-request set-var(txn.hostname) req.hdr(Host),field(1,:),lower
http-request set-var(txn.which) req.cook(which) if dash_which_cookie_set
http-response add-header Set-Cookie LP=%[var(txn.hostname)] if !lp_cookie_set

# not root url, no server chosen: redirect to root url
http-request redirect location https://%[var(txn.hostname)]/ if is_dashboard !dash_which_cookie_set !is_profit_report

# redirect http://[redacted].com to https://www.[redacted].com
http-request redirect prefix https://www.%[hdr(host)] code 301 if { hdr(host) -i [redacted].com }
http-request redirect prefix https://%[hdr(host)] code 301 if { hdr(host) -i www.[redacted].com } !{ ssl_fc letsencrpyt-acl }

# profit report - URL rewrite for the back-end
reqrep ^([^\ :]*)\ /tools/uploads/hc/(.*) \1\ /tools/uploads/\2 if is_hc_profit_report

# Always use SSL, unless Let's Encrypt
redirect scheme https if !{ ssl_fc } !letsencrypt-acl

# Let's Encrypt
use_backend letsencrypt if letsencrypt-acl

# profit report - select the appropriate back-end
use_backend hc if is_hc_profit_report
use_backend yne if is_yne_profit_report

use_backend landing_page if !dash_sess_cookie_set # No session cookie, start at the landing page
use_backend %[var(txn.which)] if dash_which_cookie_set

default_backend landing_page # all other checks failed, start at the landing page

backend letsencrypt
server letsencrypt 127.0.0.1:8888 id 999

backend landing_page
server landingpage XXX.XXX.20.200:80 id 1

backend cpeg
server cpeg XXX.XXX.20.209:80 id 2
backend hc
server hc XXX.XXX.20.205:80 id 3
backend hph
server hph XXX.XXX.20.208:80 id 4
backend ilhg
server ilhg XXX.XXX.20.210:80 id 5
backend mpceg
server mpceg XXX.XXX.20.211:80 id 6
backend thds
server thds XXX.XXX.20.206:80 id 7
backend yne
server yne XXX.XXX.20.207:80 id 8

reqrep happens after all traffic processing rules are applied, once the backend server is selected and haproxy is about to send the request. That’s why your ACLs can’t match the value you set after reqrep.
reqrep is deprecated and will be removed with haproxy 2.1.

you should use http-request set-path instead of reqrep here.
ie:
http-request set-path %[path,regsub(^/tools/uploads/hc/,/tools/uploads/)]

any rule/acl using path after that will have the updated value.

Jerome,
Thank you for the reply.

So, regardless of method used (http-request set-path, reqrep), there is no way to set the acl before the url rewrite? I’ll have to go another route with mod_rewrite or similar to change the path once the back-end is selected.

At least with http-request rules, you have different options, unlike reqrep and friends.

You can move the http-request set-path rule in backend, this way any acl using path for the use_backend can match the original value. Or you can store the value of path in a variable, and keep http-request set-path in the frontend, and use_backend based on variable value.

http-request set-var(req.path) path
http-request set-path %[path,regsub(^/tools/uploads/hc/,/tools/uploads/)]
use_backend foo if { var(req.path) bar }
1 Like

tink

that sound you just heard was me having an epiphany. Thank you so much Jerome! You are a gentleman, and a scholar.

I moved the rewrite to the back end, and it’s working great!

1 Like