I have specific requirement that depending on my context path I have to redirect my traffic to different server/port though HAProxy. I have already achieved the same with "path_beg" in ACL. Below is the configuration.
use_backend a1 if { path_beg /a1 }
use_backend a2 if { path_beg /a2 }
backend a1
balance roundrobin
server 1-www 172.17.0.1:80 check cookie s2
backend a2
balance roundrobin
server 1-www 172.17.0.3:80 check cookie s2
Now the concern is here every context path I also need to enter a frontend settings like use_backend a1 if { path_beg /a1 } which I would like to avoid. What I want when I need to add a new server I will add the backend as it's necessary but for the front end I am looking for something like this.
use_backend regex
Where regular expression will take the context path from the url and will proceed to the corresponding backend.
Note: backend name will be same as context path. Like if the url is http://example.com/dummy then backend name will be "dummy".
Any suggetion on the same.
Related
I am using HAProxy as a proxy server in front of Consul, a microservice registry. I use HAProxy to route traffic to a specific backend according to what type of node it is (what service it runs, is it active, what version it is, etc etc)
So far, I can use HAProxy to see what the path begins with, and route it to one backend eg.if the path begins with /blog, it'll go to the blog backend.
My question is, when there are multiple criterion to select a backend, how should I create said backends? Can I nest them in a way? Should I just exhaustive list all combinations of criteria and add a backend for that?
A backend is one or more servers (services, endpoints) that can all handle the same set of requests. You don't define backends based on what goes to them, but rather on what can go to them.
Example, if you have a set of servers that can serve several kinds of static assets, you wouldn't make a backend for javascript, another for CSS, another for images. You'd make one.
backend static-assets
mode http
server static-1 203.0.113.100:80
server static-2 203.0.113.200:80
Then route the appropriate requests to that backend.
You can do this in several ways.
Anonymous ACLs, one per pattern:
frontend main
mode http
bind :80
use_backend static-assets if { path_end .js }
use_backend static-assets if { path_end .css }
use_backend static-assets if { path_end .png }
Anonymous ACLs with explicit || (logical OR):
frontend main
mode http
bind :80
use_backend static-assets if { path_end .js } || { path_end .css } || { path_end .png }
Or use named ACLs. Each line in a named ACL is OR -- only one line needs to match for the ACL to match.
frontend main
mode http
bind :80
acl is_static path_end .js
acl is_static path_end .css
acl is_static path_end .png
use_backend static-assets if is_static
Or use any combination of these.
The first use_backend directive to match is the backend the request will go to -- they're processed in defined order. No "nesting" should be necessary.
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
Does HAProxy support domain name to backend mapping for path based routing.
Currently it does support maps for vhost:
frontend xyz
<other_lines>
use_backend backend1 if { hdr(Host) -i myapp.domain1.com }
use_backend backend2 if { hdr(Host) -i myapp.domain2.com }
Can be rewritten using maps as:
frontend xyz
<other_lines>
use_backend %[req.hdr(host),lower,map_dom(/path/to/map,default)]
With the contents of map file as:
#domainname backendname
myapp.domain1.com backend1
myapp.domain2.com backend2
But if the routing is based on paths as shown in the example below:
frontend xyz
acl host_server_myapp hdr(host) -i myapp.domain.com
acl path_path1 path_beg /path1
acl path_path2 path_beg /path2
use_backend backend1 if host_server_myapp path_path1
use_backend backend2 if host_server_myapp path_path2
Is it possible to have mapping for this usecase? Using base instead of hdr(host) might give the entire path but it will not have the flexibility of domains since base is string comparison. Is there an other way to convert this to haproxy maps.
Start with the Layer 7 base fetch --
This returns the concatenation of the first Host header and the path part of
the request, which starts at the first slash and ends before the question
mark.
...then use map_beg() to match the beginning of the string to the map.
use_backend %[base,map_beg(/etc/haproxy/testmap.map,default)]
If the map file /etc/haproxy/testmap.map has a line matching the prefix, the backend in the map file is used. Otherwise, the backend called default will be used (that's the 2nd argument to map_beg() -- the value to be returned if the map doesn't match).
If the resulting backend doesn't actually exist, HAProxy continues processing the request as if this statement weren't configured at all.
So your map file would look something like this:
example.com/foo this-backend # note, also matches /foo/ba
example.com/foo/bar that-backend # note, matches /foo/bar
example.org/foo some-other-backend
To treat a subdomain as equivalent to the parent domain (e.g., treating example.com and www.example.com to be handled equivalently, without map duplication, as discussed in comments) the regsub() converter could be used to modify the value passed to the map:
use_backend %[base,regsub(^www\.,,i),map_beg(/etc/haproxy/testmap.map,default)]
I have a website served by several machines behind a haproxy loadbalancer. Now it use sticky sessions based on cookies. I'm using a uptimerobot to check the machines health but I cannot configure it to use cookies and I don't want the loadbalancer to be the only open point to the internet.
Is there a way to configure the load balancer to access the machines by a url parameter?
There is a way but it isn't advisable. In the config, create duplicate backend blocks and url_param-based ACLs to route requests to specific servers based on a URL parameter.
Example:
frontend fe
bind x.x.x.x:80
bind x.x.x.x:443 ssl crt.. blah
...
default_backend www
acl is_healthchk_s1 url_param(CHECK) -i s1
acl is_healthchk_s2 url_param(CHECK) -i s2
acl is_healthchk_sn url_param(CHECK) -i sn
use_backend be_healthchk_s1 if is_healthchk_s1
use_backend be_healthchk_s2 if is_healthchk_s2
use_backend be_healthchk_sn if is_healthchk_sn
backend www
server s1 x.x.x.x:8080 check
server s2 x.x.x.x:8080 check
server sn x.x.x.x:8080 check
backend be_healthchk_s1
server s1 x.x.x.x:8080 check
backend be_healthchk_s2
server s2 x.x.x.x:8080 check
backend be_healthchk_s3
server s3 x.x.x.x:8080 check
So, your uptime robot can check these instead:
domain.com/?CHECK=s1
domain.com/?CHECK=s2
domain.com/?CHECK=sn
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