Load Balancing with HAProxy: Distributing Traffic and Health Checks in Practice
HAProxy is a load balancer that sits in front of several application servers, spreads requests across them by an algorithm you choose, and constantly checks their health, pulling a failed one out automatically. It gives you higher capacity and fault tolerance with no downtime the visitor sees.
The direct answer: HAProxy is a load balancer that sits as a gateway in front of several application servers, receives all visitor requests on a single address, then distributes them to the backend servers by an algorithm you choose, while continuously checking each server's health so it stops sending requests to any server that fails and returns it once it recovers. The two big benefits: higher capacity, because the load spreads across several machines instead of one that chokes, and fault tolerance, because one server going down does not stop the service, since the balancer routes visitors to the healthy servers without the visitor noticing anything. You place HAProxy on a front server, with two or more application servers behind it, turning a single point of failure into a resilient structure.
The practical setup is simpler than it looks. You define a group of backend servers, choose the distribution algorithm, configure the health check, and open a front listener that receives visitors. From the first moment you get real load distribution and automatic health monitoring. The most common algorithm, round-robin, distributes in turn, leastconn sends to the least busy server, and source pins each visitor to one server by their address. Each option suits a case, and the choice between them is driven by your application type and how it manages sessions.
How HAProxy actually distributes requests
When a request arrives, HAProxy decides its destination by the configured algorithm. round-robin is the simplest: it sends the first request to the first server, the second to the second, then loops, distributing evenly when server capacities match and request durations are similar. leastconn is smarter for uneven loads: it sends each new request to the server with the fewest active connections, preventing long requests from piling up on one server while another sits idle. source computes a value from the visitor's address and pins them to a specific server, which helps applications that store the session on the server itself.
The choice is practical, not theoretical. If your servers are identical and your requests are similar in length, round-robin is enough and keeps it simple. If request durations vary a lot, leastconn balances better. If your application needs the visitor to stay on their server, source or sticky sessions are the answer, which we come to next.
Health checks and pulling a failed server automatically
The most important feature of a load balancer is not distribution but health checking. HAProxy sends a periodic check to each backend server, a simple request on a given port or path, and waits for a healthy reply. When the server fails to respond a number of consecutive times, HAProxy considers it down and immediately stops sending requests to it, routing all load to the healthy servers. When the server returns to correct responses, HAProxy brings it back into service gradually. All of this is automatic with no intervention, so the visitor never sees an error page because their request never reaches the failed server.
This mechanism turns maintenance from a nightmare into a routine operation. Need to update an application server? Pull it out of distribution, update it, return it, and repeat with the second, so the service keeps running the whole time on the other server. A good health check is the difference between downtime the customer sees and maintenance nobody feels.
| Algorithm | How it distributes | Best suited for |
|---|---|---|
| round-robin | In turn across servers | Identical servers and similar request lengths |
| leastconn | To the server with fewest active connections | Requests of varying duration |
| source | Pins a visitor to a server by their address | Applications that store the session locally |
Sticky sessions and when you need them
Some applications store the user session in the memory of the server that first served them, so if the balancer routes their next request to another server, the session is lost and they are asked to log in again. The solution is sticky sessions: HAProxy pins each visitor to the server they started with for the duration of their session, either with the source algorithm or with a cookie the balancer plants. This solves the problem but reduces distribution flexibility, because a request-heavy visitor stays on one server.
The cleaner long-term solution is to make your application stateless, by storing sessions in a shared store like Redis or a database that all servers reach, so any request is valid on any server and the load distributes with full freedom. Sticky sessions are a quick fix, and the shared store is the right fix. Start with sticky if needed, and plan for the shared store as you grow.
A practical structure on CLOUD
The typical starting structure: a front server running HAProxy, two identical application servers behind it, and a shared database both reach. The balancer itself is light on resources because it forwards requests rather than processing them, so a base or growth plan is usually enough for it, while the two application servers need resources sized to your load. You spread the load across two machines, raising capacity and gaining resilience against one machine failing.
Each server activates automatically within seconds of payment, so you build this structure in minutes, and you upgrade any server's resources instantly as load grows with no rebuild. Try starting with a balancer and two application servers on a cloud server inside Riyadh with latency around 8ms for your visitors. Check the pricing page to match each layer's resources to your real load, since the balancer is light and the application scales to your need.
The beauty of this structure is that it grows horizontally with ease. When your load rises and two application servers are not enough, you add a third and a fourth and register them in the backend group, so the balancer starts distributing requests to them immediately with no change the visitor sees. This horizontal growth, adding mid-range machines rather than inflating one machine, is usually cheaper and more resilient: ten mid-range servers absorb one falling with a loss of only a tenth of capacity, while a single giant machine falling is a full stop. The practical rule: scale by adding machines to the group before you think of one larger machine, since the distribution itself is the source of resilience. Keep the application servers as identical as possible to make distribution and capacity planning easier.
TLS termination and observing what happens
The balancer is an ideal place to manage encryption. Instead of every application server carrying a TLS certificate and spending resources on decryption, HAProxy terminates the TLS connection at the gateway, receiving the visitor encrypted and passing the request to the backend servers inside your private network. This simplifies certificate management in one place and lightens the load on application servers. You can also re-encrypt traffic between the balancer and the backend if your security requires it, so the choice is yours based on how sensitive your data is.
The other important side is monitoring. HAProxy provides a live statistics page that shows each backend server's state: whether it is healthy or down, how many active connections it has, and how many requests it served. This window reveals a bottleneck before it becomes an outage, so you see, for example, a server approaching its limit and add a third before it falls. Tie HAProxy's logs to a monitoring system that collects metrics over time, so you get a historical picture rather than a momentary snapshot, and set an alert that reaches you when a backend server fails or load rises above a threshold. A balancer without monitoring works, but monitoring turns it from a black box into a structure you understand and control.
The single point of failure in the balancer itself
A logical question: if the balancer is the gateway for all load, is it not itself a single point of failure? Yes, and mature structures address this with two balancers in a high-availability arrangement, where the second takes over if the first drops through a virtual address that moves between them. To start, a single balancer improves the situation greatly compared to one lone application server, since it is simpler, lighter, and less prone to falling than an application server carrying all your logic. Add the second balancer when your scale justifies the extra complexity, not before.
Steps to start
- Set up a front server for the balancer and two identical application servers, the simplest useful balancing structure.
- Define the backend server group in HAProxy, and choose the algorithm: round-robin for identical servers, leastconn for varying requests.
- Configure the health check on a real path in your application, since it is what pulls a failed server automatically.
- Handle sessions: sticky as a quick fix, or a shared store like Redis as the right long-term fix.
- Test by deliberately stopping a backend server and watch the balancer move the load to the other with no downtime the visitor sees.
The bottom line is that HAProxy turns a simple, outage-prone structure into one that distributes load and withstands failures. Start with a balancer and two application servers, configure the health check well, plan for stateless sessions, and expand to a second balancer as your scale grows.


