HAProxy Load Balancing with Health Checks
Front a pair of app servers with HAProxy, configure TCP and HTTP health checks, and let automatic failover keep your availability intact through outages.
Netbay Cloud Team
Netbay Engineering
On this page
HAProxy is the load balancer you reach for when one Nginx is no longer enough. It is a single, event-driven process built specifically for proxying: it can split traffic across many backend servers, detect dead ones with health checks, and keep serving the survivors without a human in the loop. On a two-instance setup inside a single datacenter it is the difference between a server crash and a blip users never notice.
The two halves: frontend and backend
Every interesting HAProxy config has a frontend and a backend. The frontend listens on a public address and port and decides which backend to send things to. The backend names a pool of servers with their addresses, ports, and the rules for marking them healthy or broken. Traffic flows one direction through the pair, and the config file is a sequence of self-contained blocks with a consistent key value syntax.
A balanced backend with active health checks
This config exposes port 443 to the internet and round-robins requests across two copies of the same app on localhost.
global
log stdout format raw local0
maxconn 4096
defaults
mode http
timeout connect 5s
timeout client 30s
timeout server 30s
frontend ft_web
bind :443 ssl crt /etc/haproxy/certs.pem
default_backend bk_app
backend bk_app
balance roundrobin
option httpchk GET /health
http-check expect status 200
server app1 127.0.0.1:3001 check inter 2s rise 2 fall 3
server app2 127.0.0.1:3002 check inter 2s rise 2 fall 3The health check is the load balancer's opinion of reality. Every two seconds during an ongoing check cycle HAProxy asks each server for /health and expects status 200. A server is declared up after 2 consecutive successes and down after 3 consecutive failures. Once a server is marked down, HAProxy stops sending it production traffic immediately — no broken requests, no retries you have to explain to users.
Why the check design matters
The default behavior of any load balancer is blind round-robin, which is useless the moment one copy misbehaves. A good check verifies more than TCP reachability:
- **Path matters.** Check an endpoint that exercises the app's real startup state, like /health, not just the listening socket.
- **Expect codes.** http-check expect status 200 collapses HTTP errors such as 500 and 503 into a failing check.
- **Intervals and thresholds.** Two-second intervals find failures fast, while the rise and fall counters stop a flapping server from being toggled on every blip.
See the state, not just the config
HAProxy exposes a stats socket you can query without reloading anything.
echo "show stat" | socat /run/haproxy/admin.sock stdio | cut -d, -f1,2,18
echo "show servers state" | socat /run/haproxy/admin.sock stdioThe show stat line prints a table whose columns include the frontend, backend, and per-server status fields — UP, DOWN, and things like L7_OK during a check. When you scale back down, disable a server from the socket rather than editing the file and reloading: it changes state without bouncing the process.
Takeaway
HAProxy turns a fragile single-instance app into a pool where a crash costs you nothing visible to users. The health check interval and thresholds are the part to tune first — too slow to fail means you keep serving errors, too aggressive means flapping. Pair it with the stats socket and you can manage capacity live. Scale two copies on a single Netbay VPS, or two small instances, and point HAProxy at both — netbayhosts.in provisions in under 60 seconds.
Keep reading
Follow along on a real VPS
Deploy Linux in under 60 seconds
These guides are written against Ubuntu, Debian, and RHEL-family images — the same ones on NetBay.
Deploy an instance