Haproxy redirect www to non-www - haproxy

I'm currently using Haproxy to balance several express.js nodes. I know that it's possible to redirect using express.js, but I was hoping to do so with Haproxy.
I was wondering how I can do a permanent redirect from www.mysite.com to mysite.com?

redirect prefix http://example.com code 301 if { hdr(host) -i www.example.com }
Please see the documentation of the redirect prefix rule for more information.
If you are using a newer version of HAProxy, i.e. at least 1.6, you can use a more generic syntax which allows to redirect any host, not just explicitly named
http-request redirect prefix http://%[hdr(host),regsub(^www\.,,i)] code 301 if { hdr_beg(host) -i www. }
Here, we are using the regsub filter to dynamically generate the correct hostname without the www. prefix.
In case you want to perform a redirect the other way around, i.e. to add a www if there is none already, the rule becomes simpler:
http-request redirect prefix http://www.%[hdr(host)] code 301 unless { hdr_beg(host) -i www. }

Related

haproxy - redirect specific domain/path to other domain

i need redirect request from specific domain/path to other domain with same path, eg.
domain.com/foo/everything --> example.com/foo/everything
I think need use url_reg but I can't understand how to handle the redirect, maybe it could be such a thing?
acl redirect-foo url_reg -i ^domain.com\/foo\/*
http-request redirect code 301 location http://example.com/foo/ if redirect-foo
but obviously it doesn't work, thank anyone who can help me
You can use the following snipplet
acl host_match hdr(host) -i domain.com
acl path_match path_beg -i /foo/
http-request redirect code 301 location http://example.com/%[capture.req.uri] if host_match path_match
The acl's are described in the Documentation and in following Blog post.
Using ACLs to form conditions
Introduction to HAProxy ACLs
Documentation for capture.req.uri

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

redirect all root domain request to www. subdomain, keeping the URL intact

I want to redirect all traffic to root domain to the www. version while still keeping path/query string intact, how can I do that? I have setup a HAproxy config like follows:
frontend http
bind *:80
bind *:443
acl has_www hdr_beg(host) -i www
http-request redirect code 301 location http://www.%[hdr(host)]%[req.uri] unless has_www
However this one does the following: example.com/abc?page=1 => www.example.com, where I actually wan't it to do: example.com/abc?page=1 => www.example.com/abc?page=1 - what am I missing?
if you are using HAProxy 1.5 and up this should work for you
Single domain :
acl has_www hdr_beg(host) -i www
redirect prefix http://www.example.com code 301 unless has_www
Multiple domains: (dirty but works)
# match non www requests:
acl has_www hdr_beg(host) -i www.
# add a header that says we need to redirect these type of requests (will explain later)
http-request add-header X-Host-Redirect yes unless has_www
# rule to identify newly added headers
acl www_redirect hdr_cnt(X-Host-Redirect) eq 1
# where the magic happens (insert www. in front of all marked requests)
reqirep ^Host:\ (.*)$ Host:\ www.\1 if www_redirect
# now hostname contains 'www.' so we can redirect to the same url
redirect scheme http if www_redirect
The reason why we add a new header is because it seems that in HAProxy 1.5 and up, acls are being evalutated on each reference. so when you try to do this without the new header it does this :
#catch all domains that begin with 'www.'
acl has_www hdr_beg(host) -i www.
#insert www. in front of all non www requests
reqirep ^Host:\ (.*)$ Host:\ www.\1 unless has_www
#now hostname contains 'www.' so when the next rule gets interpreted it does not match then fails
#redirect to new url
redirect code 301 prefix / if has_www
hope this helps. I've tested this with 5 different domains on HAProxy 1.5 and it worked fine and kept the query strings intact on redirect
A multi-domain solution for HAProxy 1.6 which redirects preserving the path and query parameters:
frontend 443
http-request redirect prefix https://www.%[hdr(host)] code 301 unless { hdr_beg(host) -i www. }

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

HAProxy Redirects Of Domain & Domain w/Subdomains

I’m trying to redirect a domain and 1 other subdomain of that domain, but it’s not working (2 other redirects work to https, but they’re both different domains from each other and from this domain in question) and I haven’t been able to find an example that matches my configuration.
Here’s a snippet of the code in the order the entries appear, but let me know if you think you need to see more of the code (a lot of front ends and backends exist).
acl is_test1.domain.com hdr_dom(host) -i test1.domain.com
acl is_domain.com hdr_dom(host) -i domain.com
redirect location https://test1.domainTwo.com/ if is_domain.com
redirect location https://test1.domainTwo.com/path/ if is_test1.domain.com
Also, how should www.domain.com be handled with this configuration? Do I need another acl for it?
Thanks!
Not sure if it's the most efficient setup, but the suggestion below is similar to what I have and it works.
acl is_test1.domain.com hdr(host) -i test1.domain.com
acl is_domain.com hdr(host) -i domain.com www.domain.com
The redirects should work from there as the acl's will match appropriately now. From my understanding of HAProxy, hdr_dom(host) will match any dot-delimited part of the domain (taking the more exact match) and hdr(host) will match if the domains are identical.