I have a complex Apache config that mostly just does ProxyPassReverse, and that seems pretty silly so I've been converting it to haproxy. Mostly this has led to things being much, much simpler and clearer; yay. The exception is complex RewriteRule and RedirectMatch sorts of things. In particular, I have these:
RewriteRule ^(?:/l?mw)+/(.*\.php.*)$ https://mw-live.lojban.org/$1 [R=301,L]
RewriteRule ^(?:/l?mw)+/(.*)$ https://mw-live.lojban.org/papri/$1 [R=301,L]
The intent here is to redirect requests to, for example, /lmw/mw/lmw/foo.php to /foo.php, and /mw/lmw/mw/MyPage with /papri/MyPage (yes, those URLs are weird; an old version of the site had some redirect problems).
As far as I can tell, the right way to do this is really not to do it in haproxy, and use the back-end web service itself. I'm asking about it in case I'm missing something, but it really seems like doing this sort of thing on the back-end web service works way better than doing it in haproxy.
I'm having 2 problems with trying to do this in haproxy:
I can't find a way to get haproxy to record the redirects that it itself performs. I've told haproxy to show me the Location response header, but that only shows redirects from the back-end server:
capture response header Location len 128
The ways of doing this in haproxy are ... clunky. I've found two ways that seem to work:
# Old URL formats; trim leading "/mw" and "/lmw" when the target is a php file http-request redirect code 301 location http://%[hdr(host)]%[url,regsub(^/lmw,,g)] if { path_beg /lmw } { path_sub .php } http-request redirect code 301 location http://%[hdr(host)]%[url,regsub(^/mw,,g)] if { path_beg /mw } { path_sub .php } # Old URL formats; trim leading "/mw" and "/lmw" http-request redirect code 301 location http://%[hdr(host)]/papri%[url,regsub(^/lmw,,g)] if { path_beg /lmw } http-request redirect code 301 location http://%[hdr(host)]/papri%[url,regsub(^/mw,,g)] if { path_beg /mw } http-request redirect code 301 location http://%[hdr(host)]/papri%[url,regsub(^/papri/lmw,,g)] if { path_beg /papri/lmw } http-request redirect code 301 location http://%[hdr(host)]/papri%[url,regsub(^/papri/mw,,g)] if { path_beg /papri/mw }
The problem with this method, besides it being many lines long, is that it produces a series of redirects, repeatedly redirecting each URL to one with one less /mw or whatever.
The other is having this on the front end:
use_backend mw-live-back-old-with-php if { hdr_beg(host) -i mw-live. } { path_reg ^/l?mw.*\.php }
use_backend mw-live-back-old-without-php if { hdr_beg(host) -i mw-live. } { path_reg ^/l?mw }
and then these special backends to go with it:
backend mw-live-back-old-with-php
http-request replace-path ^(?:/l?mw)+/(.*\.php.*)$ /\1
http-request redirect prefix / code 301
backend mw-live-back-old-without-php
http-request replace-path ^(?:/l?mw)+/(.*) /papri/\1
http-request redirect prefix / code 301
The problem with this method is that it's also super long, but also it seems silly to create backends just for this.
The thing you'd think would work, which I stole from https://fromanegg.com/post/2014/12/05/how-to-rewrite-and-redirect-with-haproxy/ , is having these lines as part of the generic backend.
http-request replace-path ^(?:/l?mw)+/(.*\.php.*)$ /\1 if { path_reg ^/l?mw.*\.php }
http-request redirect prefix / code 301 if { path_reg ^/l?mw.*\.php }
http-request replace-path ^(?:/l?mw)+/(.*)$ /papri/\1 if { path_reg ^/l?mw }
http-request redirect prefix / code 301 if { path_reg ^/l?mw }
This fails because the redirect never fires, because by the time we get to the redirect line, the path_reg no longer matches.
So.
Am I missing something, or should I really just move this sort of complexity to the back-end web service?
Bingo. There's no need to reinvent the wheel here.