Learn how to set up basic load balancing using the HAProxy configuration file.

 

If you’re new to using the HAProxy load balancer, you’ve come to the right place. In this blog post, you’ll learn how to configure HAProxy for basic load balancing. I am assuming that you’ve already installed the software. If not, there are several ways to do so:

Now that you have HAProxy installed, let’s see how to configure it. All settings are defined in the file /etc/haproxy/haproxy.cfg (or /etc/hapee-{version}/hapee-lb.cfg for HAProxy Enterprise). If you are using Docker, then this file is mounted as a volume into the container at the path /usr/local/etc/haproxy/haproxy.cfg.

Before learning how to use this file, let’s consider what we are trying to achieve. To answer that, we have to first ask, what is a load balancer?

What is a load balancer?

HAProxy is a load balancer. Not familiar with the term? A load balancer helps you handle more web traffic and avoid downtime. A load balancer receives traffic from the Internet (or from your internal network, if we’re talking about load balancing an internal service) and then forwards that traffic to your web server.

The benefits of using a load balancer are realized once you’ve deployed multiple web servers. The load balancer can then relay traffic to each of them, allowing you to grow your capacity to serve more clients without asking those clients to connect to each server directly. HAProxy receives the traffic and then balances the load across your servers. This technique hedges against any one of your servers failing, since the load balancer can detect if a server becomes unresponsive and automatically stop sending traffic to it. You can use HAProxy to balance the traffic to any number of web applications using a single configuration file.

Caveat! To guarantee truly reliable service, you must run at least two instances of HAProxy in an active-active or active-standby setup. Learn how to do that with HAProxy Enterprise by reading the official docs. For now, we’ll stick to using a single instance of HAProxy.

When configuring HAProxy, you typically start with the following three goals:

  • Decide which IP addresses and ports HAProxy should bind to for receiving traffic;
  • Define pools of servers to which HAProxy will relay traffic;
  • Set rules for edge cases, such as when you want a client’s request to go somewhere other than the normal pool of servers.

Set the listening IP address and port

There are lots of things you can do with HAProxy: enable TLS, set rate limits, cache responses, reject malicious requests, modify HTTP headers, handle CORS, authenticate users, and many other tasks, but let’s start simple.

To define the IP address and port at which HAProxy should receive traffic, add a frontend section to your haproxy.cfg file. Inside this section, add a bind line. A bind line sets the IP address and port to listen on.

Your configuration file now contains the following and nothing else:

This example also includes a defaults section, which defines settings that are shared across all sections that follow. It sets timeouts for how long HAProxy should wait for a client to send data (timeout client), how long to wait when trying to connect to a backend server (timeout connect), how long to wait for the server to send back data (timeout server), and how long to wait for the client to send a complete HTTP request (timeout http-request). These are just good safety measures that will help avoid common problems.

The mode sets how HAProxy treats requests. It can be either http or tcp, with the former used when working with HTTP web applications. In this mode, HAProxy is able to inspect metadata of an HTTP request, such as headers, cookies, and the URL path, when deciding how to route the request.

Restart HAProxy:

The load balancer is now listening on the localhost address, 127.0.0.1, at port 80. If you make a request using curl, you’ll get back a response:

Granted, there’s no reply from a server because we haven’t configured any servers yet. Nevertheless, you can see that HAProxy is functional. The table below lists a few other ways that you could set the bind line:

Bind line What it does
bind 0.0.0.0:80 Listen on all IP addresses assigned to this server at port 80.
bind :80 The same as specifying 0.0.0.0 for the address.
bind :80,:8080 Listen on ports 80 and 8080. (Do not add a space between ports)
bind :6379-6390 Listen on all the ports between 6379 and 6390.

Next, let’s add a pool of servers to route requests to.

Define a backend

In HAProxy, a frontend receives traffic before dispatching it to a backend, which is a pool of web or application servers. One of the servers in the backend will receive the request, form a response, and then send the response back through HAProxy to the client.

First, let’s run a small web application. Open a new terminal window on your HAProxy server and run this command, which starts a Python-based web application that listens at port 8000:

In your HAProxy configuration, below the frontend section, add a backend section that contains a single server. Also, add a default_backend line to your frontend that points to this new backend. Your file now looks like this:

Make the same curl request as before and you’ll get a response from the Python application (truncated for space).

The request went through HAProxy. To get a real feel for it, run more Python web applications on different ports and then add them to the backend:

With each new request that you make to port 80, HAProxy receives it and selects a server to handle it. HAProxy rotates through the list of servers, relaying the next request to the next server in line. You are now balancing the load across these servers.

Set rules for edge cases

Suppose you wanted to send all requests that arrive on port 80 to servers 1 and 2, but if a request arrives at port 81, it should go to server 3. Consider the following configuration that achieves that:

Here, I’ve moved server3 into its own backend section named special. In the frontend, I’ve added a use_backend line that checks whether the destination port requested by the client is 81. If it is, then the request goes to the special backend. Because I want the frontend to listen on both ports 80 and 81 simultaneously, I’ve separated those addresses with a comma. I could also have written a second bind line, like this:

Either syntax is acceptable and they have the same result.

The condition that checks the destination port is surrounded by curly braces. Such conditions in HAProxy are called ACLs. The table below lists examples of other ACLs that you might use to route traffic to different backends. Before you can use some of them, you will need to set mode http in your frontend and backend sections, which allows HAProxy to evaluate HTTP data in a message.

ACL Description
if { path_beg /api/ } Route API requests.
if { path_end .jpg .png } Route requests for images.
if { hdr(host) -m dom example.local } Routes requests for the domain example.local.
if { src 127.0.0.1/8 } Route requests originating from the given IP address range.
if { method POST PUT } Route POST and PUT requests.
if { url_param(region) europe } Route requests that have a URL parameter named region that is set to europe.

Learn more about ACLs in our blog post, Introduction to HAProxy ACLs.

Conclusion

That should be enough to get started using HAProxy as a load balancer. Once you’ve got the hang of it, read up on some other common tasks, such as:

HAProxy Enterprise powers modern application delivery at any scale and in any environment, providing the utmost performance, observability, and security for your critical services. Organizations harness its cutting edge features and enterprise suite of add-ons, which are backed by authoritative, expert support and professional services. Ready to learn more? Sign up for a free trial.

Want to know when more content like this is published? Subscribe to our blog or follow us on Twitter. You can also join the conversation on Slack.

SHARE THIS ARTICLE