HAProxy is a high-performance load balancer and proxy for TCP and HTTP. It’s the engine behind many large websites’ traffic distribution, known for reliability, detailed health checks and excellent observability. If you need to spread traffic across several application servers — or databases — HAProxy is a strong choice.

Install

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

Ubuntu’s version is fine for most uses; the HAProxy team publishes PPAs with newer LTS branches if you need recent features.

Configuration lives in /etc/haproxy/haproxy.cfg.

Configuration structure

global      → process-wide settings (logging, limits, TLS defaults)
defaults    → defaults for all frontends/backends (mode, timeouts)
frontend    → where clients connect (bind address, ACLs, routing)
backend     → server pools traffic is sent to
listen      → frontend + backend combined (handy for simple services)

A basic HTTP load balancer

global
    log /dev/log local0
    maxconn 20000
    user haproxy
    group haproxy
    daemon

defaults
    mode http
    log global
    option httplog
    option forwardfor
    timeout connect 5s
    timeout client  30s
    timeout server  30s

frontend http_in
    bind *:80
    default_backend app_servers

backend app_servers
    balance roundrobin
    option httpchk GET /health
    http-check expect status 200
    server app1 10.0.0.11:3000 check
    server app2 10.0.0.12:3000 check
    server app3 10.0.0.13:3000 check backup
  • option forwardfor adds the client IP in X-Forwarded-For.
  • option httpchk + check enables active health checks: HAProxy polls /health on each server and removes failing ones automatically.
  • backup servers receive traffic only when all others are down.

Validate and reload:

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

Reloads are seamless: existing connections continue on the old process.

Balancing algorithms

balance Behaviour
roundrobin In turn, respecting weights (default)
leastconn Fewest active connections — good for long requests, WebSockets, databases
source Same client IP → same server
uri / url_param / hdr(name) Hash on request parts (caches, sharding)
random Random with optional “power of two choices”

Weights: server app1 10.0.0.11:3000 check weight 3.

TLS termination

Combine certificate and key into one PEM file per domain:

sudo mkdir -p /etc/haproxy/certs
sudo sh -c 'cat /etc/letsencrypt/live/example.com/fullchain.pem /etc/letsencrypt/live/example.com/privkey.pem > /etc/haproxy/certs/example.com.pem'
sudo chmod 600 /etc/haproxy/certs/*.pem
frontend https_in
    bind *:443 ssl crt /etc/haproxy/certs/ alpn h2,http/1.1
    bind *:80
    http-request redirect scheme https unless { ssl_fc }
    http-request set-header X-Forwarded-Proto https if { ssl_fc }
    default_backend app_servers

Pointing crt at a directory loads all certificates and selects by SNI. Automate renewals with a Certbot deploy hook that rebuilds the PEM files and reloads HAProxy (or use the HTTP-01 challenge via a backend that forwards /.well-known/acme-challenge/ to Certbot’s standalone server).

Routing by host or path

frontend https_in
    bind *:443 ssl crt /etc/haproxy/certs/
    acl is_api hdr(host) -i api.example.com
    acl is_static path_beg /static/
    use_backend api_servers if is_api
    use_backend static_servers if is_static
    default_backend app_servers

Sticky sessions

If an app keeps sessions in memory:

backend app_servers
    balance roundrobin
    cookie SRV insert indirect nocache
    server app1 10.0.0.11:3000 check cookie a1
    server app2 10.0.0.12:3000 check cookie a2

Better long-term: store sessions in Redis so any server can handle any request.

TCP mode (databases, other protocols)

listen postgres_read
    bind 10.0.0.5:5433
    mode tcp
    balance leastconn
    option pgsql-check user haproxy
    server db1 10.0.0.21:5432 check
    server db2 10.0.0.22:5432 check

Stats page

listen stats
    bind 127.0.0.1:8404
    stats enable
    stats uri /
    stats refresh 10s

Open via SSH tunnel (ssh -L 8404:127.0.0.1:8404 user@lb). It shows each server’s status, sessions, errors and response times. A Prometheus exporter endpoint is built in too (http-request use-service prometheus-exporter if { path /metrics }).

Logging

HAProxy logs to syslog; on Ubuntu, the package configures rsyslog to write /var/log/haproxy.log. Logs include timings for each phase of the request — invaluable for spotting slow backends.

High availability for HAProxy itself

Run two HAProxy servers with a floating IP managed by keepalived — see keepalived floating IP.

HAProxy vs Nginx

Nginx is a web server that also load-balances; HAProxy is a dedicated load balancer with richer health checks, stickiness options and statistics. For a simple setup, Nginx load balancing is enough; for serious traffic engineering, HAProxy shines. See also load balancer types.

  • HAProxy
  • Load Balancing
  • High Availability