HAProxy is a free and open source software that provides a high availability load balancer and proxy server for TCP and HTTP-based applications that spreads requests across multiple servers. It distributes the load among the web and application servers.
HAProxy is popular for load balancing because of its efficiency, reliability, and low memory and CPU footprint. Load balancing is a common solution for distributing web applications horizontally across multiple hosts while providing the users with a single point of access to the service.
In this guide we will learn how to install HAProxy on Rocky Linux and AlmaLinux 9 and 10 (dnf) and on Debian 12 and Ubuntu 24.04 (apt), then configure it as a load balancer. Only the install and firewall steps differ between the two families; the configuration is the same everywhere. The commands and configs were tested on Rocky Linux 9 and 10, AlmaLinux 10, Debian 12 and Ubuntu 24.04.
Prerequisites
- A server running Rocky Linux or AlmaLinux 9 or 10, Debian 12 or Ubuntu 24.04, to act as the load balancer
- Two or more backend web servers reachable from it on their private IPs
- A user with
sudo
HAProxy load balancing algorithms
The balancing algorithms are used to decide which server at the backend each connection is transferred to. Some of the useful options include the following:
roundrobin: Each server is used in turns according to their weights. This is the smoothest and fairest algorithm when the servers’ processing time remains equally distributed. This algorithm is dynamic, which allows server weights to be adjusted on the fly.leastconn: The server with the lowest number of connections is chosen. Round-robin is performed between servers with the same load. Using this algorithm is recommended with long sessions, such as LDAP, SQL, TSE, etc, but it is not very well suited for short sessions such as HTTP.first: The first server with available connection slots receives the connection. The servers are chosen from the lowest numeric identifier to the highest, which defaults to the server’s position on the farm. Once a server reaches itsmaxconnvalue, the next server is used.source: The source IP address is hashed and divided by the total weight of the running servers to designate which server will receive the request. This way the same client IP address will always reach the same server while the servers stay the same.
Install HAProxy
Rocky Linux and AlmaLinux 9 and 10
HAProxy is in the default AppStream repo. Update the server, then install it:
sudo dnf -y update
sudo dnf install -y haproxy
Confirm the installation:
$ rpm -q --qf '%{VERSION}-%{RELEASE}\n' haproxy
2.8.14-3.el9_8.2
That is the Rocky Linux 9 package, HAProxy 2.8. Rocky Linux 10 and AlmaLinux 10 ship HAProxy 3.0 (haproxy-3.0.5). Both are HAProxy LTS branches.
Debian 12 and Ubuntu 24.04
HAProxy is in the default repos of both. Update the server, then install it:
sudo apt update
sudo apt upgrade -y
sudo apt install -y haproxy
Confirm the installation:
$ dpkg-query -W haproxy
haproxy 2.8.30-0ubuntu0.24.04.2
That is Ubuntu 24.04, HAProxy 2.8. Debian 12 ships HAProxy 2.6 (2.6.12-1+deb12u4).
The distro packages are LTS branches and get security fixes for the life of the release. If you need a newer branch on Debian or Ubuntu, the HAProxy team publishes packages at haproxy.debian.net.
Check the version and enable the service
On any of the distributions, check the installed version:
haproxy -v
Then start HAProxy and enable it on boot. Debian and Ubuntu start it on install; Rocky and Alma do not:
sudo systemctl enable --now haproxy
Configure HAProxy as a load balancer
To configure HAProxy as a load balancer, we need to tell it what kind of connections it should be listening for and where the connections should be relayed to. This is done in the configuration file /etc/haproxy/haproxy.cfg.
The file the package installs already has global and defaults sections, plus a sample frontend and backend on Rocky and Alma. Keep global and defaults, and replace any sample frontend, backend and listen sections with the ones below. Open the file with your text editor, I am using vim:
sudo vim /etc/haproxy/haproxy.cfg
Replace the <private IP> placeholders below with the private IPs of the servers you want to send web traffic to.
Load balancing on layer 4
A layer 4 load balancer forwards TCP connections without looking at the HTTP traffic inside them. Set mode tcp on both the frontend and the backend, since the packaged defaults section sets mode http:
frontend tcp_front
mode tcp
option tcplog
bind *:80
default_backend tcp_back
backend tcp_back
mode tcp
balance roundrobin
server web_server_1 <private IP>:80 check
server web_server_2 <private IP>:80 check
This defines a frontend named tcp_front listening on port 80, which passes every connection to the backend named tcp_back. The check keyword makes HAProxy health check each server and stop sending it traffic when it is down.
Load balancing on layer 7
We can also configure the load balancer to work on layer 7. This is useful when parts of your web application are located on different hosts. HAProxy reads each HTTP request and routes it, for example by URL path:
frontend http_front
bind *:80
acl url_blog path_beg /blog
use_backend blog_back if url_blog
default_backend http_back
backend http_back
balance roundrobin
server web_server_1 <private IP>:80 check
server web_server_2 <private IP>:80 check
backend blog_back
balance roundrobin
server blog_server_1 <private IP>:80 check
server blog_server_2 <private IP>:80 check
The front end declares an ACL rule named url_blog that applies to all connections with paths that begin with /blog. use_backend defines that connections matching the url_blog condition should be served by the backend named blog_back, while all other requests are handled by the default backend.
At the backend side, the configuration sets up two server groups, http_back and blog_back, which serves only requests to example.com/blog. Use either the layer 4 or the layer 7 frontend on port 80, not both.
Configuring SSL termination
To let HAProxy handle HTTPS and pass plain HTTP to the backends, it needs the certificate and private key in one PEM file. Combine them with this command:
sudo mkdir -p /etc/haproxy/certs
cat citizix.fullchain.pem citizix.key | sudo tee /etc/haproxy/certs/citizix.pem > /dev/null
sudo chmod 600 /etc/haproxy/certs/citizix.pem
Then add a bind on port 443 to the layer 7 frontend, and redirect plain HTTP to HTTPS:
frontend http_front
bind *:80
bind *:443 ssl crt /etc/haproxy/certs/citizix.pem alpn h2,http/1.1
http-request redirect scheme https unless { ssl_fc }
acl url_blog path_beg /blog
use_backend blog_back if url_blog
default_backend http_back
alpn h2,http/1.1 lets browsers use HTTP/2 to the load balancer. To refuse old TLS versions, add ssl-default-bind-options ssl-min-ver TLSv1.2 to the global section. With Let’s Encrypt, combine the files again after every renewal, for example from a certbot deploy hook, and reload HAProxy.
Password protecting the statistics page
HAProxy can serve a statistics page with the state of every backend server. Older versions of this guide enabled it with stats uri on the public frontend, which shows it to anyone. Instead, give it its own port and a login by adding this to the end of haproxy.cfg. Replace the username and password with something secure:
listen stats
bind *:8404
stats enable
stats uri /
stats realm HAProxy\ Statistics
stats auth admin:ChangeMe
stats refresh 10s
Check the configuration and restart HAProxy
Check the file for errors before restarting:
sudo haproxy -c -f /etc/haproxy/haproxy.cfg
A valid file exits with status 0 and no errors. HAProxy 2.x (Rocky 9, Debian, Ubuntu) also prints Configuration file is valid; HAProxy 3.0 on EL 10 prints nothing. Then restart HAProxy:
sudo systemctl restart haproxy
For later changes, sudo systemctl reload haproxy applies the new config without dropping open connections.
Open the firewall
Open 80 and 443 to everyone, but the stats port only to the address you manage the load balancer from (replace 203.0.113.10). Its login is HTTP basic auth over plain HTTP, so anyone on the path can read the password.
On Rocky Linux and AlmaLinux, open the ports in firewalld. SELinux only allows HAProxy to bind and connect to a few web ports, so also allow it to use the stats port and any non-standard backend ports:
sudo firewall-cmd --permanent --add-service={http,https}
sudo firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="203.0.113.10" port port="8404" protocol="tcp" accept'
sudo firewall-cmd --reload
sudo setsebool -P haproxy_connect_any 1
On Debian and Ubuntu, if UFW is enabled:
sudo ufw allow 80,443/tcp
sudo ufw allow from 203.0.113.10 to any port 8404 proto tcp
If you would rather not open 8404 at all, bind the stats listener to 127.0.0.1:8404 and reach it through an SSH tunnel: ssh -L 8404:127.0.0.1:8404 user@<load balancer>, then browse to http://localhost:8404.
Testing the setup
With HAProxy configured and running, open the statistics page and log in with the username and password you set:
http://<load balancer public IP>:8404
When you load the statistics page and all of your servers are listed in green your configuration was successful!
The statistics page contains some helpful information to keep track of your web hosts including up and down times and session counts. If a server is listed in red, check that the server is powered on and that you can reach it from the load balancer machine.
Then open just the load balancer IP without any port numbers in your web browser:
http://<load balancer public IP>/
If your backend servers have at least slightly different landing pages you will notice that each time you reload the page you get the reply from a different host. From the command line, curl does the same:
for i in 1 2 3 4; do curl -s http://<load balancer public IP>/ | head -n 1; done
In case your load balancer does not reply, check that the firewall is not blocking the ports, and confirm that HAProxy is running and see its latest log lines:
sudo systemctl status haproxy
sudo journalctl -u haproxy -n 50
Conclusions
That is it! In this guide, we learnt how to install HAProxy on Rocky Linux, AlmaLinux, Debian and Ubuntu and configure it to load balance traffic on layer 4 and layer 7, terminate SSL and serve a password protected statistics page. This will increase your web application performance and availability.