HAProxy doesn’t actually have "listen sections"; it uses a combined frontend and backend structure to define how it accepts connections and where it sends them.
Here’s HAProxy in action, taking in web traffic on port 80 and sending it to a cluster of application servers:
frontend http_in
bind *:80
mode http
default_backend web_servers
backend web_servers
mode http
balance roundrobin
server app1 192.168.1.10:8000 check
server app2 192.168.1.11:8000 check
server app3 192.168.1.12:8000 check
This configuration tells HAProxy:
frontend http_in: Listen on all interfaces (*:80) for incoming HTTP traffic.default_backend web_servers: If no specific rules match, send this traffic to theweb_serversbackend.backend web_servers: This is a pool of servers namedweb_servers.mode http: HAProxy will inspect HTTP headers and content.balance roundrobin: Distribute incoming requests evenly among the available servers in this backend.server app1 192.168.1.10:8000 check: Defineapp1as a server at that IP and port, and periodically check its health.
HAProxy shines when you need a robust, high-performance TCP/HTTP load balancer and proxy. It handles connection termination, SSL offloading, request routing based on complex rules, and health checks for your backend services, all with minimal latency and high concurrency.
The real power comes from its ability to inspect traffic and make intelligent routing decisions. For instance, you can direct traffic based on the URL path:
frontend http_in
bind *:80
mode http
acl path_is_api /api/*
acl path_is_static /static/*
use_backend api_servers if path_is_api
use_backend static_files if path_is_static
default_backend web_servers
backend api_servers
mode http
balance roundrobin
server api1 192.168.1.20:8080 check
server api2 192.168.1.21:8080 check
backend static_files
mode http
balance roundrobin
server file1 192.168.1.30:80 check
server file2 192.168.1.31:80 check
In this setup, requests to /api/* go to api_servers, requests to /static/* go to static_files, and anything else defaults to web_servers.
The most surprising thing about HAProxy’s configuration is how granular you can get with ACLs (Access Control Lists) and actions. You can match on almost any part of an HTTP request – headers, cookies, the URI, the client IP, even the HTTP method – and then perform actions like routing, returning an error, or modifying the request. This allows for very sophisticated traffic management without needing to deploy separate layers for different types of traffic. For example, you can have a single frontend listening on port 443 (HTTPS) that serves multiple backend applications, each with its own SSL certificate, by using SNI (Server Name Indication) matching.
The mode tcp versus mode http distinction is fundamental. mode tcp operates at the transport layer, simply forwarding raw TCP connections. It’s fast and works for any protocol. mode http operates at the application layer, allowing HAProxy to understand and manipulate HTTP requests and responses. This enables features like URL rewriting, header manipulation, and sticky sessions based on cookies.
When you configure a server line, the check option is crucial. HAProxy will send a health check probe (which can be configured to be a simple TCP connection, an HTTP GET, or even a custom script) to the backend server. If the check fails, HAProxy marks the server as down and stops sending traffic to it until it becomes healthy again. You can fine-tune these checks with options like inter (interval between checks), rise (number of successful checks to bring a server back up), and fall (number of failed checks to mark a server down).
One thing that trips many people up is understanding how acl and use_backend directives interact. The order matters. HAProxy evaluates ACLs sequentially. The first use_backend directive whose associated ACL evaluates to true will be the one that routes the traffic. If no use_backend directive matches, HAProxy falls back to the default_backend defined in the frontend. It’s a cascade of matching rules.
The next concept to dive into is advanced health checking and connection pooling.