HAProxy: High Availability Load Balancing
Enterprise load balancing for homelabs. SSL termination, health checks, and failover.
HAProxy (High Availability Proxy) is a free, open-source software that provides high-performance load balancing and proxying for TCP and HTTP-based applications. It’s widely used in production environments and perfect for homelabs requiring advanced traffic management, high availability, and robust health checking.
What is HAProxy?
HAProxy is a TCP/HTTP reverse proxy and load balancer that sits between clients and servers, distributing incoming requests across multiple backend servers. It offers:
- Layer 4 (TCP) and Layer 7 (HTTP) load balancing
- Advanced health checking
- SSL/TLS termination and offloading
- Content switching and routing
- Session persistence (sticky sessions)
- Traffic shaping and rate limiting
- Real-time statistics and monitoring
- Zero-downtime configuration reloads
Load Balancing Topology
Traditional Single Server:
Clients → Web Server → Application
HAProxy Load Balanced:
┌→ Backend 1
Clients → HAProxy ├→ Backend 2
└→ Backend 3
Multi-Tier with HAProxy:
┌→ Web 1 ┐
Clients → HAProxy 1 ├→ Web 2 ├→ HAProxy 2 ┬→ App 1
└→ Web 3 ┘ └→ App 2 Why Use HAProxy in Your Homelab?
Benefits
- High Availability - Eliminate single points of failure
- Performance - Handle 100,000+ requests per second
- Flexibility - Support for HTTP, HTTPS, TCP, WebSocket
- Smart Health Checks - Automatic failover on backend failures
- SSL Termination - Centralized certificate management
- Zero Downtime - Reload configurations without dropping connections
- Advanced Routing - Route based on headers, paths, or custom rules
Use Cases
- Load balance multiple application instances
- SSL/TLS termination for backend services
- A/B testing and canary deployments
- Multi-datacenter failover
- WebSocket load balancing
- API gateway functionality
Installation
Docker Installation (Recommended)
Basic Docker Compose Setup
Create /opt/haproxy/docker-compose.yml:
version: '3.8'
services:
haproxy:
image: haproxy:2.9-alpine
container_name: haproxy
ports:
- "80:80"
- "443:443"
- "8404:8404" # Stats page
volumes:
- ./haproxy.cfg:/usr/local/etc/haproxy/haproxy.cfg:ro
- ./certs:/etc/ssl/certs:ro
- ./errors:/etc/haproxy/errors:ro
restart: unless-stopped
networks:
- frontend
- backend
sysctls:
- net.ipv4.ip_unprivileged_port_start=0
networks:
frontend:
driver: bridge
backend:
driver: bridge Advanced Setup with Keepalived
For high availability with VRRP:
version: '3.8'
services:
haproxy:
image: haproxy:2.9-alpine
container_name: haproxy
cap_add:
- NET_ADMIN
ports:
- "80:80"
- "443:443"
- "8404:8404"
volumes:
- ./haproxy.cfg:/usr/local/etc/haproxy/haproxy.cfg:ro
- ./certs:/etc/ssl/certs:ro
restart: unless-stopped
network_mode: host
keepalived:
image: osixia/keepalived:2.0.20
container_name: keepalived
cap_add:
- NET_ADMIN
- NET_BROADCAST
- NET_RAW
environment:
- KEEPALIVED_INTERFACE=eth0
- KEEPALIVED_VIRTUAL_IPS=192.168.1.100
- KEEPALIVED_UNICAST_PEERS=#PYTHON2BASH:['192.168.1.11', '192.168.1.12']
- KEEPALIVED_PRIORITY=100
volumes:
- ./keepalived.conf:/usr/local/etc/keepalived/keepalived.conf:ro
restart: unless-stopped
network_mode: host Native Installation
Ubuntu/Debian
sudo apt-get update
sudo apt-get install haproxy
# Enable HAProxy
sudo systemctl enable haproxy
sudo systemctl start haproxy RHEL/CentOS/Rocky Linux
sudo dnf install haproxy
sudo systemctl enable haproxy
sudo systemctl start haproxy Build from Source (Latest Version)
# Install dependencies
sudo apt-get install build-essential libssl-dev libpcre3-dev zlib1g-dev
# Download and compile
wget https://www.haproxy.org/download/2.9/src/haproxy-2.9.0.tar.gz
tar xzf haproxy-2.9.0.tar.gz
cd haproxy-2.9.0
make TARGET=linux-glibc USE_OPENSSL=1 USE_PCRE=1 USE_ZLIB=1 USE_SYSTEMD=1
sudo make install
# Create systemd service
sudo cp /opt/haproxy/haproxy-2.9.0/admin/systemd/haproxy.service.in /etc/systemd/system/haproxy.service
sudo systemctl daemon-reload
sudo systemctl enable haproxy Basic Configuration
Configuration File Structure
HAProxy configuration consists of four main sections:
global - Process-wide settings
defaults - Default settings for all sections
frontend - Client-facing configuration
backend - Server pool configuration
listen - Combined frontend + backend Simple Load Balancer Configuration
Create /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
# Default SSL material locations
ca-base /etc/ssl/certs
crt-base /etc/ssl/private
# Cryptographic settings
ssl-default-bind-ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256
ssl-default-bind-ciphersuites TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384
ssl-default-bind-options ssl-min-ver TLSv1.2 no-tls-tickets
defaults
log global
mode http
option httplog
option dontlognull
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
frontend http_front
bind *:80
default_backend http_back
backend http_back
balance roundrobin
server web1 192.168.1.10:80 check
server web2 192.168.1.11:80 check
server web3 192.168.1.12:80 check Testing Configuration
# Test configuration syntax
haproxy -c -f /etc/haproxy/haproxy.cfg
# Reload without downtime
sudo systemctl reload haproxy
# View status
sudo systemctl status haproxy Advanced Configurations
SSL/TLS Termination
Generate SSL Certificate
# Self-signed certificate for testing
openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout /etc/ssl/private/haproxy.key -out /etc/ssl/certs/haproxy.crt
# Combine for HAProxy
cat /etc/ssl/certs/haproxy.crt /etc/ssl/private/haproxy.key > /etc/ssl/private/haproxy.pem
chmod 600 /etc/ssl/private/haproxy.pem SSL Configuration
global
# SSL tuning
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 ssl-min-ver TLSv1.2 no-tls-tickets
frontend https_front
bind *:443 ssl crt /etc/ssl/private/haproxy.pem alpn h2,http/1.1
# HSTS header
http-response set-header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"
# Redirect HTTP to HTTPS
redirect scheme https code 301 if !{ ssl_fc }
default_backend https_back
backend https_back
balance roundrobin
option httpchk GET /health
http-check expect status 200
server web1 192.168.1.10:80 check ssl verify none
server web2 192.168.1.11:80 check ssl verify none
server web3 192.168.1.12:80 check ssl verify none Multiple Certificates (SNI)
frontend https_multi
bind *:443 ssl crt /etc/ssl/private/certs/ alpn h2,http/1.1
# Route based on SNI
use_backend app1_back if { ssl_fc_sni app1.example.com }
use_backend app2_back if { ssl_fc_sni app2.example.com }
use_backend app3_back if { ssl_fc_sni app3.example.com }
default_backend default_back
backend app1_back
server app1 192.168.1.20:80 check
backend app2_back
server app2 192.168.1.21:80 check
backend app3_back
server app3 192.168.1.22:80 check Content-Based Routing
frontend web_front
bind *:80
# ACLs for routing
acl is_api path_beg /api
acl is_static path_beg /static /images /css /js
acl is_admin path_beg /admin
acl is_websocket hdr(Upgrade) -i WebSocket
# Header-based routing
acl is_mobile hdr_sub(User-Agent) -i mobile iphone android
# Use backends based on ACLs
use_backend api_back if is_api
use_backend static_back if is_static
use_backend admin_back if is_admin
use_backend websocket_back if is_websocket
use_backend mobile_back if is_mobile
default_backend web_back
backend api_back
balance leastconn
option httpchk GET /api/health
server api1 192.168.1.30:8080 check
server api2 192.168.1.31:8080 check
backend static_back
balance roundrobin
http-request set-header Cache-Control "public, max-age=3600"
server static1 192.168.1.40:80 check
backend websocket_back
balance leastconn
option http-server-close
option forceclose
server ws1 192.168.1.50:8080 check
server ws2 192.168.1.51:8080 check Sticky Sessions (Session Persistence)
backend sticky_back
# Cookie-based persistence
cookie SERVERID insert indirect nocache
server web1 192.168.1.10:80 check cookie web1
server web2 192.168.1.11:80 check cookie web2
server web3 192.168.1.12:80 check cookie web3
backend sticky_ip
# Source IP-based persistence
balance source
hash-type consistent
server web1 192.168.1.10:80 check
server web2 192.168.1.11:80 check
server web3 192.168.1.12:80 check
backend sticky_header
# Custom header-based persistence
stick-table type string len 32 size 100k expire 30m
stick on hdr(X-Session-ID)
server web1 192.168.1.10:80 check
server web2 192.168.1.11:80 check Advanced Health Checks
backend health_check_advanced
option httpchk
# HTTP health check with custom request
http-check send meth GET uri /health ver HTTP/1.1 hdr Host www.example.com
http-check expect status 200
http-check expect string "healthy"
# TCP check on different port
server db1 192.168.1.60:3306 check port 3306 inter 2000 rise 2 fall 3
# Multiple check methods
server app1 192.168.1.70:8080 check inter 5s rise 2 fall 3
server app2 192.168.1.71:8080 check inter 5s rise 2 fall 3 backup
backend advanced_health
option httpchk GET /api/health
http-check expect status 200
http-check expect rstring "status.*ok"
# Check parameters
default-server inter 3s rise 2 fall 3 slowstart 60s maxconn 100
server srv1 192.168.1.80:80 check
server srv2 192.168.1.81:80 check
server srv3 192.168.1.82:80 check weight 200 Rate Limiting and DDoS Protection
frontend rate_limited
bind *:80
# Track client requests
stick-table type ip size 100k expire 30s store http_req_rate(10s)
# Rate limit: 20 requests per 10 seconds
http-request track-sc0 src
http-request deny deny_status 429 if { sc_http_req_rate(0) gt 20 }
# Connection rate limit
acl too_many_conn sc0_conn_cur gt 10
http-request deny deny_status 429 if too_many_conn
default_backend web_back
backend web_back
# Backend rate limiting
rate-limit sessions 100
server web1 192.168.1.10:80 check maxconn 50
server web2 192.168.1.11:80 check maxconn 50 TCP Mode Load Balancing
# MySQL load balancing
listen mysql_cluster
bind *:3306
mode tcp
balance leastconn
option mysql-check user haproxy_check
server mysql1 192.168.1.90:3306 check
server mysql2 192.168.1.91:3306 check backup
# PostgreSQL load balancing
listen postgres_cluster
bind *:5432
mode tcp
balance roundrobin
option pgsql-check user haproxy_check
server pg1 192.168.1.95:5432 check
server pg2 192.168.1.96:5432 check
# Redis load balancing
listen redis_cluster
bind *:6379
mode tcp
balance first
option tcp-check
tcp-check send PING\r\n
tcp-check expect string +PONG
server redis1 192.168.1.100:6379 check
server redis2 192.168.1.101:6379 check backup Blue-Green and Canary Deployments
frontend deployment_front
bind *:80
# Use custom header to route to specific version
acl use_green hdr(X-Version) -i green
acl is_canary rand(100) lt 10 # 10% traffic to canary
use_backend green_back if use_green
use_backend canary_back if is_canary
default_backend blue_back
backend blue_back
# Current production
server blue1 192.168.1.110:80 check
server blue2 192.168.1.111:80 check
backend green_back
# New version for testing
server green1 192.168.1.120:80 check
server green2 192.168.1.121:80 check
backend canary_back
# Canary release
server canary1 192.168.1.130:80 check Statistics and Monitoring
Stats Page Configuration
listen stats
bind *:8404
stats enable
stats uri /stats
stats refresh 30s
stats show-legends
stats show-node
# Authentication
stats auth admin:your-secure-password
# Admin level access
stats admin if TRUE Access at http://YOUR-SERVER-IP:8404/stats
Prometheus Exporter
Install HAProxy exporter:
docker run -d --name haproxy-exporter -p 9101:9101 quay.io/prometheus/haproxy-exporter:latest --haproxy.scrape-uri="http://admin:password@haproxy:8404/stats;csv" Or native installation:
wget https://github.com/prometheus/haproxy_exporter/releases/download/v0.15.0/haproxy_exporter-0.15.0.linux-amd64.tar.gz
tar xzf haproxy_exporter-0.15.0.linux-amd64.tar.gz
sudo mv haproxy_exporter /usr/local/bin/
# Create systemd service
cat > /etc/systemd/system/haproxy-exporter.service <<EOF
[Unit]
Description=HAProxy Exporter
After=network.target
[Service]
Type=simple
User=haproxy
ExecStart=/usr/local/bin/haproxy_exporter \
--haproxy.scrape-uri="unix:/run/haproxy/admin.sock"
[Install]
WantedBy=multi-user.target
EOF
sudo systemctl daemon-reload
sudo systemctl enable --now haproxy-exporter Prometheus Configuration
scrape_configs:
- job_name: 'haproxy'
static_configs:
- targets: ['localhost:9101'] Grafana Dashboard
Import dashboard ID: 2428 for HAProxy 2.x metrics
Custom Logging
global
log /dev/log local0 info
log /dev/log local1 notice
defaults
log global
option httplog
option dontlognull
# Custom log format
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"
frontend custom_logging
bind *:80
# Log only errors
option dontlog-normal
# Capture custom headers
capture request header User-Agent len 128
capture request header Referer len 128
capture response header Content-Type len 64
default_backend web_back High Availability Setup
Two-Node HA with Keepalived
Node 1 Configuration
# /etc/haproxy/haproxy.cfg on Node 1
global
stats socket /run/haproxy/admin.sock mode 660 level admin
daemon
defaults
mode http
timeout connect 5000
timeout client 50000
timeout server 50000
frontend ha_front
bind 192.168.1.100:80 # Virtual IP
default_backend ha_back
backend ha_back
balance roundrobin
server web1 192.168.1.10:80 check
server web2 192.168.1.11:80 check Keepalived configuration:
# /etc/keepalived/keepalived.conf on Node 1
vrrp_script check_haproxy {
script "/usr/bin/killall -0 haproxy"
interval 2
weight 2
}
vrrp_instance VI_1 {
state MASTER
interface eth0
virtual_router_id 51
priority 101
advert_int 1
authentication {
auth_type PASS
auth_pass your_secret_pass
}
virtual_ipaddress {
192.168.1.100/24
}
track_script {
check_haproxy
}
} Node 2 Configuration
Same HAProxy config, different Keepalived:
# /etc/keepalived/keepalived.conf on Node 2
vrrp_script check_haproxy {
script "/usr/bin/killall -0 haproxy"
interval 2
weight 2
}
vrrp_instance VI_1 {
state BACKUP
interface eth0
virtual_router_id 51
priority 100
advert_int 1
authentication {
auth_type PASS
auth_pass your_secret_pass
}
virtual_ipaddress {
192.168.1.100/24
}
track_script {
check_haproxy
}
} Session Synchronization
# Enable peer synchronization
peers haproxy_cluster
peer haproxy1 192.168.1.51:1024
peer haproxy2 192.168.1.52:1024
backend synced_sessions
stick-table type string len 32 size 100k expire 30m peers haproxy_cluster
stick on url_param(session_id)
server web1 192.168.1.10:80 check
server web2 192.168.1.11:80 check Integration with Homelab Services
Docker Swarm Integration
frontend swarm_front
bind *:80
# Route to Docker Swarm services
acl is_service1 hdr(host) -i service1.local
acl is_service2 hdr(host) -i service2.local
use_backend swarm_service1 if is_service1
use_backend swarm_service2 if is_service2
backend swarm_service1
balance roundrobin
option httpchk GET /health
# Swarm nodes
server node1 192.168.1.201:8080 check
server node2 192.168.1.202:8080 check
server node3 192.168.1.203:8080 check
backend swarm_service2
balance roundrobin
server node1 192.168.1.201:8081 check
server node2 192.168.1.202:8081 check
server node3 192.168.1.203:8081 check Kubernetes Ingress Alternative
frontend k8s_front
bind *:80
bind *:443 ssl crt /etc/ssl/private/k8s.pem
# Route based on hostname
acl is_app1 hdr(host) -i app1.k8s.local
acl is_app2 hdr(host) -i app2.k8s.local
use_backend k8s_app1 if is_app1
use_backend k8s_app2 if is_app2
backend k8s_app1
balance roundrobin
# Kubernetes NodePort
server k8s-node1 192.168.1.210:30080 check
server k8s-node2 192.168.1.211:30080 check
server k8s-node3 192.168.1.212:30080 check Home Assistant Integration
frontend homeassistant
bind *:443 ssl crt /etc/ssl/private/ha.pem
# WebSocket support
option http-server-close
option forwardfor
default_backend ha_back
backend ha_back
server ha1 192.168.1.50:8123 check Proxmox Integration
frontend proxmox_front
bind *:8006 ssl crt /etc/ssl/private/proxmox.pem
default_backend proxmox_back
backend proxmox_back
balance source
# Sticky sessions for VNC/SPICE
stick-table type ip size 200k expire 30m
stick on src
option httpchk GET /
http-check expect status 200
server pve1 192.168.1.220:8006 check ssl verify none
server pve2 192.168.1.221:8006 check ssl verify none
server pve3 192.168.1.222:8006 check ssl verify none Performance Tuning
Kernel Tuning
# /etc/sysctl.d/99-haproxy.conf
# Increase connection limits
net.core.somaxconn = 4096
net.ipv4.tcp_max_syn_backlog = 4096
# TCP optimization
net.ipv4.tcp_fin_timeout = 30
net.ipv4.tcp_keepalive_time = 300
net.ipv4.tcp_tw_reuse = 1
# Increase local port range
net.ipv4.ip_local_port_range = 1024 65535
# Increase network buffers
net.core.rmem_max = 16777216
net.core.wmem_max = 16777216
net.ipv4.tcp_rmem = 4096 87380 16777216
net.ipv4.tcp_wmem = 4096 65536 16777216
# Apply settings
sudo sysctl -p /etc/sysctl.d/99-haproxy.conf HAProxy Tuning
global
# Increase connection limits
maxconn 100000
# Multi-threading (HAProxy 2.x)
nbthread 4
cpu-map auto:1/1-4 0-3
# Memory tuning
tune.bufsize 32768
tune.maxrewrite 1024
# SSL optimization
tune.ssl.default-dh-param 2048
tune.ssl.maxrecord 1419
ssl-default-bind-ciphers ECDHE-ECDSA-AES128-GCM-SHA256
# Performance
tune.h2.initial-window-size 65535
tune.h2.max-concurrent-streams 100
defaults
# Optimize timeouts
timeout connect 3s
timeout client 30s
timeout server 30s
timeout http-keep-alive 10s
timeout http-request 10s
# Performance options
option http-keep-alive
option prefer-last-server Connection Pooling
backend pooled_connections
balance leastconn
# Reuse backend connections
option http-keep-alive
option prefer-last-server
# Connection limits
server web1 192.168.1.10:80 check maxconn 1000
server web2 192.168.1.11:80 check maxconn 1000 Security Best Practices
HTTP Security Headers
frontend secure_front
bind *:443 ssl crt /etc/ssl/private/site.pem
# Security headers
http-response set-header X-Frame-Options "SAMEORIGIN"
http-response set-header X-Content-Type-Options "nosniff"
http-response set-header X-XSS-Protection "1; mode=block"
http-response set-header Referrer-Policy "strict-origin-when-cross-origin"
http-response set-header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"
http-response set-header Content-Security-Policy "default-src 'self'"
http-response set-header Permissions-Policy "geolocation=(), microphone=(), camera=()"
# Remove server information
http-response del-header Server
http-response del-header X-Powered-By
default_backend secure_back IP Whitelisting
frontend whitelist_front
bind *:80
# Define allowed IPs
acl allowed_ips src 192.168.1.0/24 10.0.0.0/8
acl admin_ips src 192.168.1.100 192.168.1.101
# Admin access
acl is_admin path_beg /admin
http-request deny if is_admin !admin_ips
# General access
http-request deny if !allowed_ips
default_backend web_back Bot Protection
frontend bot_protection
bind *:80
# Bad bots
acl is_bad_bot hdr_sub(User-Agent) -i bot spider crawler scraper
http-request deny deny_status 403 if is_bad_bot
# Block specific user agents
acl blocked_ua hdr_sub(User-Agent) -i sqlmap nikto nmap
http-request deny deny_status 403 if blocked_ua
default_backend web_back SSL/TLS Hardening
global
# Modern SSL configuration
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-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
frontend secure_ssl
bind *:443 ssl crt /etc/ssl/private/site.pem alpn h2,http/1.1 curves secp384r1
# OCSP stapling
bind *:443 ssl crt /etc/ssl/private/site.pem ca-file /etc/ssl/certs/ca.pem verify optional Troubleshooting
Debug Mode
# Start in debug mode
haproxy -d -f /etc/haproxy/haproxy.cfg
# Verbose mode
haproxy -V -f /etc/haproxy/haproxy.cfg Socket Commands
# Connect to admin socket
echo "show info" | socat stdio /run/haproxy/admin.sock
# Show backends
echo "show backend" | socat stdio /run/haproxy/admin.sock
# Show servers
echo "show servers state" | socat stdio /run/haproxy/admin.sock
# Show statistics
echo "show stat" | socat stdio /run/haproxy/admin.sock
# Disable server
echo "disable server backend_name/server1" | socat stdio /run/haproxy/admin.sock
# Enable server
echo "enable server backend_name/server1" | socat stdio /run/haproxy/admin.sock
# Set server weight
echo "set weight backend_name/server1 50%" | socat stdio /run/haproxy/admin.sock Log Analysis
# View logs
journalctl -u haproxy -f
# Filter errors
journalctl -u haproxy | grep -i error
# Connection statistics
journalctl -u haproxy --since "1 hour ago" | grep "HTTP/1.1" | wc -l
# Top client IPs
journalctl -u haproxy --since "1 hour ago" | grep -oP 'd+.d+.d+.d+' | sort | uniq -c | sort -rn | head -20 Performance Analysis
# Check connection states
echo "show info" | socat stdio /run/haproxy/admin.sock | grep -i conn
# Backend statistics
echo "show stat" | socat stdio /run/haproxy/admin.sock | column -t -s,
# Session rate
watch -n 1 'echo "show info" | socat stdio /run/haproxy/admin.sock | grep SessRate' Backup and Disaster Recovery
Configuration Backup Script
#!/bin/bash
# backup-haproxy.sh
BACKUP_DIR="/backup/haproxy"
DATE=$(date +%Y%m%d-%H%M%S)
mkdir -p "$BACKUP_DIR"
# Backup configuration
tar -czf "$BACKUP_DIR/haproxy-config-$DATE.tar.gz" /etc/haproxy/haproxy.cfg /etc/haproxy/errors/ /etc/ssl/private/
# Backup certificates
tar -czf "$BACKUP_DIR/haproxy-certs-$DATE.tar.gz" /etc/ssl/private/
# Retain only last 30 days
find "$BACKUP_DIR" -name "haproxy-*.tar.gz" -mtime +30 -delete
echo "Backup completed: $BACKUP_DIR/haproxy-config-$DATE.tar.gz" Zero-Downtime Configuration Reload
#!/bin/bash
# reload-haproxy.sh
# Test new configuration
haproxy -c -f /etc/haproxy/haproxy.cfg.new
if [ $? -eq 0 ]; then
# Backup current config
cp /etc/haproxy/haproxy.cfg /etc/haproxy/haproxy.cfg.backup
# Apply new config
cp /etc/haproxy/haproxy.cfg.new /etc/haproxy/haproxy.cfg
# Reload
systemctl reload haproxy
echo "Configuration reloaded successfully"
else
echo "Configuration test failed"
exit 1
fi Conclusion
HAProxy is a powerful load balancer perfect for homelab environments requiring high availability, advanced traffic management, and robust health checking. Key takeaways:
- Start with simple round-robin load balancing
- Implement SSL/TLS termination for centralized certificate management
- Use health checks to ensure backend availability
- Configure sticky sessions for stateful applications
- Enable statistics for monitoring and troubleshooting
- Implement high availability with Keepalived
- Tune performance based on workload requirements
With proper configuration, HAProxy can handle thousands of concurrent connections while providing intelligent routing, failover, and security features essential for production-grade homelabs.
Additional Resources
- Official Documentation: https://www.haproxy.org/
- Configuration Manual: https://docs.haproxy.org/
- HAProxy Blog: https://www.haproxy.com/blog/
- Community Forum: https://discourse.haproxy.org/
- GitHub Repository: https://github.com/haproxy/haproxy
- SSL Configuration Generator: https://ssl-config.mozilla.org/