Configure HAProxy load balancing with multiple backend servers

Intermediate 45 min May 07, 2026 69 views
Ubuntu 24.04 Debian 12 AlmaLinux 9 Rocky Linux 9

Set up HAProxy to distribute traffic across multiple backend servers with health checks, SSL termination, and automatic failover for high availability load balancing.

Prerequisites

  • Root or sudo access
  • Multiple backend web servers
  • Network connectivity between HAProxy and backends

What this solves

HAProxy distributes incoming traffic across multiple backend servers, preventing any single server from becoming a bottleneck. This setup provides automatic failover when backend servers go down, health monitoring to ensure traffic only goes to healthy servers, and the ability to scale your application by adding more backend servers without changing client configurations.

Step-by-step configuration

Update system packages

Start by updating your package manager to ensure you have access to the latest HAProxy version.

sudo apt update && sudo apt upgrade -y
sudo dnf update -y

Install HAProxy

Install HAProxy from the official repositories. This provides the latest stable version with security updates.

sudo apt install -y haproxy
sudo dnf install -y haproxy

Backup the default configuration

Create a backup of the original configuration file before making changes.

sudo cp /etc/haproxy/haproxy.cfg /etc/haproxy/haproxy.cfg.backup

Configure HAProxy for load balancing

Create a new configuration that defines frontend listeners, backend server pools, and health checks. This example balances HTTP traffic across three web servers.

global
    daemon
    chroot /var/lib/haproxy
    stats socket /run/haproxy/admin.sock mode 660 level admin
    stats timeout 30s
    user haproxy
    group haproxy
    log stdout local0

    # Default SSL material locations
    ca-base /etc/ssl/certs
    crt-base /etc/ssl/private

    # Intermediate configuration
    ssl-default-bind-ciphers ECDHE+aRSA+AES256:ECDHE+aRSA+AES128:!aNULL:!MD5:!DSS
    ssl-default-bind-options ssl-min-ver TLSv1.2 no-tls-tickets

defaults
    mode http
    timeout connect 5000
    timeout client 50000
    timeout server 50000
    errorfile 400 /etc/haproxy/errors/400.http
    errorfile 403 /etc/haproxy/errors/403.http
    errorfile 408 /etc/haproxy/errors/408.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 - receives requests from clients

frontend web_frontend bind *:80 bind *:443 ssl crt /etc/ssl/certs/example.com.pem redirect scheme https code 301 if !{ ssl_fc } # Security headers http-response set-header X-Frame-Options DENY http-response set-header X-Content-Type-Options nosniff http-response set-header Strict-Transport-Security max-age=31536000 default_backend web_servers

Backend - pool of web servers

backend web_servers balance roundrobin option httpchk GET /health http-check expect status 200 # Backend servers with health checks server web1 192.168.1.10:80 check inter 30s fall 3 rise 2 server web2 192.168.1.11:80 check inter 30s fall 3 rise 2 server web3 192.168.1.12:80 check inter 30s fall 3 rise 2

Statistics page

listen stats bind *:8404 stats enable stats uri /stats stats refresh 30s stats admin if TRUE stats auth admin:secure_password_here

Configure firewall rules

Open the necessary ports for HAProxy to accept client connections and access the statistics page.

sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw allow 8404/tcp
sudo ufw --force enable
sudo firewall-cmd --permanent --add-port=80/tcp
sudo firewall-cmd --permanent --add-port=443/tcp
sudo firewall-cmd --permanent --add-port=8404/tcp
sudo firewall-cmd --reload

Test configuration syntax

Validate the HAProxy configuration before starting the service to catch any syntax errors.

sudo haproxy -c -f /etc/haproxy/haproxy.cfg
Note: If the configuration is valid, you'll see "Configuration file is valid". Fix any errors before proceeding.

Enable and start HAProxy

Enable HAProxy to start automatically on boot and start the service now.

sudo systemctl enable haproxy
sudo systemctl start haproxy
sudo systemctl status haproxy

Configure backend servers for health checks

Each backend server needs to respond to the health check endpoint. Create a simple health check on each web server.

echo 'OK' | sudo tee /var/www/html/health
sudo chmod 644 /var/www/html/health

Advanced load balancing configuration

Configure session persistence

For applications that require users to stick to the same backend server, configure session persistence using cookies.

backend web_servers
    balance roundrobin
    cookie SERVERUSED insert indirect nocache
    option httpchk GET /health
    http-check expect status 200
    
    server web1 192.168.1.10:80 check cookie web1 inter 30s fall 3 rise 2
    server web2 192.168.1.11:80 check cookie web2 inter 30s fall 3 rise 2
    server web3 192.168.1.12:80 check cookie web3 inter 30s fall 3 rise 2

Configure weighted load balancing

Assign different weights to servers based on their capacity. Higher weight servers receive more connections.

