Implement HAProxy rate limiting and DDoS protection with advanced security rules

Intermediate 45 min Apr 08, 2026 82 views
Ubuntu 24.04 Debian 12 AlmaLinux 9 Rocky Linux 9

Configure HAProxy with comprehensive rate limiting, connection throttling, and DDoS protection using stick tables, ACLs, and advanced security rules to protect your applications from malicious traffic and ensure service availability.

Prerequisites

  • Root or sudo access
  • Basic knowledge of load balancing concepts
  • Backend web servers configured

What this solves

HAProxy rate limiting and DDoS protection shields your web applications from traffic spikes, brute force attacks, and distributed denial of service attempts. This tutorial implements advanced security rules using stick tables for connection tracking, ACLs for traffic classification, and tarpit mechanisms to slow down malicious requests while maintaining performance for legitimate users.

Step-by-step installation

Update system packages

Start by updating your package manager to ensure you get the latest HAProxy version with security features.

sudo apt update && sudo apt upgrade -y
sudo dnf update -y

Install HAProxy

Install HAProxy with all required modules for advanced load balancing and security features.

sudo apt install -y haproxy rsyslog
sudo dnf install -y haproxy rsyslog

Create backup of default configuration

Always backup the original configuration before making changes for easy rollback if needed.

sudo cp /etc/haproxy/haproxy.cfg /etc/haproxy/haproxy.cfg.backup

Configure HAProxy global settings

Set up global security parameters including SSL tuning, logging, and performance optimizations.

global
    log 127.0.0.1:514 local0
    chroot /var/lib/haproxy
    stats socket /run/haproxy/admin.sock mode 660 level admin
    stats timeout 30s
    user haproxy
    group haproxy
    daemon
    
    # Security settings
    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
    
    # Performance tuning
    tune.ssl.default-dh-param 2048
    tune.bufsize 32768
    
defaults
    mode http
    timeout connect 5000ms
    timeout client 50000ms
    timeout server 50000ms
    timeout http-request 15s
    timeout http-keep-alive 15s
    
    # Security headers
    option httplog
    option dontlognull
    option log-health-checks
    option forwardfor
    option http-server-close
    
    # Error handling
    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

Configure stick tables for rate limiting

Create stick tables to track connection rates, request rates, and abuse patterns by IP address.

# Rate limiting frontend
frontend web_frontend
    bind *:80
    bind *:443 ssl crt /etc/ssl/certs/example.com.pem
    
    # Redirect HTTP to HTTPS
    redirect scheme https if !{ ssl_fc }
    
    # Stick tables for tracking
    stick-table type ip size 100k expire 30s store http_req_rate(10s),http_err_rate(10s),conn_rate(10s),sess_cnt
    
    # Track requests per IP
    http-request track-sc0 src
    
    # DDoS protection rules
    # Block if more than 20 requests per 10 seconds
    http-request deny if { sc_http_req_rate(0) gt 20 }
    
    # Block if more than 10 connections per 10 seconds
    http-request deny if { sc_conn_rate(0) gt 10 }
    
    # Block if error rate is too high (more than 10 errors in 10s)
    http-request deny if { sc_http_err_rate(0) gt 10 }
    
    # Tarpit suspicious traffic (slow response for abusers)
    http-request tarpit if { sc_http_req_rate(0) gt 15 } { sc_http_req_rate(0) lt 21 }
    
    # 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 Strict-Transport-Security "max-age=31536000; includeSubDomains"
    
    default_backend web_servers

Create advanced ACL rules

Define Access Control Lists to identify and handle different types of traffic patterns and potential attacks.

