It is lightweight, highly configurable, and capable of handling tens of thousands of concurrent connections.
In this technical guide, we will walk through the complete installation and configuration of HAProxy as a reverse proxy and load balancer on Ubuntu 24.04 LTS. We will cover backend setup, core routing, SSL termination, and enabling the statistics dashboard.
Architecture Overview
Before installing anything, it is important to understand where HAProxy sits in the network. The client does not directly connect to the backend servers. Instead, HAProxy receives the request, selects a healthy backend, and forwards the traffic.
For this tutorial, we will set up a standard three-node architecture using RFC 5737 documentation IP addresses.
Note: Replace the example IP addresses (192.0.2.x) with your actual network IPs.
Prerequisites
- Three servers running Ubuntu 24.04 LTS.
- Root or sudo privileges on all nodes.
- Basic familiarity with the Linux command line and nano or vim.
Step 1: Prepare the Backend Web Servers
Before configuring the load balancer, we need backend servers to route traffic to. We will use Nginx for this example. Run these steps on both Backend 1 and Backend 2.
1. Install Nginx:
sudo apt update
sudo apt install nginx -y
2. Create a distinct index page for each server:
This allows us to visually verify that HAProxy is distributing traffic.
On Backend 1 (192.0.2.20):
echo "<h1>Welcome to Backend Server 1</h1>" | sudo tee /var/www/html/index.nginx-debian.html
On Backend 2 (192.0.2.21):
echo "<h1>Welcome to Backend Server 2</h1>" | sudo tee /var/www/html/index.nginx-debian.html
3. Secure the Backend Firewalls:
Your backend servers should only accept web traffic directly from the HAProxy load balancer. Block direct outside access to port 80.
# Allow SSH so you don't lock yourself out
sudo ufw allow OpenSSH
# Restrict HTTP traffic to ONLY the HAProxy IP
sudo ufw allow from 192.0.2.10 to any port 80
sudo ufw deny 80/tcp
sudo ufw enable
4. Ensure Nginx is running:
sudo systemctl enable --now nginx
Step 2: Install HAProxy on the Load Balancer
Switch to your Load Balancer node (192.0.2.10). Ubuntu 24.04 repositories include a stable version of HAProxy (2.8+), which is perfectly suitable for production environments and uses the modern configuration syntax.
1. Install HAProxy:
sudo apt update
sudo apt install haproxy -y
2. Verify the installation:
haproxy -v
Step 3: Configure HAProxy
The main configuration file is located at /etc/haproxy/haproxy.cfg. Before making changes, back up the default configuration.
sudo cp /etc/haproxy/haproxy.cfg /etc/haproxy/haproxy.cfg.bak
Open the configuration file in your text editor:
sudo nano /etc/haproxy/haproxy.cfg
Clear the existing content and paste the following Production-Ready Configuration block. This consolidated configuration includes modern health check syntax, security timeouts to prevent Slowloris attacks, and passes the true client IP to your backends.
global
log /dev/log local0
log /dev/log local1 notice
maxconn 50000 # Tune based on server RAM (~17KB per connection)
chroot /var/lib/haproxy
user haproxy
group haproxy
daemon
# Modern SSL tuning for 2026 standards
ssl-default-bind-ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256
ssl-default-bind-ciphersuites TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384
ssl-default-bind-options ssl-min-ver TLSv1.2 no-tls-tickets
defaults
log global
mode http
option httplog
option dontlognull
option forwardfor # Crucial: Passes real client IP to backends
option http-server-close
timeout http-request 10s # Protects against Slowloris attacks
timeout connect 5s
timeout client 30s
timeout server 30s
errorfile 400 /etc/haproxy/errors/400.http
errorfile 500 /etc/haproxy/errors/500.http
errorfile 502 /etc/haproxy/errors/502.http
errorfile 503 /etc/haproxy/errors/503.http
errorfile 504 /etc/haproxy/errors/504.http
frontend http_front
bind *:80
# Optional: Redirect HTTP to HTTPS if you configure SSL later
# http-request redirect scheme https unless { ssl_fc }
default_backend web_servers
backend web_servers
balance roundrobin
# Modern HAProxy 2.8+ health check syntax
option httpchk
http-check send meth GET uri / ver HTTP/1.1
http-check expect status 200
# 'check' enables health monitoring. 'inter', 'fall', and 'rise' tune sensitivity.
server web1 192.0.2.20:80 check inter 5s fall 3 rise 2
server web2 192.0.2.21:80 check inter 5s fall 3 rise 2
# Secure Statistics Dashboard
listen stats
bind *:8404
mode http
stats enable
stats uri /stats
stats refresh 10s
stats auth admin:YourSecurePasswordHere
# Optional: Restrict stats to a specific admin IP
# http-request deny unless { src 198.51.100.50 }
/health endpoint that returns an HTTP 200 only when the database and app are fully functional, and point your http-check there.
Step 4: Validate and Restart HAProxy
Never restart a service without validating the configuration first. A syntax error will prevent HAProxy from starting, causing load balancer downtime.
1. Check configuration syntax:
sudo haproxy -c -f /etc/haproxy/haproxy.cfg
Expected output: Configuration file is valid
2. Restart and enable HAProxy:
sudo systemctl restart haproxy
sudo systemctl enable haproxy
Step 5: Configure the Load Balancer Firewall
Ensure your firewall allows traffic to the HAProxy frontend (Port 80) and the stats page (Port 8404). Run this on the HAProxy server:
sudo ufw allow 80/tcp
sudo ufw allow 8404/tcp
sudo ufw reload
Step 6: Test the Load Balancer
Now, we verify that HAProxy is correctly distributing traffic.
1. Test via Command Line:
From your local machine (or a separate test server), use curl to hit the Load Balancer's IP multiple times.
for i in {1..6}; do curl -s http://192.0.2.10; done
Expected Output:
<h1>Welcome to Backend Server 1</h1>
<h1>Welcome to Backend Server 2</h1>
<h1>Welcome to Backend Server 1</h1>
<h1>Welcome to Backend Server 2</h1>
<h1>Welcome to Backend Server 1</h1>
<h1>Welcome to Backend Server 2</h1>
The output should alternate perfectly between Server 1 and Server 2, confirming that the roundrobin algorithm is functioning.
2. Test the Stats Dashboard:
Open your web browser and navigate to: http://192.0.2.10:8404/stats
Log in using the credentials you set (admin / YourSecurePasswordHere). You will see a real-time dashboard showing queue sizes, response times, and the up/down status of your backend servers.
Step 7: Implementing SSL/TLS Termination (Optional but Recommended)
In a production environment, you should terminate SSL at the load balancer to offload cryptographic processing from your application servers.
1. Generate a combined PEM file:
HAProxy requires the certificate and private key to be combined into a single .pem file. If you are using Let's Encrypt, concatenate them:
sudo mkdir -p /etc/haproxy/certs
sudo cat /etc/letsencrypt/live/yourdomain.com/fullchain.pem /etc/letsencrypt/live/yourdomain.com/privkey.pem | sudo tee /etc/haproxy/certs/yourdomain.com.pem
(Ensure permissions are restricted: sudo chmod 600 /etc/haproxy/certs/yourdomain.com.pem)
2. Update the Frontend Configuration:
Modify your frontend http_front in /etc/haproxy/haproxy.cfg to bind to port 443 with SSL:
frontend http_front
bind *:80
bind *:443 ssl crt /etc/haproxy/certs/yourdomain.com.pem
# Force HTTPS
http-request redirect scheme https unless { ssl_fc }
default_backend web_servers
3. Open port 443 and reload configuration:
sudo ufw allow 443/tcp
sudo systemctl reload haproxy
Step 8: Production Consideration - Avoiding a Single Point of Failure
A common mistake in new deployments is building the architecture we just created and stopping there. While this protects against an application node failure, HAProxy itself has now become a Single Point of Failure (SPOF).
If your primary HAProxy instance crashes, both backend servers can remain perfectly healthy, but users still won't be able to reach your site. For high-availability enterprise environments, you need two independent HAProxy nodes sharing a Virtual IP (VIP) using a tool like Keepalived:
Implementing this ensures that if HAProxy Node 1 goes offline, Node 2 instantly takes over the IP address, resulting in zero downtime.
Troubleshooting Common Issues
- 503 Service Unavailable: HAProxy cannot reach the backend servers. Verify that the backend IPs are correct, Nginx is running on the backends, and the backend firewalls correctly allow traffic from the HAProxy IP.
- Configuration fails to load: Always run sudo haproxy -c -f /etc/haproxy/haproxy.cfg after making changes. Check
/var/log/syslogfor specific syntax errors. - Backend stuck in "DOWN" state: Your health check URI might be returning a non-200 status code. Ensure
http-check sendis pointing to a valid endpoint that returns a 200 OK.
Need High-Performance Infrastructure?
Scaling a load balancer requires reliable, high-throughput networking. Whether you need a lightweight reverse proxy or a fully redundant multi-node cluster, our bare-metal servers provide the unmetered bandwidth and low latency required for mission-critical routing.
Explore Dedicated Servers