backend web_servers
    balance roundrobin
    option httpchk GET /health
    
    server web1 192.168.1.10:80 check weight 100 inter 30s fall 3 rise 2
    server web2 192.168.1.11:80 check weight 150 inter 30s fall 3 rise 2
    server web3 192.168.1.12:80 check weight 200 inter 30s fall 3 rise 2

Configure backup servers

Designate backup servers that only receive traffic when all primary servers are down.

backend web_servers
    balance roundrobin
    option httpchk GET /health
    
    server web1 192.168.1.10:80 check inter 30s fall 3 rise 2
    server web2 192.168.1.11:80 check inter 30s fall 3 rise 2
    server web3 192.168.1.12:80 check inter 30s fall 3 rise 2
    server backup1 192.168.1.20:80 check backup inter 30s fall 3 rise 2

Reload configuration after changes

Apply configuration changes without dropping existing connections using graceful reload.

sudo haproxy -c -f /etc/haproxy/haproxy.cfg
sudo systemctl reload haproxy

Set up monitoring and logging

Configure rsyslog for HAProxy logs

Enable UDP logging in rsyslog to receive HAProxy log messages.

# Enable UDP syslog reception
$ModLoad imudp
$UDPServerRun 514
$UDPServerAddress 127.0.0.1

HAProxy log file

local0.* /var/log/haproxy.log & stop

Restart rsyslog and create log file

Apply rsyslog changes and ensure the log file exists with correct permissions.

sudo systemctl restart rsyslog
sudo touch /var/log/haproxy.log
sudo chmod 640 /var/log/haproxy.log
sudo chown syslog:adm /var/log/haproxy.log

Update HAProxy logging configuration

Configure HAProxy to send logs to the local syslog server.

global
    # ... existing configuration ...
    log 127.0.0.1:514 local0

defaults
    # ... existing configuration ...
    log global
    option httplog
    option dontlognull

Verify your setup

Test the load balancing configuration and verify all components are working correctly.

# Check HAProxy status
sudo systemctl status haproxy

Test configuration syntax

sudo haproxy -c -f /etc/haproxy/haproxy.cfg

View backend server status

echo "show stat" | sudo socat stdio /run/haproxy/admin.sock

Test load balancing (run multiple times to see round-robin)

curl -I http://your-server-ip/

Check health check responses

curl -s http://192.168.1.10/health curl -s http://192.168.1.11/health curl -s http://192.168.1.12/health

View HAProxy statistics page

curl -u admin:secure_password_here http://your-server-ip:8404/stats
Note: Replace your-server-ip with your HAProxy server's IP address and update backend server IPs to match your environment.

Testing failover scenarios

Test automatic failover

Simulate server failures to verify HAProxy automatically removes failed servers from the pool.

# Stop web service on one backend server
sudo systemctl stop nginx  # or apache2

Monitor server status in HAProxy stats

watch 'echo "show stat" | sudo socat stdio /run/haproxy/admin.sock | grep web_servers'

Test that traffic still flows to healthy servers

for i in {1..10}; do curl -s http://your-server-ip/ | head -1; done

Test server recovery

Verify that recovered servers automatically rejoin the load balancer pool.

# Restart the stopped service
sudo systemctl start nginx  # or apache2

Verify server returns to active pool (may take 60-90 seconds)

echo "show stat" | sudo socat stdio /run/haproxy/admin.sock | grep web1

Performance optimization

Optimize connection handling

Tune HAProxy for high-traffic scenarios by adjusting connection limits and timeouts.

global
    # ... existing configuration ...
    maxconn 4096
    tune.ssl.default-dh-param 2048
    tune.bufsize 32768

defaults
    # ... existing configuration ...
    timeout connect 3s
    timeout client 30s
    timeout server 30s
    timeout http-keep-alive 3s
    timeout check 5s
    maxconn 3000

Enable connection multiplexing

Reduce backend server connections by reusing HTTP/1.1 keep-alive connections.

backend web_servers
    # ... existing configuration ...
    option http-server-close
    option forwardfor
    option httpchk GET /health
    http-reuse safe

Common issues

Symptom Cause Fix
HAProxy won't start Configuration syntax error sudo haproxy -c -f /etc/haproxy/haproxy.cfg to check syntax
Backend servers show as DOWN Health check endpoint missing or wrong Verify /health endpoint returns HTTP 200 on each backend
SSL certificate errors Certificate file not found or wrong format Ensure certificate is in PEM format and readable by haproxy user
Connection timeouts Backend servers not responding Check backend server status and network connectivity
Statistics page not accessible Firewall blocking port or wrong credentials Verify port 8404 is open and credentials are correct
No logs appearing Rsyslog not configured for HAProxy Restart rsyslog after adding HAProxy log configuration

Next steps

Running this in production?

Want this handled for you? Setting up HAProxy load balancing is straightforward. Keeping it monitored, optimized, and handling failover scenarios across environments is the harder part. See how we run infrastructure like this for European teams.

Need help?

Don't want to manage this yourself?

We handle private cloud infrastructure for businesses that depend on uptime. From initial setup to ongoing operations.