What is HAProxy?
HAProxy (High Availability Proxy) is a free, open-source software that provides a high-performance TCP/HTTP load balancer and proxy server. It is designed to distribute incoming network traffic across multiple backend servers, ensuring high availability, reliability, and optimal resource utilization for web applications and services.
At its core, HAProxy operates as a reverse proxy, sitting between clients and backend servers. It accepts incoming requests, analyzes them based on configurable rules, and forwards them to the most appropriate backend server. HAProxy supports proxying at both Layer 4 (TCP) and Layer 7 (HTTP), making it incredibly versatile for a wide range of use cases including web applications, databases, APIs, and microservices.
Why HAProxy Matters
🚀 Deploy your AI agent in 10 minutes
Managed Hermes hosting. Zero DevOps. 100M tokens/mo included.
Try it free →HAProxy has become a critical component in modern infrastructure for several compelling reasons:
High Availability and Fault Tolerance
HAProxy continuously monitors the health of backend servers through active and passive health checks. When a server fails or becomes unresponsive, HAProxy automatically removes it from the pool and redirects traffic to healthy servers. This seamless failover capability ensures zero-downtime deployments and resilient production environments.
Scalability Through Load Distribution
As traffic grows, a single server inevitably becomes a bottleneck. HAProxy distributes client requests across multiple servers using configurable load-balancing algorithms such as round-robin, least connections, and source IP hashing. This horizontal scaling approach allows applications to handle millions of concurrent connections efficiently.
Performance and Efficiency
HAProxy is written in C and is engineered for extreme performance. It can handle tens of thousands of connections per second on modest hardware while consuming minimal CPU and memory resources. Its event-driven, non-blocking I/O architecture allows it to proxy traffic at near line-speed with sub-millisecond latency overhead.
Advanced Traffic Routing
With its powerful Access Control List (ACL) system, HAProxy can route traffic based on virtually any request attribute — hostname, path, headers, cookies, source IP, or even SSL certificate information. This enables sophisticated routing scenarios like content-based switching, A/B testing, canary deployments, and microservice routing.
Security and DDoS Protection
HAProxy acts as a shield for backend servers. It can absorb and filter malicious traffic, enforce rate limiting, validate HTTP requests, terminate SSL/TLS connections, and protect against common web attacks before they reach your application servers.
Installation
HAProxy is available in most Linux distribution repositories. The recommended approach is to install the latest stable version from the official HAProxy repository for your distribution.
Installing on Ubuntu/Debian
# Update package list
sudo apt update
# Install HAProxy
sudo apt install haproxy -y
# Verify installation
haproxy -v
Installing on CentOS/RHEL/Rocky Linux
# Install EPEL repository (if not already present)
sudo yum install epel-release -y
# Install HAProxy
sudo yum install haproxy -y
# Verify installation
haproxy -v
Installing the Latest Version from HAProxy Repository
For production environments, it is recommended to use the latest stable version from the official HAProxy repositories. The following example demonstrates installation on Ubuntu 22.04:
# Add HAProxy repository
sudo apt install --no-install-recommends software-properties-common
sudo add-apt-repository ppa:vbernat/haproxy-2.8 -y
# Install the latest version
sudo apt update
sudo apt install haproxy=2.8.\* -y
After installation, the HAProxy service can be managed using systemd:
# Enable HAProxy to start on boot
sudo systemctl enable haproxy
# Start the service
sudo systemctl start haproxy
# Check service status
sudo systemctl status haproxy
# Restart after configuration changes
sudo systemctl restart haproxy
# Reload without dropping connections
sudo systemctl reload haproxy
Configuration File Structure
The main HAProxy configuration file is located at /etc/haproxy/haproxy.cfg. The configuration is organized into several distinct sections, each serving a specific purpose:
# /etc/haproxy/haproxy.cfg
global
# Process-level and system-wide settings
defaults
# Default settings inherited by all sections below
frontend
# How HAProxy listens for incoming connections
backend
# Pools of servers that receive forwarded traffic
listen
# Combines frontend and backend in a single section
Let's examine each section in detail.
The global Section
The global section configures process-wide parameters that affect HAProxy's overall operation. This includes logging, user/group privileges, performance tuning, and security settings.
global
log /dev/log local0
log /dev/log local1 notice
chroot /var/lib/haproxy
stats socket /run/haproxy/admin.sock mode 660 level admin
stats timeout 30s
user haproxy
group haproxy
daemon
# SSL/TLS performance tuning
tune.ssl.default-dh-param 2048
ssl-default-bind-ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256
ssl-default-bind-options no-sslv3 no-tlsv10 no-tlsv11
# Default TLS curves
ssl-default-server-curves X25519:P-256
# Performance tuning for high connection counts
maxconn 100000
nbthread 4
cpu-map auto:1-4
The defaults Section
The defaults section defines configuration parameters that are inherited by all subsequent frontend and backend sections unless explicitly overridden. This reduces repetition and ensures consistency.
defaults
log global
mode http
option httplog
option dontlognull
option forwardfor
option http-server-close
timeout connect 5000
timeout client 50000
timeout server 50000
errorfile 400 /etc/haproxy/errors/400.http
errorfile 403 /etc/haproxy/errors/403.http
errorfile 408 /etc/haproxy/errors/408.http
errorfile 500 /etc/haproxy/errors/500.http
errorfile 502 /etc/haproxy/errors/502.http
errorfile 503 /etc/haproxy/errors/503.http
errorfile 504 /etc/haproxy/errors/504.http
Key timeout parameters explained:
- timeout connect — Maximum time to wait for a connection to a backend server to establish
- timeout client — Maximum inactivity time on the client side before HAProxy closes the connection
- timeout server — Maximum inactivity time on the server side before HAProxy closes the connection
Basic Load Balancing Configuration
The simplest and most common HAProxy configuration involves defining a frontend that listens for client connections and a backend that specifies the pool of servers. Here is a complete working example:
frontend web_frontend
bind *:80
bind *:443 ssl crt /etc/ssl/certs/mysite.pem
# Redirect HTTP to HTTPS
http-request redirect scheme https code 301 if !{ ssl_fc }
default_backend web_servers
backend web_servers
balance roundrobin
option httpchk GET /health
server web1 192.168.1.10:80 check inter 3s rise 2 fall 3
server web2 192.168.1.11:80 check inter 3s rise 2 fall 3
server web3 192.168.1.12:80 check inter 3s rise 2 fall 3 maxconn 500
This configuration does the following:
- Listens on ports 80 (HTTP) and 443 (HTTPS) with an SSL certificate
- Redirects all HTTP traffic to HTTPS using a 301 redirect
- Distributes traffic across three backend servers using the round-robin algorithm
- Performs active health checks by requesting
/healthevery 3 seconds - Uses
rise 2andfall 3— a server needs 2 consecutive successful health checks to be considered UP and 3 consecutive failures to be considered DOWN
Load Balancing Algorithms
HAProxy offers several load balancing algorithms through the balance directive. Each algorithm suits different workloads and scenarios:
Round Robin
backend web_servers
balance roundrobin
server web1 10.0.0.1:80 check
server web2 10.0.0.2:80 check
Distributes connections evenly in a circular order. Best for stateless applications where all servers have similar capacity.
Least Connections
backend api_servers
balance leastconn
server api1 10.0.0.1:8080 check
server api2 10.0.0.2:8080 check
server api3 10.0.0.3:8080 check
Sends traffic to the server with the fewest active connections. Ideal for long-lived connections like WebSocket or database queries.
Source IP Hash
backend sticky_servers
balance source
hash-type consistent
server app1 10.0.0.1:8080 check
server app2 10.0.0.2:8080 check
Hashes the client's source IP to consistently route the same client to the same server. This enables session persistence without cookies. The hash-type consistent option minimizes redistribution when servers are added or removed.
URI Hash
backend cache_servers
balance uri
hash-type consistent
server cache1 10.0.0.1:8080 check
server cache2 10.0.0.2:8080 check
Hashes the URI to ensure that the same resource always goes to the same server. Useful for caching proxies.
Random with Weighted Distribution
backend weighted_servers
balance random
server large1 10.0.0.1:80 weight 3 check
server large2 10.0.0.2:80 weight 3 check
server small1 10.0.0.3:80 weight 1 check
Uses random selection with optional weights. The weight parameter allows distributing traffic proportionally based on server capacity.
Access Control Lists (ACLs) and Routing Logic
ACLs are one of HAProxy's most powerful features, enabling content-based routing, filtering, and traffic manipulation based on arbitrary request characteristics. ACLs evaluate conditions and return true or false, allowing you to build complex routing logic.
Host-Based Routing (Name-Based Virtual Hosting)
frontend http_frontend
bind *:80
bind *:443 ssl crt /etc/haproxy/certs/
# Define ACLs for hostnames
acl is_app_host hdr(host) -i app.example.com
acl is_api_host hdr(host) -i api.example.com
acl is_admin_host hdr(host) -i admin.example.com
# Route based on hostname
use_backend app_servers if is_app_host
use_backend api_servers if is_api_host
use_backend admin_servers if is_admin_host
default_backend fallback_servers
backend app_servers
server app1 10.0.0.1:8080 check
server app2 10.0.0.2:8080 check
backend api_servers
server api1 10.0.0.3:8080 check
server api2 10.0.0.4:8080 check
backend admin_servers
server admin1 10.0.0.5:8080 check
backend fallback_servers
server default1 10.0.0.6:8080 check
Path-Based Routing (URL Prefix Routing)
frontend web_frontend
bind *:80
acl is_static path_beg /static/ /images/ /css/ /js/
acl is_api path_beg /api/
acl is_uploads path_beg /uploads/
use_backend static_servers if is_static
use_backend api_servers if is_api
use_backend upload_servers if is_uploads
default_backend main_servers
backend static_servers
balance roundrobin
server static1 10.0.0.1:80 check
server static2 10.0.0.2:80 check
backend api_servers
balance leastconn
server api1 10.0.0.3:8080 check
server api2 10.0.0.4:8080 check
backend upload_servers
balance roundrobin
server upload1 10.0.0.5:80 check maxconn 100
backend main_servers
server main1 10.0.0.6:80 check
server main2 10.0.0.7:80 check
Method-Based Routing with Logical Operators
frontend api_frontend
bind *:443 ssl crt /etc/haproxy/certs/api.pem
acl is_post method POST
acl is_put method PUT
acl is_delete method DELETE
acl is_write_method is_post or is_put or is_delete
acl is_get method GET
acl is_head method HEAD
use_backend write_servers if is_write_method
use_backend read_servers if is_get or is_head
default_backend read_servers
backend write_servers
balance leastconn
server write1 10.0.0.1:8080 check
server write2 10.0.0.2:8080 check
backend read_servers
balance roundrobin
server read1 10.0.0.3:8080 check
server read2 10.0.0.4:8080 check
server read3 10.0.0.5:8080 check
Header-Based and Query Parameter Routing
frontend mobile_frontend
bind *:80
# Route mobile users to a mobile-specific backend
acl is_mobile_user hdr_sub(User-Agent) -i Mobile Android iPhone
acl is_api_version_v2 hdr(X-API-Version) 2
acl has_debug_param urlp(debug) -m reg ^(1|true|yes)$
use_backend mobile_servers if is_mobile_user
use_backend api_v2_servers if is_api_version_v2
use_backend debug_servers if has_debug_param
default_backend main_servers
Combining Multiple ACLs for Complex Conditions
frontend advanced_frontend
bind *:443 ssl crt /etc/haproxy/certs/site.pem
acl is_admin_path path_beg /admin
acl is_internal_ip src 10.0.0.0/8 172.16.0.0/12 192.168.0.0/16
acl is_authorized hdr_sub(Cookie) -i session_token=valid
acl exceeds_rate_limit src_http_req_rate(admin_zone) ge 10
# Block admin access from external IPs
http-request deny if is_admin_path !is_internal_ip
# Block if rate limit exceeded and not authorized
http-request deny if exceeds_rate_limit !is_authorized
# Route admin traffic with sticky sessions
use_backend admin_servers if is_admin_path is_internal_ip
default_backend public_servers
SSL/TLS Termination
SSL termination at the load balancer offloads the CPU-intensive TLS encryption/decryption work from backend servers, allowing them to focus on application logic. HAProxy provides comprehensive SSL/TLS support.
Basic SSL Termination
frontend https_frontend
bind *:443 ssl crt /etc/haproxy/certs/mysite.pem
default_backend web_servers
backend web_servers
server web1 10.0.0.1:80 check
server web2 10.0.0.2:80 check
SSL Termination with Multiple Certificates (SNI)
frontend https_frontend
bind *:443 ssl crt-list /etc/haproxy/cert-list.txt
# Use SNI to select the correct certificate
acl sni_app req.ssl_sni -i app.example.com
acl sni_api req.ssl_sni -i api.example.com
use_backend app_servers if sni_app
use_backend api_servers if sni_api
default_backend fallback_servers
The cert-list.txt file format:
# /etc/haproxy/cert-list.txt
/etc/haproxy/certs/app.example.com.pem
/etc/haproxy/certs/api.example.com.pem
/etc/haproxy/certs/fallback.pem [*]
SSL Pass-Through (No Termination)
When you need end-to-end encryption without decrypting traffic at the load balancer, use TCP mode with SSL pass-through:
frontend tcp_frontend
bind *:443
mode tcp
option tcplog
# Use SNI extension to route without decrypting
tcp-request inspect-delay 5s
tcp-request content accept if { req.ssl_hello_type 1 }
acl sni_app req.ssl_sni -i app.example.com
acl sni_api req.ssl_sni -i api.example.com
use_backend app_tcp_servers if sni_app
use_backend api_tcp_servers if sni_api
default_backend fallback_tcp_servers
backend app_tcp_servers
mode tcp
server app1 10.0.0.1:443 check port 443
server app2 10.0.0.2:443 check port 443
backend api_tcp_servers
mode tcp
server api1 10.0.0.3:443 check port 443
SSL Re-Encryption (Backend SSL)
For maximum security, you can terminate SSL at HAProxy and then re-encrypt traffic to backend servers:
frontend https_frontend
bind *:443 ssl crt /etc/haproxy/certs/frontend.pem
default_backend secure_servers
backend secure_servers
balance roundrobin
server web1 10.0.0.1:443 ssl verify required ca-file /etc/haproxy/certs/ca.pem check
server web2 10.0.0.2:443 ssl verify required ca-file /etc/haproxy/certs/ca.pem check
Health Checks
HAProxy provides robust health checking mechanisms to ensure traffic is only sent to healthy backend servers. There are two types of health checks: active and passive.
Active Health Checks
Active health checks are periodic probes initiated by HAProxy to test backend server health. The most common configuration uses HTTP health checks:
backend web_servers
balance roundrobin
option httpchk GET /health HTTP/1.1\r\nHost:\ www.example.com
http-check expect status 200
server web1 10.0.0.1:80 check inter 3s rise 2 fall 3
server web2 10.0.0.2:80 check inter 3s rise 2 fall 3
TCP Health Checks
backend database_servers
mode tcp
option tcp-check
server db1 10.0.0.1:3306 check port 3306 inter 5s rise 1 fall 2
server db2 10.0.0.2:3306 check port 3306 inter 5s rise 1 fall 2
Custom Scripted Health Checks (External Checks)
backend custom_servers
option external-check
external-check command /usr/local/bin/health_check.sh
server app1 10.0.0.1:8080 check inter 10s
Example external health check script:
#!/bin/bash
# /usr/local/bin/health_check.sh
# Exit 0 for healthy, non-zero for unhealthy
HOST=${HAPROXY_SERVER_ADDR}
PORT=${HAPROXY_SERVER_PORT}
curl -s --max-time 3 "http://${HOST}:${PORT}/health" | grep -q "OK"
exit $?
Passive Health Checks (In-Line Observation)
Passive checks observe live traffic responses. HAProxy marks servers as DOWN based on the number of consecutive failed responses:
backend web_servers
option redispatch
default-server check inter 3s rise 2 fall 3 on-error mark-down observe layer7 error-limit 10
server web1 10.0.0.1:80
server web2 10.0.0.2:80
Session Persistence (Sticky Sessions)
Session persistence ensures that a client is consistently routed to the same backend server throughout a session. This is essential for applications that store session state locally on servers.
Cookie-Based Persistence
backend sticky_servers
balance roundrobin
cookie SERVERID insert indirect nocache
server web1 10.0.0.1:80 cookie web1 check
server web2 10.0.0.2:80 cookie web2 check
server web3 10.0.0.3:80 cookie web3 check
This configuration inserts a cookie named SERVERID with the value web1, web2, or web3 depending on which server handles the first request. Subsequent requests from the same client will be routed to the same server based on this cookie.
Source IP Affinity with Stick Tables
backend sticky_source
balance roundrobin
stick-table type ip size 200k expire 30m peers cluster1
stick on src
server web1 10.0.0.1:80 check
server web2 10.0.0.2:80 check
Stick tables provide a more sophisticated approach to persistence, storing client-to-server mappings in an in-memory table that can be synchronized across multiple HAProxy instances using the peers protocol.
Rate Limiting and DDoS Protection
HAProxy can enforce rate limits to protect backend servers from excessive traffic or abusive clients:
frontend protected_frontend
bind *:80
# Create stick table for tracking request rates
stick-table type ip size 200k expire 10m store http_req_rate(10s)
# Track client request rate
tcp-request connection track-sc0 src
# Block if more than 100 requests in 10 seconds
acl rate_abuse sc0_http_req_rate gt 100
http-request deny if rate_abuse
# Additional rate limiting per path
acl is_api path_beg /api/
acl api_rate_high sc0_http_req_rate gt 50
http-request deny if is_api api_rate_high
default_backend web_servers
Connection Limits
frontend connection_limited
bind *:80
# Limit concurrent connections per source IP
stick-table type ip size 100k expire 30s store conn_cur
tcp-request connection track-sc0 src
tcp-request connection reject if { sc0_conn_cur ge 50 }
default_backend web_servers
Logging and Monitoring
Proper logging is essential for troubleshooting and monitoring HAProxy's behavior. HAProxy can log to syslog facilities and provide detailed request information.
Configuring Syslog
global
log 127.0.0.1:514 local0
log 127.0.0.1:514 local1 notice
defaults
log global
option httplog
option log-separate-error
option dontlognull
option forwardfor
# For rsyslog, add to /etc/rsyslog.d/49-haproxy.conf:
# $AddMsgSyslogFacility local0
# $AddMsgSyslogFacility local1
# local0.* /var/log/haproxy/haproxy.log
# local1.* /var/log/haproxy/haproxy-err.log
Custom Log Formats
defaults
log global
# Custom log format with detailed timing information
log-format "%ci:%cp [%tr] %ft %b/%s %TR/%Tw/%Tc/%Tr/%Ta %ST %B %CC %CS %tsc %ac/%fc/%bc/%sc/%rc %sq/%bq %hr %hs %{+Q}r"
HAProxy Statistics Page (Stats Socket)
The HAProxy Stats page provides a real-time web interface for monitoring and managing HAProxy:
listen stats
bind *:8404
mode http
stats enable
stats uri /stats
stats realm HAProxy\ Statistics
stats auth admin:secure_password
stats refresh 10s
stats admin if TRUE
# Additional metrics endpoints
stats uri /metrics
stats show-legends
stats show-desc
You can also interact with HAProxy via the Unix socket for runtime management:
# Query server states
echo "show stat" | socat /run/haproxy/admin.sock stdio
# Disable a server gracefully
echo "disable server web_servers/web1" | socat /run/haproxy/admin.sock stdio
# Enable a server
echo "enable server web_servers/web1" | socat /run/haproxy/admin.sock stdio
# Set a server to drain mode (complete existing connections, no new ones)
echo "set server web_servers/web1 state drain" | socat /run/haproxy/admin.sock stdio
Graceful Reloads and Zero-Downtime Configuration Changes
One of HAProxy's strengths is the ability to reload configuration without dropping active connections:
# Test configuration syntax before applying
haproxy -c -f /etc/haproxy/haproxy.cfg
# Perform a graceful reload
sudo systemctl reload haproxy
# Or use the traditional method
haproxy -f /etc/haproxy/haproxy.cfg -p /run/haproxy.pid -sf $(cat /run/haproxy.pid)
For truly zero-downtime reloads in high-traffic environments, you can use the expose-fd feature available in newer versions:
global
expose-fd listeners
stats socket /run/haproxy/admin.sock mode 660 level admin expose-fd listeners
Complete Production-Ready Configuration Example
Below is a comprehensive, production-ready HAProxy configuration that incorporates many of the concepts covered in this guide. This example demonstrates a multi-service setup with SSL termination, host-based routing, rate limiting, health checks, and statistics:
# /etc/haproxy/haproxy.cfg
global
log /dev/log local0
log /dev/log local1 notice
chroot /var/lib/haproxy
stats socket /run/haproxy/admin.sock mode 660 level admin
stats timeout 30s
user haproxy
group haproxy
daemon
# SSL performance
tune.ssl.default-dh-param 2048
ssl-default-bind-ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384
ssl-default-bind-options no-sslv3 no-tlsv10 no-tlsv11
ssl-default-server-curves X25519:P-256
# Performance
maxconn 50000
nbthread auto
defaults
log global
mode http
option httplog
option dontlognull
option forwardfor
option http-server-close
timeout connect 5000
timeout client 50000
timeout server 50000
errorfile 400 /etc/haproxy/errors/400.http
errorfile 403 /etc/haproxy/errors/403.http
errorfile 408 /etc/haproxy/errors/408.http
errorfile 500 /etc/haproxy/errors/500.http
errorfile 502 /etc/haproxy/errors/502.http
errorfile 503 /etc/haproxy/errors/503.http
errorfile 504 /etc/haproxy/errors/504.http
# Main HTTPS frontend
frontend https_main
bind *:80
bind *:443 ssl crt-list /etc/haproxy/cert-list.txt alpn h2,http/1.1
# Redirect HTTP to HTTPS
http-request redirect scheme https code 301 if !{ ssl_fc }
# Rate limiting stick table
stick-table type ip size 200k expire 10m store http_req_rate(10s)
tcp-request connection track-sc0 src
# Global rate limit: 200 requests per 10 seconds
http-request deny if { sc0_http_req_rate gt 200 }
# Security headers
http-response set-header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"
http-response set-header X-Content-Type-Options "nosniff"
http-response set-header X-Frame-Options "DENY"
# Host-based ACLs
acl host_www hdr(host) -i www.example.com
acl host_api hdr(host) -i api.example.com
acl host_static hdr(host) -i static.example.com
# Path-based ACLs for main site
acl path_admin path_beg /admin
acl path_assets path_beg /assets/ /static/ /uploads/
# Internal IP check for admin
acl internal_network src 10.0.0.0/8
# Route traffic
use_backend admin_servers if host_www path_admin internal_network
http-request deny if host_www path_admin !internal_network
use_backend asset_servers if host_www path_assets
use_backend api_servers if host_api
use_backend static_servers if host_static
default_backend main_servers
# Backend for main web servers
backend main_servers
balance roundrobin
option httpchk GET /health HTTP/1.1\r\nHost:\ www.example.com
http-check expect status 200
cookie SERVERID insert indirect nocache secure
server web1 10.0.0.10:80 cookie web1 check inter 3s rise 2 fall 3 maxconn 500
server web2 10.0.0.11:80 cookie web2 check inter 3s rise 2 fall 3 maxconn 500
server web3 10.0.0.12:80 cookie web3 check inter 3s rise 2 fall 3 maxconn 500
# Backend for admin servers (internal only)
backend admin_servers
balance source
option httpchk GET /health
stick-table type ip size 100k expire 30m stick on src
server admin1 10.0.0.20:8080 check inter 3s rise 2 fall 3
server admin2 10.0.0.21:8080 check inter 3s rise 2 fall 3
# Backend for API servers
backend api_servers
balance leastconn
option httpchk GET /api/health
http-check expect status 200
server api1 10.0.0.30:8080 check inter 3s rise 2 fall 3 maxconn 200
server api2 10.0.0.31:8080 check inter 3s rise 2 fall 3