HAProxy can serve every single request that hits your application, but most people configure it to only handle a fraction of them.

Let’s see HAProxy in action, balancing traffic between two backend web servers.

frontend http_frontend
    bind *:80
    mode http
    default_backend http_backend

backend http_backend
    mode http
    balance roundrobin
    server webserver1 192.168.1.10:80 check
    server webserver2 192.168.1.11:80 check

When a request comes into *:80 on the HAProxy server, it’s directed to the http_backend. The balance roundrobin directive means HAProxy will send the first request to webserver1, the second to webserver2, the third back to webserver1, and so on, distributing the load evenly. The check option tells HAProxy to periodically ping webserver1 and webserver2 on port 80 to ensure they are healthy. If a server fails the check, HAProxy will temporarily stop sending traffic to it.

The core problem HAProxy solves is distributing incoming network traffic across multiple backend servers. This increases reliability (if one server fails, others take over) and scalability (you can add more servers to handle more traffic). Internally, HAProxy is a high-performance TCP/HTTP load balancer and proxy. It operates at the network layer (layer 4) and application layer (layer 7), allowing it to inspect HTTP headers, cookies, and other application-level data to make intelligent routing decisions. The frontend section defines how HAProxy listens for incoming connections, specifying the IP address, port, and protocol. The backend section defines the pool of servers that will handle the requests, along with the load balancing algorithm and health check configurations.

You control HAProxy’s behavior through a rich configuration language. Key directives include:

  • bind: Specifies the IP address and port HAProxy listens on. For production, you’d typically bind to a public IP address and port 80/443.
  • mode: http for layer 7 load balancing (inspecting HTTP traffic) or tcp for layer 4 (raw TCP connections).
  • balance: The algorithm used to distribute traffic. Common options are roundrobin (default, cycles through servers), leastconn (sends to the server with the fewest active connections), and source (hashes the client IP to stick a client to the same server).
  • server: Defines a backend server with its IP address, port, and health check parameters.
  • option httpchk: Configures HAProxy to perform an HTTP-specific health check, like expecting a 200 OK response from a specific URL.
  • acl (Access Control List) and use_backend: These allow for sophisticated routing rules. You can direct traffic based on HTTP headers, request URIs, or source IPs to different backend pools. For example, you could send requests for /api/v1 to one set of servers and /api/v2 to another.

The health check mechanism is more than just a ping; it’s a sophisticated system that allows HAProxy to understand the actual state of your backend services. When you configure server webserver1 192.168.1.10:80 check inter 2s fall 3 rise 2, you’re telling HAProxy to send a TCP connection attempt every 2 seconds (inter 2s). If three consecutive connection attempts fail (fall 3), the server is marked as down. It will then try to bring it back up by performing two consecutive successful checks (rise 2) before marking it as healthy again. This granular control prevents HAProxy from prematurely removing a healthy but momentarily slow server or from sending traffic to a server that’s genuinely struggling.

When you’re dealing with SSL/TLS termination at HAProxy, the configuration shifts slightly. You’ll typically have your frontend listening on port 443 and specifying the certificate file.

frontend https_frontend
    bind *:443 ssl crt /etc/haproxy/certs/my-app.pem
    mode http
    http-request redirect scheme https code 301 if !{ ssl_fc }
    default_backend http_backend

backend http_backend
    mode http
    balance roundrobin
    server webserver1 192.168.1.10:80 check
    server webserver2 192.168.1.11:80 check

Here, bind *:443 ssl crt /etc/haproxy/certs/my-app.pem tells HAProxy to listen on port 443, enable SSL/TLS, and use the certificate and private key found in my-app.pem. The http-request redirect scheme https code 301 if !{ ssl_fc } line is a common pattern to force all incoming HTTP traffic on port 80 (if HAProxy were also listening there) to redirect to HTTPS, ensuring all communication is encrypted. The backend configuration remains the same, as HAProxy decrypts the SSL traffic and sends plain HTTP to the backend servers.

The real power of HAProxy for production traffic lies in its ability to make decisions based on the content of the HTTP request, not just the IP and port. This is achieved using Access Control Lists (ACLs) and use_backend directives. For instance, you might have different backend pools for your API versus your static assets.

frontend http_frontend
    bind *:80
    mode http

    acl is_api hdr(Host) -i api.example.com
    acl is_static path_beg /static/

    use_backend api_backend if is_api
    use_backend static_backend if is_static
    default_backend web_backend

backend api_backend
    mode http
    balance roundrobin
    server api1 192.168.1.20:8000 check
    server api2 192.168.1.21:8000 check

backend static_backend
    mode http
    balance roundrobin
    server static1 192.168.1.30:9000 check

backend web_backend
    mode http
    balance roundrobin
    server web1 192.168.1.10:80 check
    server web2 192.168.1.11:80 check

In this setup, requests to api.example.com are routed to api_backend, requests starting with /static/ go to static_backend, and everything else falls through to web_backend. This allows for granular control and optimization of different parts of your application, directing them to servers best suited for their specific workloads.

The next step is often implementing HAProxy for sticky sessions, ensuring a user remains connected to the same backend server throughout their session.

Want structured learning?

Take the full Load-balancing course →