HAProxy Basics
Introduction¶
HAProxy sits in front of your servers and distributes connections. It does L4 (TCP) or L7 (HTTP) load balancing, TLS termination, health checking, and content-based routing, all from one config file.
The model¶
frontend -> receives client connections (a bind address + port)
| (ACLs decide which backend)
backend -> a pool of servers + how to pick one + how to health-check them
A working config¶
global
log /dev/log local0
maxconn 20000
stats socket /run/haproxy/admin.sock mode 660 level admin
defaults
mode http
log global
option httplog
option dontlognull
timeout connect 5s
timeout client 30s
timeout server 30s
retries 3
frontend fe_web
bind :80
bind :443 ssl crt /etc/haproxy/certs/site.pem alpn h2,http/1.1
http-request redirect scheme https unless { ssl_fc }
http-request set-header X-Forwarded-Proto https if { ssl_fc }
acl is_api path_beg /api/
acl is_static path_end .jpg .css .js .png .woff2
use_backend be_api if is_api
use_backend be_static if is_static
default_backend be_app
backend be_app
balance roundrobin
option httpchk GET /healthz
http-check expect status 200
cookie SRVID insert indirect nocache
server app1 10.0.1.11:8080 check cookie app1
server app2 10.0.1.12:8080 check cookie app2
backend be_api
balance leastconn
option httpchk GET /api/health
server api1 10.0.2.11:3000 check
server api2 10.0.2.12:3000 check
backend be_static
balance roundrobin
server cdn1 10.0.3.11:80 check
listen stats
bind :8404
stats enable
stats uri /
stats refresh 10s
stats auth admin:changeme
Key concepts¶
mode httpvsmode tcp— L7 lets you route by path/host/header, rewrite, and terminate TLS. L4 is faster and protocol-agnostic (databases, SMTP, raw TCP). Set per frontend/backend.balance—roundrobin(weighted, default),leastconn(fewest active connections — good for long-lived/uneven requests),source(hash client IP — crude stickiness),uri/hdr(...)(cache affinity),random.- Health checks —
checkon a server enables it;option httpchk+http-check expectmakes it an HTTP check instead of a bare TCP connect. Alsocheck inter 2s fall 3 rise 2for timing. - Sticky sessions —
cookie SRVID insertadds a cookie naming the server; subsequent requests from that client go back to it. Prefer stateless apps; use stickiness only when you must. - ACLs — named boolean conditions (
path_beg,hdr(host) -i example.com,src 10.0.0.0/8,ssl_fc) combined inuse_backend ... if.
TLS¶
- Terminate:
bind :443 ssl crt file.pem— HAProxy decrypts, backends get plain HTTP (or re-encrypt withserver ... ssl). - The
.pemis the fullchain cert + private key concatenated. A directory of.pems withcrt /etc/haproxy/certs/does SNI selection. - Modern TLS:
ssl-default-bind-ciphersuites,ssl-min-ver TLSv1.2.
Verification and troubleshooting¶
haproxy -c -f /etc/haproxy/haproxy.cfg # config check
echo "show stat" | socat - /run/haproxy/admin.sock | column -s, -t
echo "show servers state" | socat - /run/haproxy/admin.sock
# stats page: http://lb:8404/ (auth admin:changeme)
The stats page columns: Status (UP/DOWN/MAINT), LastChk (why a check
failed), Sessions, Bytes, Denied, Errors, Warnings, Server.
- All servers DOWN, "L7STS/404" or "L4CON" — the health check path 404s
(wrong
option httpchkURL), or the port/host is wrong (L4CON = can't even connect), or a backend firewall. - 503 Service Unavailable from HAProxy — no backend server is UP. Check the
stats page
LastChk. - 502 Bad Gateway — backend closed the connection / sent a malformed
response, or
timeout servertoo short for a slow endpoint. - 504 Gateway Timeout —
timeout connect(can't reach backend) ortimeout server(backend too slow). - Sticky sessions not sticking — client not sending cookies, or
cookiedirective missing on theserverlines, ornocacheinterfering with a caching proxy. - Client IP lost at the backend — add
option forwardfor(X-Forwarded-For) inmode http, or use the PROXY protocol (send-proxy+ backend support) inmode tcp. - TLS handshake fails — cert/key not concatenated in the
.pem, chain incomplete, or the client needs a cipher you disabled.openssl s_client -connect lb:443. - Reload drops connections — use
haproxy -sf $(cat pid)/ systemd'sreloadwhich does a seamless handover; hitless reloads keep existing connections.
Related tools and reading¶
- On-site: SSL Certificate Checker, Port Checker, HTTP Header Analyzer.
- Related posts: VRRP and keepalived, An Nginx reverse proxy with TLS.
Stuck on something this site can't fix?Reach out to Prabath directly on LinkedIn.More in Web & Mail Servers
Running BIND 9 as an Authoritative Server
BIND as an authoritative server: zone files, secured AXFR with TSIG, SOA serial rules, and DNSSEC inline-signing. Here's a working master/slave setup.
October 24, 2026Varnish Cache in Front of a Site
Varnish is a caching HTTP accelerator configured in VCL. Here's the request lifecycle, why you strip cookies, how bans work, and grace mode for serving stale during backend trouble.
October 24, 2026Let's Encrypt with Certbot, Including Renewal That Doesn't Break
Getting the first cert is easy; keeping renewal working for years is the part people get wrong. Webroot vs DNS-01, deploy hooks, and the failure modes.
October 24, 2026