Software & Configuration

HAProxy Load Balancer

Install and configure HAProxy as a TCP/HTTP load balancer and reverse proxy on Linux

HAProxy is a high-performance TCP/HTTP load balancer and proxy. It's widely used to distribute traffic across multiple backend servers, handle health checks, and terminate SSL.

Use cases

  • Load balance web servers (Nginx/Apache/Node.js)
  • TCP load balancing for databases or game servers
  • SSL/TLS termination
  • High-availability failover between backends

Installation

sudo apt update
sudo apt install haproxy -y
haproxy -v

Configuration file

The main config is at /etc/haproxy/haproxy.cfg. Back it up first:

sudo cp /etc/haproxy/haproxy.cfg /etc/haproxy/haproxy.cfg.bak

Basic HTTP load balancing

Replace the default config with:

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

defaults
    log     global
    mode    http
    option  httplog
    option  dontlognull
    timeout connect 5s
    timeout client  50s
    timeout server  50s
    errorfile 400 /etc/haproxy/errors/400.http
    errorfile 503 /etc/haproxy/errors/503.http

frontend http_front
    bind *:80
    default_backend web_servers

backend web_servers
    balance roundrobin
    option httpchk GET /health
    server web1 10.0.0.1:80 check
    server web2 10.0.0.2:80 check
    server web3 10.0.0.3:80 check

Test the configuration:

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

Apply:

sudo systemctl restart haproxy

Load balancing algorithms

AlgorithmConfigDescription
Round Robinbalance roundrobinRequests distributed in turn
Least Connectionsbalance leastconnSend to server with fewest active connections
Source IP hashbalance sourceSame client always goes to same server
URI hashbalance uriSame URL always goes to same server (cache-friendly)

SSL termination

Install Certbot and obtain a certificate, then combine the files:

sudo cat /etc/letsencrypt/live/yourdomain.com/fullchain.pem \
         /etc/letsencrypt/live/yourdomain.com/privkey.pem \
  | sudo tee /etc/haproxy/certs/yourdomain.com.pem
sudo chmod 600 /etc/haproxy/certs/yourdomain.com.pem

Update the frontend:

frontend https_front
    bind *:443 ssl crt /etc/haproxy/certs/yourdomain.com.pem
    http-request set-header X-Forwarded-Proto https
    default_backend web_servers

frontend http_front
    bind *:80
    http-request redirect scheme https unless { ssl_fc }

Health checks

HAProxy removes servers from the pool if they fail health checks:

backend web_servers
    option httpchk GET /health HTTP/1.1\r\nHost:\ yourdomain.com
    http-check expect status 200
    server web1 10.0.0.1:80 check inter 5s fall 3 rise 2
    server web2 10.0.0.2:80 check inter 5s fall 3 rise 2
  • inter 5s: check every 5 seconds
  • fall 3: mark down after 3 consecutive failures
  • rise 2: mark up again after 2 consecutive successes

Sticky sessions

Keep a user on the same backend server using a cookie:

backend web_servers
    balance roundrobin
    cookie SERVERID insert indirect nocache
    server web1 10.0.0.1:80 check cookie web1
    server web2 10.0.0.2:80 check cookie web2

TCP load balancing

For non-HTTP protocols (databases, game servers, SMTP):

frontend mysql_front
    bind *:3306
    mode tcp
    default_backend mysql_servers

backend mysql_servers
    mode tcp
    balance leastconn
    option mysql-check user haproxy
    server db1 10.0.0.10:3306 check
    server db2 10.0.0.11:3306 check backup

The backup keyword means db2 only receives traffic if db1 is down.


Statistics dashboard

Enable the built-in stats page:

frontend stats
    bind *:8404
    stats enable
    stats uri /stats
    stats refresh 10s
    stats auth admin:StrongPassword123!
    stats hide-version

Access at http://your-server:8404/stats.

Restrict the stats port with a firewall rule, never expose it publicly without authentication.


Rate limiting

Block clients sending too many requests:

frontend http_front
    bind *:80
    stick-table type ip size 100k expire 30s store conn_rate(10s)
    http-request track-sc0 src
    http-request deny deny_status 429 if { sc_conn_rate(0) gt 50 }
    default_backend web_servers

This denies clients making more than 50 connections per 10 seconds.


Useful commands

# Reload config without dropping connections
sudo systemctl reload haproxy

# Check config syntax
sudo haproxy -c -f /etc/haproxy/haproxy.cfg

# Live status via socket
echo "show info" | sudo socat stdio /run/haproxy/admin.sock
echo "show servers state" | sudo socat stdio /run/haproxy/admin.sock

# View logs
journalctl -u haproxy -f

Disable a backend server temporarily

echo "disable server web_servers/web1" | sudo socat stdio /run/haproxy/admin.sock
# Re-enable:
echo "enable server web_servers/web1" | sudo socat stdio /run/haproxy/admin.sock

On this page