← Back to DevBytes

HAProxy Configuration: Complete Setup and Configuration Guide

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:

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:

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

🚀 Need a reliable AI agent for your project?

Deploy Hermes Agent in 10 minutes. Managed hosting, zero DevOps.

Get Started — $23.99/mo
← Back to all articles