Networking advanced ⏱ 60 minutes

HAProxy: High Availability Load Balancing

Enterprise load balancing for homelabs. SSL termination, health checks, and failover.

By homelabbing.io • 2025-12-17
#haproxy#load-balancing#ha#ssl#proxy

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

  1. High Availability - Eliminate single points of failure
  2. Performance - Handle 100,000+ requests per second
  3. Flexibility - Support for HTTP, HTTPS, TCP, WebSocket
  4. Smart Health Checks - Automatic failover on backend failures
  5. SSL Termination - Centralized certificate management
  6. Zero Downtime - Reload configurations without dropping connections
  7. 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

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