# Advanced ACL definitions
frontend web_frontend
    # ... previous configuration ...
    
    # ACL for known bad user agents
    acl bad_bots hdr_sub(User-Agent) -i "sqlmap" "nikto" "nmap" "masscan" "zmap"
    acl bad_bots hdr_sub(User-Agent) -i "python-requests" "curl/" "wget/" unless { src -f /etc/haproxy/whitelist_ips.txt }
    
    # ACL for suspicious request patterns
    acl suspicious_path path_beg -i "/admin" "/wp-admin" "/phpmyadmin" "/.env"
    acl suspicious_path path_reg -i "\.(php|asp|jsp)$" unless { path_beg "/api/" }
    acl sql_injection query -m reg -i ".(union|select|insert|delete|update|drop|create|alter)."
    acl xss_attempt query -m reg -i ".(script|javascript|vbscript|onload|onerror)."
    
    # Rate limiting for different endpoints
    acl api_path path_beg "/api/"
    acl login_path path "/login" "/wp-login.php" "/admin/login"
    
    # Geographic restrictions (if needed)
    # acl blocked_countries src -f /etc/haproxy/blocked_countries.txt
    
    # Advanced blocking rules
    http-request deny if bad_bots
    http-request deny if sql_injection
    http-request deny if xss_attempt
    http-request tarpit if suspicious_path
    
    # Stricter rate limiting for login endpoints
    http-request deny if login_path { sc_http_req_rate(0) gt 5 }
    
    # More permissive for API endpoints (but still limited)
    http-request deny if api_path { sc_http_req_rate(0) gt 50 }

Configure backend servers with health checks

Set up backend server pools with health monitoring and failover capabilities.

backend web_servers
    balance roundrobin
    option httpchk GET /health HTTP/1.1\r\nHost:\ example.com
    
    # Backend server health and performance settings
    default-server check inter 3000ms rise 2 fall 3 maxconn 100
    
    # Add your backend servers
    server web1 10.0.1.10:80 check
    server web2 10.0.1.11:80 check
    server web3 10.0.1.12:80 check backup
    
    # Connection limits per server
    server web1 10.0.1.10:80 maxconn 200 check
    server web2 10.0.1.11:80 maxconn 200 check
    
    # Timeout settings for backends
    timeout server 30s
    timeout connect 5s

Create statistics interface

Enable HAProxy statistics page for monitoring rate limiting effectiveness and server health.

# Statistics interface
listen stats
    bind *:8404
    stats enable
    stats uri /stats
    stats refresh 30s
    stats hide-version
    stats realm HAProxy\ Statistics
    stats auth admin:secure_password_here
    
    # Security for stats interface
    acl stats_admin src 127.0.0.1 10.0.0.0/8 192.168.0.0/16
    http-request deny unless stats_admin

Create whitelist for trusted IPs

Create a whitelist file for trusted IP addresses that should bypass rate limiting.

sudo mkdir -p /etc/haproxy
sudo touch /etc/haproxy/whitelist_ips.txt
# Trusted IP addresses (monitoring systems, CDN, etc.)
127.0.0.1
10.0.0.0/8
192.168.0.0/16

Add your monitoring server IPs here

203.0.113.100

198.51.100.0/24

Configure logging for security monitoring

Set up dedicated logging for HAProxy to monitor rate limiting actions and security events.

$ModLoad imudp
$UDPServerRun 514
$UDPServerAddress 127.0.0.1

HAProxy log processing

local0.* /var/log/haproxy.log & stop

Set up log rotation

Configure log rotation to prevent HAProxy security logs from consuming too much disk space.

/var/log/haproxy.log {
    daily
    rotate 30
    compress
    delaycompress
    missingok
    notifempty
    postrotate
        /bin/kill -HUP $(cat /var/run/rsyslogd.pid 2> /dev/null) 2> /dev/null || true
    endscript
}

Test configuration and start services

Validate the HAProxy configuration and start the services with security monitoring enabled.

# Test HAProxy configuration
sudo haproxy -c -f /etc/haproxy/haproxy.cfg

Restart services

sudo systemctl restart rsyslog sudo systemctl enable haproxy sudo systemctl restart haproxy

Check service status

sudo systemctl status haproxy sudo systemctl status rsyslog

Create monitoring script

Set up a monitoring script to track rate limiting effectiveness and send alerts.

#!/bin/bash

HAProxy Security Monitor Script

LOG_FILE="/var/log/haproxy.log" ALERT_EMAIL="admin@example.com" THRESHOLD_BLOCKS=50

Count blocked requests in the last 5 minutes

BLOCKED_COUNT=$(tail -n 1000 $LOG_FILE | grep "$(date -d '5 minutes ago' '+%b %d %H:%M')" | grep -c "HTTP/1.1" | grep -c "403\|429\|444") if [ $BLOCKED_COUNT -gt $THRESHOLD_BLOCKS ]; then echo "High number of blocked requests detected: $BLOCKED_COUNT" | mail -s "HAProxy Security Alert" $ALERT_EMAIL logger "HAProxy Security Alert: $BLOCKED_COUNT blocked requests in last 5 minutes" fi

