Mapping Domain Names to Backend Server

Your HAProxy load balancer may only ever need to relay traffic for a single domain name, but HAProxy can handle two, ten, or even ten million routing rules without breaking a sweat. This article shows several ways of handling multi-domain configurations, including an introduction to using HAProxy maps.There’s a range of techniques explained here, whether you are deploying a simple, fairly-static multi-domain web server, or leveraging HAProxy’s more advanced features to tame the configuration and management of a dynamic API Gateway, or anything in between.

Access Control List Mapping

If your HAProxy is already serving multiple domains, you’re probably familiar with using Access Control Lists (ACLs) in your frontend declaration. This works well, but once you find yourself writing ACLs for many domains, it can become difficult to maintain.

Here’s how you might write ACLs for two domains, example.com and example.net:

Let’s take the second ACL as an example. It breaks down as follows:

acl ACL definition begins with acl.
ACL_example.net The name of the ACL. The name is arbitrary, but it’s good form to make them understandable.
hdr(host) -i example.net www.example.net This says that this rule will match any request that has an HTTP Host header of

example.net or www.example.net.

Once the ACL is set, define what to do with it:

This tells HAProxy to send any matching requests to a backend named be_example_net.
This is a good approach for a small number of domains, if they are fairly static, but what happens when you need it to handle tens of thousands of domains mapped to multiple backends,and you need to change them dynamically?

Direct Mapping

One strategy is to simply create a backend with the same name as your incoming domain names and use this use_backend directive in your frontend:

Above, %[req.hdr(host)] is replaced with the incoming host header, and forced to lowercase with lower. Therefore, if a request comes in for api.example.com, it will be sent to this backend:

Please note that the incoming host header variable includes any port explicitly specified, so incoming requests for example.com:6666 would be sent to a backend named backend example.com:6666, which may or may not exist. To strip the port, use:
use_backend %[req.hdr(host),lower,word(1,:)]

HAProxy Maps

If you need something more flexible and dynamic than ACLs or Direct Mapping, take a look at HAProxy maps. A map is an in-memory key/value data structure of a type known as an Elastic Binary Tree that is loaded at startup from a text file that you specify in your HAProxy configuration file. These maps are highly-optimized search tree structures that allow for incredibly fast lookups of the data stored within. The format of the text file used to create the map is quite simple: two columns, separated with one or more spaces or tabs. Comment lines begin with a hash (#) and must be on their own line.

To have HAProxy load this file, save it as /etc/haproxy/maps/hosts.map and then add the following line to your frontend config:

When using an ACL for this task, there was a line that looked like this:

But when using a map, the use_backend line gets a little more complicated, so let’s break it down. The directive use_backend is the same, but the second part within the square brackets is as follows:

req.hdr(host) is the Host header that contains the domain part of the URL. This is the key that we look up in the map.
Using lower forces the Host header value to lowercase, turning « EXAMPLE.COM » into « example.com » to simplify matches.
map_dom(/path/to/map,be_default)

The map_dom function takes two arguments, the first being the location of the map and the second being the default backend to use if an incoming Host header isn’t in the map file.

In addition to mapping domain names to backends, you can also use a similar technique to map URL paths to backends. This simplifies some of the complexities of designing and maintaining the type of routing explained in Using HAProxy as an API Gateway, Part 1 [Introduction].
To map paths to backends using a map, create a use_backend line that uses the path fetch method to get the URL path and the map_beg converter to find that path in the map file.

Your route map, located at /etc/haproxy/maps/routes.map in the line above, might look like this:

Routes that aren’t listed in the map are sent to the default backend, as well as requests for routes in the map that point to nonexistent or unavailable backends.

Modifying Maps

You have several options for modifying your maps, depending upon your use case.

Manual Update

The simplest method is to edit the map file in a text editor and do a hitless reload of HAProxy. This is a direct way of making a change, but it’s a manual process. Using hitless reloads means that you won’t lose any connections while it is reloading.

HAProxy Runtime API

You can directly interact with a running instance of HAProxy by using HAProxy’s Runtime API. To do this, first ensure that a socket has been defined in the global section of your configuration file:

Test your socket using socat by piping echo « help » at it:

This will produce the following output, which shows you several map functions:

For example, to add a mapping for a domain and backend pairing, use:

Deleting a map entry with the Runtime API is just as straightforward:

Note: Changes to the running instance made using this API are not written to disk and will be lost if you do a restart or reload of HAProxy.

HAProxy Data Plane API

Maps can also be managed using a RESTful interface, using the HAProxy Data Plane API. Unlike the Runtime API, with the Data Plane API, changes are written to disk.
Automatic Dynamic Updates via URL
HAProxy Enterprise can set maps dynamically via URL, checking for changes at an interval you specify:

This is ideal if you run a cluster of HAProxy Enterprise instances, since their map files can all be kept in sync with the file you host at the configured URL.

Conclusion

HAProxy is the ideal tool for load balancing multiple domains, whether the number of domains is ten or ten thousand. ACLs are a convenient method for managing a few domains that don’t require dynamic configuration. Maps, on the other hand, will let you handle many domains efficiently without your configuration file becoming a nightmare and they allow you to update your domain mappings dynamically.

Want to stay up to date on similar topics? Subscribe to this blog! You can also follow us on Twitter and join the conversation on Slack.

Interested in advanced security and administrative features? HAProxy Enterprise is the world’s fastest and most widely used software load balancer. It powers modern application delivery at any scale and in any environment, providing the utmost performance, observability, and security. Organizations harness its cutting edge features and enterprise suite of add-ons, backed by authoritative expert support and professional services. Ready to learn more? Sign up for a free trial.

SHARE THIS ARTICLE