How to remove query string with reqrep in Haproxy backend? - haproxy

I am trying to write a reqrep query to try and strip out a query string. I am using ACLs with urlp_end to direct to the correct backend, but the query string that is being used for that is being passed over to the backend.
The frontend uses an ACL like this:
acl Test_ACL urlp_end(device) -m str eq 14110
use_backend Device_1 if Test_ACL
In my backend I just have the server IP, but i would like to remove the device parameter in the backend. Here is an example:
https://example.com/chkimg/FRONT200GRAY8_1.JPG?device=14110
This forwards to the right backend. Basically all i want to do is in the backend traffic, strip the "?device=______" parameter from the URL, so that it just forwards this to the backend, with the entire device parameter invisible to the backend server:
https://example.com/chkimg/FRONT200GRAY8_1.JPG

Member on Haproxy forum answered this for me
http-request set-uri %[path]

Related

Haproxy - 301/302 redirect URL1 to URL2 with all pathes

I'm a little bit lost atm. I try to implement a redirect within a complex HAproxy configuration. The goal is simple:
user uses a subdomain -> 123.domain.com
user will be pointed to api.domain.com but thinks it's still on 123.domain.com
user should be able to use pathes like 123.domain.com/123?123 but still get results from api.domain.com/123?123 but thinks it's gets result from 123.domain.com/123?123.
I'm totally unsure how to implement that without taking the rist of taking down production traffic.
What i would do:
creating ACL rule in SSL frontend to point to the api backend when 123.domain.de is used.
redirect prefix http://123.domain.com code 301 if { hdr(host) -i api.domain.com }
Not usre if that would work.
creating redirection rule pointing simply to another api url:
redirect location https://www.mysites/v2/pages 302 if { hdr(host) -i api.domain.com }
It's hard to implement this wihtout taking a risk of an outage. Is there something who could know the answer?
First I would recommend that you have a development and/or staging environment configured to test any changes before you make them.
To do a 301 redirect of all traffic coming from 123.domain.com to api.domain.com you can use the following
http-request redirect prefix http://api.domain.com code 301 if { hdr(host) -i 123.domain.com }
If you wanted HAProxy to connect to the api.domain.com backend on the users behalf and mask the hostname itself you would add a backend for api.domain.com and then create a use_backend rule. Keep in mind that with the below there are no 301/302 redirects performed, instead HAProxy makes the connection on behalf of the client.
Something like this would work:
use_backend api.domain.com if { hdr(host) -i 123.domain.com }
Then within api.domain.com backend you can update the Host header.
backend api.domain.com
http-request set-header Host api.domain.com
server api1 api.domain.com:80 check

HAProxy http response rewrite rspirep string