Check for potential DDoS

DDOS_IPS=$(tail -n 2000 $LOG_FILE | grep "$(date '+%b %d %H:%M')" | awk '{print $6}' | sort | uniq -c | awk '$1 > 100 {print $2}' | wc -l) if [ $DDOS_IPS -gt 0 ]; then echo "Potential DDoS detected from $DDOS_IPS IP addresses" | mail -s "HAProxy DDoS Alert" $ALERT_EMAIL fi
sudo chmod +x /usr/local/bin/haproxy_security_monitor.sh

Add to crontab for regular monitoring

sudo crontab -e

Add this line:

/5 * /usr/local/bin/haproxy_security_monitor.sh

Configure advanced stick table sharing

Set up stick table synchronization

For multi-HAProxy deployments, configure stick table synchronization to share rate limiting data between instances.

# Add to the peers section for cluster synchronization
peers mycluster
    peer haproxy1 192.168.1.10:1024
    peer haproxy2 192.168.1.11:1024
    

Update frontend with peers configuration

frontend web_frontend # ... previous configuration ... stick-table type ip size 100k expire 30s store http_req_rate(10s),http_err_rate(10s),conn_rate(10s),sess_cnt peers mycluster

Configure firewall for HAProxy

Set up firewall rules to protect HAProxy while allowing legitimate traffic.

# Allow HTTP, HTTPS, and stats interface
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw allow from 192.168.0.0/16 to any port 8404
sudo ufw allow from 10.0.0.0/8 to any port 8404
# Allow HTTP, HTTPS, and stats interface
sudo firewall-cmd --permanent --add-port=80/tcp
sudo firewall-cmd --permanent --add-port=443/tcp
sudo firewall-cmd --permanent --add-rich-rule='rule family=ipv4 source address=192.168.0.0/16 port protocol=tcp port=8404 accept'
sudo firewall-cmd --reload

Verify your setup

Test that HAProxy is running with rate limiting and DDoS protection enabled.

# Check HAProxy status
sudo systemctl status haproxy

Verify configuration syntax

sudo haproxy -c -f /etc/haproxy/haproxy.cfg

Test rate limiting with curl

for i in {1..25}; do curl -s -o /dev/null -w "%{http_code}\n" http://example.com/; done

Check statistics interface

curl -u admin:secure_password_here http://localhost:8404/stats

Monitor logs for rate limiting actions

sudo tail -f /var/log/haproxy.log | grep -E "403|429|tarpit"

Check stick table contents

echo "show table web_frontend" | sudo socat stdio /run/haproxy/admin.sock

Monitor and tune security rules

Set up Prometheus metrics collection

Enable HAProxy stats in Prometheus format for advanced monitoring and alerting.

# Add to the stats listen section
listen stats
    # ... existing configuration ...
    
    # Prometheus metrics endpoint
    http-request use-service prometheus-exporter if { path /metrics }
    stats show-modules

You can now monitor HAProxy performance and security metrics with monitoring solutions. Consider implementing HAProxy monitoring with Prometheus and Grafana for comprehensive observability.

Common issues

SymptomCauseFix
Configuration test failsSyntax error in haproxy.cfgsudo haproxy -c -f /etc/haproxy/haproxy.cfg to identify specific errors
Rate limiting not workingStick table not tracking correctlyCheck track-sc0 src is properly configured in frontend
Legitimate users blockedRate limits too aggressiveIncrease thresholds or add IPs to whitelist file
SSL certificate errorsCertificate path incorrectVerify certificate file exists and HAProxy user has read access
Statistics page not accessibleFirewall blocking port 8404Configure firewall rules for stats interface access
Backend servers marked downHealth check failingVerify /health endpoint exists on backend servers
High memory usageStick table size too largeReduce stick table size or decrease expiration time
Logs not appearingRsyslog not configuredRestart rsyslog service and verify UDP listener on 127.0.0.1:514
Security Warning: Never disable rate limiting entirely in production. Start with higher thresholds and gradually decrease based on traffic patterns. Always maintain a whitelist for monitoring and administrative systems.

Next steps

Automated install script

Run this to automate the entire setup

Need help?

Don't want to manage this yourself?

We handle infrastructure security hardening for businesses that depend on uptime. From initial setup to ongoing operations.