HAProxy Overview
HAProxy is an open-source high-performance reverse proxy and load balancer that supports active-passive failover, virtual hosting, and application-layer proxying for TCP and HTTP protocols. Its configuration is straightforward, maintenance is simple, and it includes robust health-checking capabilities. When a backend server fails, HAProxy automatically removes it from the pool; once recovered, the server is seamlessly reintegrated.
HAProxy excels in high-traffic scenarios requiring session persistence or layer 7 application proxying. Running on standard hardware, it can handle tens of thousands of concurrent connections without extensive optimization. Its proxy mode keeps backend servers hidden from external networks, eliminating the need for public IPs on backend nodes.
HAProxy operates at both layer 4 and layer 7, similar to how LVS works at layer 4 and Nginx at layer 7. Configuration involves defining backend servers in a configuration file, then distributing traffic using various algorithms.
Key Advantages:
- Virtual host support across layers 4 and 7
- Session persistence and cookie-based routing
- URL-based backend health checking
- Superior concurrent connection handling compared to Nginx
- MySQL read load balancing with multiple algorithm support
Architecture Topology
Layer 4 TCP Proxy Configuration
HAProxy's layer 4 TCP proxy is straightforward and requires no scripts on the real servers, making it easier to configure than LVS or Nginx. Note that NAT mode routes all traffic through HAProxy, so performance under extremely high load may be lower than LVS. For small to medium deployments, HAProxy is recommended over LVS or Nginx.
Layer 7 Load Balancing
HAProxy's strength lies in its layer 7 URL-based request filtering capabilities. It's commonly deployed behind LVS or hardware load balancers like F5.
Host Planning
| Host | Interface | IP | Purpose |
|---|---|---|---|
| MASTER | eth0 | 192.168.1.81 | External management, WAN forwarding |
| MASTER | eth1 | 192.168.2.81 | Internal management, LAN forwarding |
| MASTER | eth2 | 192.168.3.81 | Heartbeat connection (optional) |
| MASTER | vip | 192.168.1.181 | Application A service |
| BACKUP | eth0 | 192.168.1.82 | External management |
| BACKUP | eth1 | 192.168.2.82 | Internal management |
| BACKUP | eth2 | 192.168.3.82 | Heartbeat connection (optional) |
| BACKUP | vip | 192.168.1.182 | Application B service |
Load Balancing Algorithms
HAProxy provides eight balancing algorithms:
- roundrobin - Dynamic weighted round-robin with weight support
- static-rr - Static round-robin without weight support
- leastconn - Least connections first (recommended)
- source - Source IP hashing
- uri - URI-based hashing
- url_param - URL parameter-based hashing
- hdr(name) - HTTP header-based request distribution
- rdp-cookie(name) - Cookie-based TCP request hashing
Installation
Dependencies:
yum install gcc gcc-c++ -y
Enable IP Forwarding:
vim /etc/sysctl.conf
net.ipv4.ip_forward = 1
net.ipv4.ip_nonlocal_bind = 1
sysctl -p
Compile from Source:
tar xf haproxy-2.4.tar.gz && cd haproxy-2.4
make TARGET=linux-glibc PREFIX=/opt/haproxy
make install PREFIX=/opt/haproxy
Note: The TARGET parameter should match your kernel version. Refer to the README file in the source directory for specific target options.
Directory Structure and Configuration
Create Directories:
cd /opt/haproxy/
mkdir -p bin conf logs var/run var/chroot
Configure Rsyslog:
vim /etc/rsyslog.conf
$ModLoad imudp
$UDPServerRun 514
local0.* /var/log/haproxy.log
Restart rsyslog:
/etc/init.d/rsyslog restart
Configuration File Structure
Global Section
global
log 127.0.0.1 local0
log 127.0.0.1 local1 notice
maxconn 4096
user haproxy
group haproxy
daemon
pidfile /opt/haproxy/conf/haproxy.pid
spread-checks 3
nbproc 4
ulimit-n 819200
chroot /opt/haproxy/var/chroot
stats socket /var/lib/haproxy/haproxy.sock mode 600 level admin
stats timeout 2m
Parameters explained:
- daemon: Run in background
- nbproc: Number of worker processes (match CPU cores)
- pidfile: Process ID file location
- ulimit-n: File descriptor limit
- chroot: Security jail directory
- stats socket: Enable runtime management via socket
Defaults Section
defaults
log global
mode http
option httplog
option dontlognull
option forwardfor
option httpclose
retries 3
maxconn 4096
timeout connect 5000
timeout client 30000
timeout server 30000
balance roundrobin
Key options:
- mode: http (layer 7), tcp (layer 4), or health
- forwardfor: Inject client IP into X-Forwarded-For header
- htttpclose: Close connections after each request
- retries: Failed connection attempts before marking server down
Listen Section for Statistics
listen monitoring
bind 0.0.0.0:1080
mode http
option httplog
option forwardfor
maxconn 10
stats enable
stats refresh 30s
stats uri /admin?stats
stats realm Production\ HAProxy
stats auth admin:strongpass123
stats hide-version
stats admin if TRUE
server web01 192.168.1.101:80 check port 80 inter 2000 fall 3
server web02 192.168.1.102:80 check port 80 inter 2000 fall 3
Access the statistics page at: http://IP:1080/admin?stats
Frontend Configuration
frontend web_cluster
bind *:80
acl is_static path_beg /images /css /js
acl is_api path_beg /api
use_backend static_pool if is_static
use_backend api_pool if is_api
default_backend dynamic_pool
Backend Configuration
backend dynamic_pool
mode http
balance roundrobin
option httpchk GET /health.html HTTP/1.0
option httpclose
option forwardfor
server app01 10.0.1.11:8080 weight 5 check inter 2000 rise 2 fall 3
server app02 10.0.1.12:8080 weight 3 check inter 2000 rise 2 fall 3
server app03 10.0.1.13:8080 backup
backend static_pool
mode http
balance leastconn
option httpchk GET /health.html
server static01 10.0.2.11:80 check inter 2000 fall 3
server static02 10.0.2.12:80 check inter 2000 fall 3
backend api_pool
mode http
balance source
server api01 10.0.3.11:8000 check inter 1500 fall 2
server api02 10.0.3.12:8000 check inter 1500 fall 2
Backend server parameters:
- check: Enable health monitoring
- inter: Check interval in milliseconds
- fall: Failed checks before marking down
- rise: Successful checks before marking up
- weight: Traffic weight relative to other servers
- backup: Activate only when all primary servers fail
Health Checking Options
# Basic HTTP check
option httpchk /index.html
# Check with specific method
option httpchk GET /api/health HTTP/1.1\r\nHost:\ example.com
# TCP check (default port)
option httpchk
Recommendation: Coordinate with developers on which URI to use for health checks, as this provides accountability when issues arise.
SSL/TLS Configuration
global
maxsslconn 2048
tune.ssl.default-dh-param 2048
frontend https_in
bind *:443 ssl crt /etc/ssl/certs/web.pem
mode http
default_backend web_pool
Generate a self-signed certificate:
make certbot CERTDIR=/etc/pki/tls/certs
TCP Proxy Configuration
listen mysql_proxy
bind 0.0.0.0:3306
mode tcp
option tcplog
maxconn 4086
server db01 10.0.10.11:3306 weight 1 check port 3306
server db02 10.0.10.12:3306 weight 1 check port 3306 backup
ACL Rules
Syntax:
acl <name> <criterion> [flags] [operator] <value>
Domain-Based Routing
acl website_a hdr(host) -i www.example.com
acl website_b hdr(host) -i api.example.com
use_backend service_a if website_a
use_backend service_b if website_b
default_backend service_a
Path-Based Routing
acl img_paths path_beg /images /assets
acl api_paths path_beg /api/v1 /api/v2
use_backend image_servers if img_paths
use_backend api_servers if api_paths
Extension-Based Routing
acl static_files path_end .jpg .png .gif .css .js
use_backend cdn_servers if static_files
Client-Based Routing
acl mobile_client hdr_sub(user-agent) -i iphone android
redirect prefix http://m.example.com if mobile_client
IP-Based Filtering
acl allowed_ips src 10.0.0.0/8 172.16.0.0/12
acl blocked_hosts hdr(host) -i evil.com
http-request allow if allowed_ips
http-request deny if blocked_hosts
301 Redirects
frontend old_site
bind *:80
acl legacy_domain hdr(host) -i oldsite.com
redirect prefix http://newsite.com code 301 if legacy_domain
Logging Client IP Addresses
HAProxy configuration:
option forwardfor
Nginx log format:
log_format forwarded '$http_x_forwarded_for - $remote_user [$time_local] '
'"$request" $status $body_bytes_sent '
'"$http_referer" "$http_user_agent"';
High Availability
Backup Server Configuration
Activate single backup when all primaries fail:
server primary01 10.0.1.11:80 check
server primary02 10.0.1.12:80 check
server failover01 10.0.1.21:80 backup
Activate all backups simultaneously:
option allbackups
server primary01 10.0.1.11:80 check
server primary02 10.0.1.12:80 check
server failover01 10.0.1.21:80 backup
server failover02 10.0.1.22:80 backup
Handling VIP Binding Issues
If HAProxy fails to bind to a virtual IP, enable non-local binding:
vim /etc/sysctl.conf
net.ipv4.ip_nonlocal_bind = 1
sysctl -p
Dynamic Management
Connect to HAProxy socket for runtime changes:
yum install socat -y
echo "help" | socat stdio /var/lib/haproxy/haproxy.sock
Useful commands:
# Disable a backend server
echo "disable server backend_name/server_name" | socat stdio /var/lib/haproxy/haproxy.sock
# Enable a backend server
echo "enable server backend_name/server_name" | socat stdio /var/lib/haproxy/haproxy.sock
# Show current stats
echo "show info" | socat stdio /var/lib/haproxy/haproxy.sock
Startup and Management
Check configuration:
/opt/haproxy/sbin/haproxy -f /opt/haproxy/conf/haproxy.cfg -c
Start HAProxy:
/opt/haproxy/sbin/haproxy -f /opt/haproxy/conf/haproxy.cfg -D
Graceful restart:
/opt/haproxy/sbin/haproxy -f /opt/haproxy/conf/haproxy.cfg -sf $(cat /opt/haproxy/conf/haproxy.pid)
Stop:
kill $(cat /opt/haproxy/conf/haproxy.pid)
Integration with Keepalived
Keepalived configuraton for MASTER:
vrrp_instance VI_1 {
state MASTER
interface eth0
virtual_router_id 51
priority 100
advert_int 1
virtual_ipaddress {
192.168.1.181
}
}
Keepalived configuration for BACKUP:
vrrp_instance VI_1 {
state BACKUP
interface eth0
virtual_router_id 51
priority 90
advert_int 1
virtual_ipaddress {
192.168.1.181
}
}
Layer 4 + Layer 7 Separation Architecture
For high-performance requirements, separate layer 4 and layer 7 load balancing:
- LVS handles layer 4 traffic distribution
- HAProxy handles layer 7 URL-based routing
This approach reduces resource consumption and allows horizontal scaling of HAProxy instances.
Troubleshooting
Compilation error during make install:
If you encounter missing documentation files error:
make TARGET=linux2628 PREFIX=/opt/haproxy
make install TARGET=linux2628 PREFIX=/opt/haproxy
Or edit the Makefile to skip documentation installation.
Warning about multi-process stats:
When nbproc > 1, statistics may be limited. To suppress this warning, set nbproc to 1 or modify the source code in src/cfgparse.c.