HAProxy Load Balancer Setup on Linux (Complete Step-by-Step Guide)

haproxy load balancer setup linux custom-haproxy-featured.png

Our earlier Nginx reverse proxy guide covers routing traffic to a single backend app. HAProxy is purpose-built for the next step: spreading traffic across multiple backend servers, health-checking each one, and automatically routing around a server that goes down.

This guide sets up a two-node backend pool behind a single HAProxy load balancer, verifies round-robin distribution, and tests real failover by taking a backend offline.

Step 1: Install HAProxy

On the load balancer host: sudo apt install haproxy (Ubuntu/Debian) or sudo dnf install haproxy (AlmaLinux). Confirm the version with haproxy -v — this guide assumes HAProxy 2.8+.

Install HAProxy load balancer package on Linux
Step 1: Install HAProxy

Step 2: Plan Your Backend Pool

Identify the servers HAProxy will distribute traffic to — in this example, web01 (192.168.1.101) and web02 (192.168.1.102), both running identical web apps on port 80. Confirm each is independently reachable (curl web01:80) before wiring up the load balancer.

Planning HAProxy backend pool of web servers
Step 2: Plan Your Backend Pool

Step 3: Configure the Frontend

Edit /etc/haproxy/haproxy.cfg and add a frontend web_front block that binds port 80 and points default_backend at the backend pool you’re about to define. The frontend is the entry point clients actually connect to.

HAProxy frontend configuration binding port 80
Step 3: Configure the Frontend

Step 4: Configure the Backend With Health Checks

Add a backend web_back block with balance roundrobin and a server line per host, each ending in check — this tells HAProxy to actively health-check that server (default: TCP connect check every 2s) and automatically pull it out of rotation if it stops responding.

HAProxy backend configuration with roundrobin and health checks
Step 4: Configure the Backend With Health Checks

Step 5: Validate and Reload the Configuration

Always check syntax before reloading a live load balancer: haproxy -c -f /etc/haproxy/haproxy.cfg. Once it reports Configuration file is valid, reload with systemctl reload haproxy — this applies the new config without dropping existing connections.

Validating and reloading HAProxy configuration safely
Step 5: Validate and Reload the Configuration

Step 6: Enable the Stats Page

Add a listen stats block bound to a separate port (e.g. *:8404) with stats enable and a basic-auth stats auth line. Browse to http://lb01:8404/stats to see live per-backend session counts, health status, and error rates — your first stop when diagnosing anything.

HAProxy stats page showing backend server status
Step 6: Enable the Stats Page

Step 7: Test Round-Robin Distribution

From a client machine, hit the load balancer repeatedly and confirm requests alternate between backends: for i in 1 2 3 4; do curl -s lb01/hostname; done should show web01, web02, web01, web02 — proof traffic is actually being spread, not pinned to one server.

Testing HAProxy round robin load distribution with curl
Step 7: Test Round-Robin Distribution

Step 8: Test Failover

Stop the app on one backend (systemctl stop nginx on web02) and watch the stats page mark it DOWN within one health-check interval. Repeat the round-robin test — every request should now land on web01 only, with zero client-visible errors. This is the actual payoff: a backend can die and users don’t notice.

HAProxy failover test after stopping one backend server
Step 8: Test Failover

Example haproxy.cfg

frontend web_front
    bind *:80
    default_backend web_back

backend web_back
    balance roundrobin
    option httpchk GET /healthz
    server web01 192.168.1.101:80 check
    server web02 192.168.1.102:80 check

listen stats
    bind *:8404
    stats enable
    stats uri /stats
    stats auth admin:changeme

Next steps for production

  • Switch option httpchk to a real health endpoint your app exposes, not just a TCP connect check — an app that’s hung but still accepting TCP connections will otherwise stay in rotation
  • Terminate SSL at HAProxy with a bind *:443 ssl crt /etc/haproxy/certs/site.pem line — pair with our Certbot guide for the certificate
  • HAProxy itself is a single point of failure unless you run two instances with keepalived and a floating VIP — worth doing once this box matters for production traffic

Related tutorials

Terminal screenshots are original illustrations created for Gnome IT Solutions (blog.gnomeitsolutions.com).