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.
Related
Example cookie name in request:
wordpress_logged_in_8df6736080e8...
I want to create an haproxy acl based on when the cookie name begins with wordpress_logged_in and then route the logged in users based on that acl to separate backend.
acl url_admin path_beg -i /wp-admin /wp-login.php
acl url_admin hdr_sub(cookie) wordpress_logged_in
This config is working for me, as it matches the whole cookie header and some URLs. Without the first ACL it's not working.
You can try to use cook_beg for the acl
acl cookie_backend cook_beg(wordpress_logged_in) -m found
...
use_backend cookie_backend if cookie_backend
...
default_backend default_backend
This Blog post explains the haproy acl Introduction to HAProxy ACLs
In the doc can you find more details Using ACLs to form conditions
I am working on a project where I need requests destined to a particular page to be routed to a separate backend.
For example, all requests for https://mycooldomain.com will go to backend "A". But, if navigating to https://mycooldomain.com/secretpage I want it to go to backend "B".
Now, I have this working but running into an issue where I need the trailing slash for this to work correctly.
So, I need a way to say if request is https://[whateverhostnameisused]/secretpage redirect to https://[whateverhostnameisused]/secretpage/.
Here is a sample of my config so far:
frontend f_https
bind *:443 ssl crt cert.pem
reqadd X-Forwarded-Proto:\ https
#define hosts
acl host_a hdr(host) -i a.mycooldomain.com
acl host_b hdr(host) -i b.mycooldomain.com
acl host_c hdr(host) -i c.mycooldomain.com
#custom acls
acl secret path_beg -i /secretpage
#Custom redirects
##define backend
use_backend b_secret if secret
use_backend b_a if host_a
use_backend b_b if host_b
use_backend b_c if host_c
default_backend b_https
backend b_secret
server secret 192.168.15.15:5575 check
It seems that you are looking for something like this:
http-request redirect scheme https drop-query append-slash if { path -m str /secretpage }
This should work if applied to either the frontend or the backend.
http://cbonte.github.io/haproxy-dconv/1.6/configuration.html#4.2-redirect%20scheme
Specifying the scheme is only necessary because the syntax requires one of location | prefix | scheme, and with the other two options, you have to reassemble the URL yourself in the config.
Note also that reqadd is not officially deprecated, but the preferred way to add that request header is like this:
http-request set-header X-Forwarded-Proto https
Note that no : is specified and the space after the header name must not be escaped with \. This accomplishes the same result, but it uses a different code path inside HAProxy, and should be a more efficient operation. You will want to use the the http-request and http-response directives instead of reqxxx and rspxxx where possible, as they are also better suited to more complex manipulations.
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
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.
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)]