15
votes

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.

1
There's a map_beg() converter in the docs. It's not really explained, but it seems like you could use that along with the layer 7 path fetch, for something along the lines of use_backend %[path,map_beg(... - Michael - sqlbot
But that will not include the domain name, path will just give the path part of the request. - ajays20078
Ah, I saw that you were matching on paths, overlooked that you were testing two ACLs, one for path, one for host. There may still be a solution, I'll look at it in more detail to see if this can readily be done. - Michael - sqlbot

1 Answers

13
votes

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)]