Scenario is HAProxy as a reverse-proxy for a Docker user-defined network, so the servers are reachable by service name from HAProxy. Inbound works, but I can't seem to get the response rewrite to work.
I need any traffic, foo.com/api/* to be redirected to api:9999/*.
Current config
frontend https
acl api path_beg /api
use_backend api if api
backend api
reqrep ^([^\ ]*\ /)api[/]?(.*) \1\2
rspirep (.*) /api/
server api api:9999 check
I'm pretty sure this is what's needed, but I suspect my rspirep string is NOT correct. Any help is appreciated!

pass a backend from backend map to haproxy nbsrv

Can someone advise what I have to change in the nbsrv expression in order to make it work:
frontend webfarm
bind 11.22.33.44:80
...
acl MAIN_not_enough_capacity nbsrv([%[req.hdr(host),lower,map(/etc/haproxy/backend.map,bk_default)]]) eq 0
http-request redirect code 301 location http://global-swajm.example.com if MAIN_not_enough_capacity
use_backend %[req.hdr(host),lower,map(/etc/haproxy/backend.map,bk_default)]
The idea is according to the host in the header to get the right backend name from the map file.
If there are no available servers in this backend the request will be redirected to another haproxy (in another DC).
use_backend is working perfectly:
use_backend %[req.hdr(host),lower,map(/etc/haproxy/backend.map,bk_default)]
but I don't know how to modify the expression for nbsrv in order to pass the backend name:
nbsrv([%[req.hdr(host),lower,map(/etc/haproxy/backend.map,bk_default)]])
just chiming in after having struggled with the same
Use
acl MAIN_not_enough_capacity req.hdr(host),lower,map(/etc/haproxy/backend.map,bk_default),nbsrv eq 0
instead

HAProxy reqrep not replacing string in url

We have deprecated some software which was available under http://localhost/test and is now available under http://localhost/app/testing. We are using HAProxy 1.4
Thus, I want via haproxy, to replace all urls containing /test with /app/testing/. I tried first with a redirect prefix in order to keep the query string, but /test wasn't removed from the url and had something like /app/testing/test/?id=x.
frontend all
bind 0.0.0.0:80
timeout client 86400000
acl is_test path_beg /test
redirect prefix /app/testing code 301 if is_test
Then used a reqrep, which seems to redirect to the new software, but the /test string in the url is never replaced.
frontend all
bind 0.0.0.0:80
timeout client 86400000
reqrep ^([^\ :]*)\ /test[/]?(.*) \1\ /app/testing/\2
Since url rewriting isn't possible with version 1.4 and we didn't want to update HAProxy, we went on using reqrep and keeping the old link as is with
reqrep ^([^\ :]*)\ /test[/]?(.*) \1\ /app/testing/\2
Try this
This works for me with your scenario on HAProxy 1.6
acl test path_beg -i /test
http-request set-header X-Location-Path %[capture.req.uri] if test
http-request replace-header X-Location-Path /test /app/testing if test
http-request redirect location %[hdr(X-Location-Path)] if test
use_backend WHEREVER if test
Using redirect prefix is meant, going by the HAProxy examples, more for changing the hostname, but keeping the path. For example, http://apple.com/my/path could be redirected to http://orange.com/my/path with:
redirect prefix http://orange.com if apple
The HAProxy 1.4 docs say:
With "redirect prefix", the "Location" header is built from the
concatenation of < pfx > and the complete URI path
To me, that suggests that you would expect whatever you put for the "prefix" will be prefixed to what was already in the path. That explains the behavior you were seeing. This is useful for changing to a new domain (e.g. from apple.com to orange.com), but keeping the original path (e.g. /my/path).
You can switch to using redirect location to replace the entire URL. The following would redirect http://apple.com/my/path to http://orange.com/path:
redirect location http://orange.com/path if apple
UPDATE:
In the case where you want to change the URL, but keep the query string, use reqirep or reqrep to rewrite the URL, as you are doing, but also put a redirect prefix into the frontend. The URL will be rewritten and then the user will be redirected to it so they see it.
You might be able to set the "prefix" to "/". The HAProxy docs say:
As a special case, if < pfx > equals exactly "/", then nothing is
inserted before the original URI. It allows one to redirect to the
same URL (for instance, to insert a cookie).
Using your code example, something like this:
reqrep ^([^\ :]*)\ /test[/]?(.*) \1\ /app/testing/\2
redirect prefix / code 301 if is_test

Route by using existing cookie

How can I route requests in haproxy using a cookie that was set on the app servers?
Example: SESS=<hash-of-username>
haproxy should not insert cookies by itself in any case.
For testing a specific server behind haproxy I can recommend this approach:
frontend http
acl is_cookie_hack_1 hdr_sub(cookie) server_test_hack=server1
acl is_cookie_hack_2 hdr_sub(cookie) server_test_hack=server2
... insert your normal acl rules here
use_backend bk_server_1 if is_cookie_hack_1
use_backend bk_server_2 if is_cookie_hack_2
... insert your normal use_backend expressions here
backend bk_server_1
...
backend bk_server_2
...
I insert the server_test_hack cookie by javascript in my browser's js console by this script:
document.cookie="server_test_hack=server1";
You can't use your existing cookie for balancing, the way you could use the URI parameter. You can't just take the md5() or build the hash table of the cookie, at least that is not documented. You could use prefix parameter for the cookie to achieve a different result. It might be what you are looking for (if you want to avoid creation of yet another cookie).
So in your case the config would look like this:
backend bk_web
balance roundrobin
cookie SESS prefix indirect nocache
server s1 192.168.10.11:80 check cookie s1
server s2 192.168.10.21:80 check cookie s2
When the request arrives without a cookie, any server is chosen by round-robin and request is redirected to it. When response arrives from the backend, HAProxy checks for the SESS cookie and if it's set, it prepends the server name (sX) to the cookie and sends it to the client. In the browser, the cookie looks like sX~, but when the next request is sent with that cookie, the backend server only sees in the cookie, as HAProxy strips the sX~ part
Source: load balancing, affinity, persistence, sticky sessions: what you need to know
If you just want to read cookies in the request and route accordingly, you can do something like this in your configuration:
frontend http
acl cookie_found hdr_sub(cookie) COOKIENAME
use_backend app_server if cookie_found
backend app_server
balance roundrobin
server channel1 X.X.X.X:PORT #Host1
server channel2 Y.Y.Y.Y:PORT #Host2