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
Install HAProxy
Install HAProxy from the official repositories. This provides the latest stable version with security updates.
sudo apt 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
Test configuration syntax
Validate the HAProxy configuration before starting the service to catch any syntax errors.
sudo haproxy -c -f /etc/haproxy/haproxy.cfg
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
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
- Set up HAProxy high availability with keepalived clustering for automatic failover
- Configure HAProxy SSL termination with Let's Encrypt and security headers
- Monitor HAProxy and Consul with Prometheus and Grafana dashboards
- Implement HAProxy WAF integration with ModSecurity 3 for advanced threat protection
- Configure HAProxy advanced routing with ACLs and maps for intelligent traffic management