High-performance TCP/HTTP load balancer and reverse proxy for distributing traffic across backend servers.
Addresses below are RFC 5737 documentation ranges or placeholders - swap in your own.
Table of Contents#
- Overview
- Installation and Setup
- Configuration Structure
- HTTP Configuration
- SSL/TLS Termination
- ACLs and Routing Rules
- Rate Limiting
- Health Checks
- Stats and Monitoring
- Database Load Balancing Examples
- Performance Tuning
- Troubleshooting
- See Also
- Sources
1. Overview#
HAProxy (High Availability Proxy) is an open-source load balancer and reverse proxy for TCP and HTTP applications. It handles tens to hundreds of thousands of concurrent connections with minimal resource consumption. HAProxy operates in either TCP (Layer 4) or HTTP (Layer 7) mode, providing flexible traffic distribution, health checking, SSL termination, and detailed statistics. It is the de facto standard for database cluster load balancing (Patroni, Galera) and high-traffic web applications.
Key capabilities:
- Layer 4 (TCP) and Layer 7 (HTTP) load balancing
- SSL/TLS termination and passthrough
- Content-based routing with ACLs
- Stick tables for rate limiting and session persistence
- HTTP/2 and HTTP/3 (QUIC) support (3.0+)
- Built-in stats dashboard and socket API
2. Installation and Setup#
2.1 Package Installation#
RHEL/CentOS/Fedora:
dnf install -y haproxyDebian/Ubuntu:
apt install -y haproxyArch Linux:
pacman -S haproxy2.2 Enable and Start#
systemctl enable --now haproxy2.3 SELinux Configuration (RHEL-based)#
When running on SELinux-enforcing systems, set the required booleans:
setsebool -P httpd_can_network_connect_db 1
setsebool -P httpd_can_network_connect 1
setsebool -P haproxy_connect_any 1
setsebool -P nis_enabled 12.4 Enable Multi-File Configuration#
Split configuration into multiple files for maintainability:
mkdir -p /etc/haproxy/haproxy.d
sed -i 's/OPTIONS=""/OPTIONS="-f \/etc\/haproxy\/haproxy.d"/' /etc/sysconfig/haproxyOn Debian-based systems, edit /etc/default/haproxy instead:
mkdir -p /etc/haproxy/conf.d
echo 'EXTRAOPTS="-f /etc/haproxy/conf.d"' >> /etc/default/haproxy2.5 Validate Configuration#
Always validate before reloading:
haproxy -c -f /etc/haproxy/haproxy.cfg
systemctl reload haproxy3. Configuration Structure#
HAProxy configuration is divided into four major sections: global, defaults, frontend, and backend. An optional listen section combines frontend and backend into one block.
3.1 Global Section#
Process-wide settings such as logging, resource limits, and security:
global
log 127.0.0.1 local2
chroot /var/lib/haproxy
pidfile /var/run/haproxy.pid
maxconn 8192
user haproxy
group haproxy
daemon
# Performance
nbthread 4
cpu-map auto:1/1-4 0-3
# Stats socket for runtime API
stats socket /var/run/haproxy.sock mode 600 level admin
stats timeout 30s3.2 Defaults Section#
Default values inherited by all frontend and backend sections:
defaults
mode http
log global
option httplog
option dontlognull
option http-server-close
option forwardfor except 127.0.0.0/8
option redispatch
retries 3
timeout http-request 10s
timeout connect 10s
timeout client 1m
timeout server 1m
timeout http-keep-alive 10s
timeout check 10s
maxconn 3000Key timeout parameters:
| Timeout | Purpose | Recommended |
|---|---|---|
http-request | Time to receive complete HTTP request | 5-10s |
connect | Time to establish connection to backend | 5-10s |
client | Inactivity timeout on client side | 30s-5m |
server | Inactivity timeout on server side | 30s-5m |
http-keep-alive | Idle time for keep-alive connections | 10s |
check | Health check timeout | 5-10s |
queue | Time a request can wait in queue | 30s-1m |
4. HTTP Configuration#
4.1 Basic HTTP Frontend and Backend#
frontend http_front
bind *:80
default_backend http_back
backend http_back
balance roundrobin
option httpchk GET /health
http-check expect status 200
server web1 192.0.2.11:8080 check
server web2 192.0.2.12:8080 check
server web3 192.0.2.13:8080 check backup4.2 Listen Block (Combined Frontend/Backend)#
listen webapp
bind *:80
balance leastconn
option httpchk GET /health
server web1 192.0.2.11:8080 check weight 3
server web2 192.0.2.12:8080 check weight 2
server web3 192.0.2.13:8080 check weight 14.3 HTTP Headers and Forwarding#
frontend http_front
bind *:80
# Add headers for backend awareness
http-request set-header X-Forwarded-Proto http
http-request set-header X-Real-IP %[src]
# Remove server-identifying headers
http-response del-header Server
http-response del-header X-Powered-By
default_backend http_back4.4 Load Balancing Algorithms#
# Round Robin (default) - equal distribution
balance roundrobin
# Least Connections - fewest active connections
balance leastconn
# Source IP Hash - session persistence by client IP
balance source
# URI Hash - same URI goes to same server (caching)
balance uri
# First available server with capacity
balance first
# Random with weight
balance random4.5 HTTP/2 Support#
frontend https_front
bind *:443 ssl crt /etc/haproxy/certs/ alpn h2,http/1.1
default_backend http_back5. SSL/TLS Termination#
5.1 Basic SSL Termination#
HAProxy terminates TLS and forwards plaintext HTTP to backends:
frontend https_front
bind *:443 ssl crt /etc/haproxy/certs/example.com.pem
bind *:80
http-request redirect scheme https unless { ssl_fc }
default_backend http_back
backend http_back
server web1 192.0.2.11:8080 checkThe PEM file must contain the certificate, private key, and any intermediate certificates concatenated:
cat cert.pem intermediate.pem privkey.pem > /etc/haproxy/certs/example.com.pem5.2 SSL Hardening#
global
ssl-default-bind-ciphersuites TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256
ssl-default-bind-options ssl-min-ver TLSv1.2 no-tls-tickets
tune.ssl.default-dh-param 20485.3 SSL Passthrough#
Forward encrypted traffic to backends without terminating TLS:
frontend ssl_passthrough
bind *:443
mode tcp
option tcplog
tcp-request inspect-delay 5s
tcp-request content accept if { req_ssl_hello_type 1 }
use_backend app1_back if { req_ssl_sni -i app1.example.com }
use_backend app2_back if { req_ssl_sni -i app2.example.com }
backend app1_back
mode tcp
server app1 192.0.2.11:443 check5.4 Backend SSL (Re-encryption)#
backend secure_back
server web1 192.0.2.11:443 ssl verify required ca-file /etc/haproxy/ca.pem check6. ACLs and Routing Rules#
ACLs (Access Control Lists) match conditions in requests for content-based routing.
6.1 ACL Syntax#
acl <name> <criterion> [flags] <value>6.2 Host-Based Routing#
frontend http_front
bind *:80
acl is_app1 hdr(host) -i app1.example.com
acl is_app2 hdr(host) -i app2.example.com
acl is_api hdr(host) -i api.example.com
use_backend app1_back if is_app1
use_backend app2_back if is_app2
use_backend api_back if is_api
default_backend fallback_back6.3 Path-Based Routing#
frontend http_front
bind *:80
acl is_api path_beg /api/
acl is_static path_end .css .js .png .jpg .gif .ico
acl is_ws path_beg /ws/
use_backend api_back if is_api
use_backend static_back if is_static
use_backend ws_back if is_ws
default_backend app_back6.4 IP-Based Access Control#
frontend http_front
bind *:80
acl allowed_ips src 192.0.2.0/24 198.51.100.0/24
acl is_admin path_beg /admin
http-request deny if is_admin !allowed_ips
default_backend app_back6.5 Method-Based Routing#
acl is_get method GET
acl is_post method POST
acl is_options method OPTIONS
# CORS preflight
http-request return status 204 if is_options7. Rate Limiting#
HAProxy uses stick tables to track client behavior and enforce rate limits.
7.1 Connection Rate Limiting#
frontend http_front
bind *:80
# Track requests per IP over 10 seconds
stick-table type ip size 100k expire 30s store http_req_rate(10s)
http-request track-sc0 src
# Deny if more than 100 requests in 10 seconds
acl rate_limited sc_http_req_rate(0) gt 100
http-request deny deny_status 429 if rate_limited
default_backend app_back7.2 Concurrent Connection Limiting#
frontend http_front
bind *:80
stick-table type ip size 100k expire 30s store conn_cur
http-request track-sc0 src
# Deny if more than 50 concurrent connections per IP
acl too_many_conns sc_conn_cur(0) gt 50
http-request deny deny_status 429 if too_many_conns
default_backend app_back7.3 Tarpit Abusive Clients#
Slow down abusive clients instead of rejecting immediately:
acl rate_abusive sc_http_req_rate(0) gt 200
http-request tarpit if rate_abusive
timeout tarpit 5s8. Health Checks#
8.1 HTTP Health Check#
backend app_back
option httpchk GET /health
http-check expect status 200
default-server inter 3s fall 3 rise 2 on-marked-down shutdown-sessions
server web1 192.0.2.11:8080 maxconn 100 check
server web2 192.0.2.12:8080 maxconn 100 check8.2 TCP Health Check#
backend tcp_back
mode tcp
option tcp-check
tcp-check connect
tcp-check send PING\r\n
tcp-check expect string +PONG
server redis1 192.0.2.11:6379 check8.3 Health Check Parameters#
| Parameter | Purpose |
|---|---|
inter <time> | Interval between checks (default 2s) |
fall <count> | Consecutive failures before marking down |
rise <count> | Consecutive successes before marking up |
on-marked-down shutdown-sessions | Kill active sessions when server goes down |
slowstart <time> | Gradually increase traffic to recovered server |
9. Stats and Monitoring#
9.1 Stats Web Dashboard#
listen stats
bind *:8404
mode http
stats enable
stats uri /stats
stats refresh 10s
stats show-legends
stats auth admin:<password>
stats admin if TRUEAccess at http://<haproxy-ip>:8404/stats.
9.2 Stats Socket (Runtime API)#
Configure in the global section:
global
stats socket /var/run/haproxy.sock mode 600 level admin
stats timeout 30sCommon runtime commands:
# Show server status
echo "show stat" | socat stdio /var/run/haproxy.sock
# Disable a backend server
echo "disable server app_back/web1" | socat stdio /var/run/haproxy.sock
# Enable a backend server
echo "enable server app_back/web1" | socat stdio /var/run/haproxy.sock
# Show session info
echo "show sess" | socat stdio /var/run/haproxy.sock
# Show current connections
echo "show info" | socat stdio /var/run/haproxy.sock
# Set server weight dynamically
echo "set weight app_back/web1 50%" | socat stdio /var/run/haproxy.sock9.3 Prometheus Integration#
frontend prometheus
bind *:8405
mode http
http-request use-service prometheus-exporter if { path /metrics }
no log10. Database Load Balancing Examples#
10.1 Patroni (PostgreSQL HA)#
Route traffic to the Patroni leader using HTTP health checks against the Patroni REST API:
frontend patroni0_frontend
bind *:5432
mode tcp
maxconn 100
timeout client 3600s
default_backend patroni0_backend
backend patroni0_backend
mode tcp
option httpchk GET /primary
timeout check 5s
timeout connect 2s
timeout server 3600s
http-check expect status 200
default-server inter 3s fall 3 rise 2 on-marked-down shutdown-sessions
server node01 192.0.2.111:6432 maxconn 100 check port 8008
server node02 192.0.2.112:6432 maxconn 100 check port 8008
# Read replicas (optional)
frontend patroni0_ro_frontend
bind *:5433
mode tcp
maxconn 200
timeout client 3600s
default_backend patroni0_ro_backend
backend patroni0_ro_backend
mode tcp
option httpchk GET /replica
timeout check 5s
timeout connect 2s
timeout server 3600s
http-check expect status 200
balance roundrobin
default-server inter 3s fall 3 rise 2 on-marked-down shutdown-sessions
server node01 192.0.2.111:6432 maxconn 100 check port 8008
server node02 192.0.2.112:6432 maxconn 100 check port 800810.2 Galera (MySQL/MariaDB HA)#
frontend galera_frontend
bind *:3306
mode tcp
default_backend galera_backend
backend galera_backend
mode tcp
balance roundrobin
option mysql-check user haproxy
server node01 192.0.2.111:3306 check weight 1
server node02 192.0.2.112:3306 check weight 1
server node03 192.0.2.113:3306 check weight 1 backup11. Performance Tuning#
11.1 Global Tuning#
global
maxconn 50000
nbthread 4
cpu-map auto:1/1-4 0-3
tune.bufsize 32768
tune.http.maxhdr 128
tune.ssl.default-dh-param 2048
tune.ssl.cachesize 100000
tune.ssl.lifetime 300
tune.comp.maxlevel 511.2 System-Level Tuning#
Increase system limits for high-connection environments:
# /etc/security/limits.d/haproxy.conf
haproxy soft nofile 100000
haproxy hard nofile 100000# /etc/sysctl.d/haproxy.conf
net.ipv4.tcp_max_syn_backlog = 65535
net.core.somaxconn = 65535
net.ipv4.ip_local_port_range = 1024 65535
net.ipv4.tcp_tw_reuse = 111.3 Connection Reuse#
defaults
option http-keep-alive
http-reuse safe11.4 Compression#
defaults
compression algo gzip
compression type text/html text/plain text/css application/javascript application/json12. Troubleshooting#
| Issue | Cause | Solution |
|---|---|---|
Starting proxy: cannot bind socket | Port already in use or insufficient permissions | Check with ss -tlnp; ensure HAProxy user can bind to the port |
Server marked DOWN | Backend health check failing | Verify backend is reachable; check health check endpoint and port |
503 Service Unavailable | All backend servers are down | Check backend health; review show stat via stats socket |
408 Request Timeout | Client did not send complete request in time | Increase timeout http-request |
SELinux avc: denied | SELinux blocking HAProxy connections | Set haproxy_connect_any boolean; check audit2allow |
| High memory usage | Too many stick table entries or large buffers | Reduce stick-table size; lower tune.bufsize |
| SSL handshake failures | Mismatched ciphers or expired certificates | Verify PEM file order; check ssl-default-bind-options |
Connection refused to stats | Stats listener not configured or wrong port | Verify listen stats block and bind address |
| Configuration not loading | Syntax error in config file | Run haproxy -c -f /etc/haproxy/haproxy.cfg to validate |