How to Configure Haproxy Rate Limiting with Stick Tables and Acls on Ubuntu
Learning how to configure HAProxy rate limiting with stick tables and ACLs on Ubuntu is one of the most effective ways to protect your web applications from traffic abuse, brute-force attacks, and DDoS floods. HAProxy is a high-performance load balancer and proxy server trusted by major websites worldwide. Its stick table feature lets you track client behavior across requests. Combined with ACLs, you can build smart, dynamic rate-limiting rules that block bad actors automatically. In this tutorial, you will install HAProxy on Ubuntu, configure stick tables to count requests per IP, write ACL rules to enforce limits, and test that everything works correctly. By the end, you will have a working rate-limiting setup that can protect any backend service you run.
Prerequisites and Requirements for HAProxy Rate Limiting
Before you start configuring HAProxy rate limiting with stick tables and ACLs, make sure you have the following in place.
System requirements:
- Ubuntu 20.04 or 22.04 (fresh or existing server)
- Root or sudo access
- A backend web server or application running (such as Nginx or Apache)
- Basic familiarity with the Linux command line
Estimated time: 30–45 minutes
You should also have a basic understanding of how proxies and load balancers work. You don’t need to be an expert. If you’ve edited config files and run commands in a terminal before, you’re ready. Make sure your Ubuntu server has internet access so you can install packages. It also helps to have a second machine or tool like curl or Apache Benchmark available for testing your rate limits later.
Step-by-Step Guide to Configure HAProxy Rate Limiting with Stick Tables and ACLs
For a related walkthrough, see: How to Optimize Docker Images with Multi-stage Builds
Follow these steps carefully. Each step builds on the previous one.
Step 1: Update your system and install HAProxy
Start by refreshing your package list and installing HAProxy.
sudo apt update && sudo apt upgrade -y
sudo apt install haproxy -y
After installation, verify the version:
haproxy -v
You should see version 2.x or higher. HAProxy 2.x includes full stick table support with expiry and rate tracking. Check the official HAProxy configuration documentation for a complete reference on all directives.
Step 2: Back up the default configuration
Always back up config files before editing them.
sudo cp /etc/haproxy/haproxy.cfg /etc/haproxy/haproxy.cfg.bak
Step 3: Open the HAProxy configuration file
sudo nano /etc/haproxy/haproxy.cfg
You’ll edit this file throughout the next steps.
Step 4: Configure the global and defaults sections
Replace or update the existing global and defaults blocks with the following:
global
log /dev/log local0
log /dev/log local1 notice
chroot /var/lib/haproxy
stats socket /run/haproxy/admin.sock mode 660 level admin
maxconn 50000
user haproxy
group haproxy
daemon
defaults
log global
mode http
option httplog
option dontlognull
timeout connect 5s
timeout client 30s
timeout server 30s
These settings establish logging, connection limits, and timeouts. Keep timeouts short to free resources from slow or abusive clients.
Step 5: Create a frontend with a stick table
Now add your frontend block. This is where rate limiting happens. Add the following after your defaults section:
frontend http_front
bind :80
mode http
# Define a stick table to track request rates per IP
stick-table type ip size 100k expire 30s store http_req_rate(10s)
# Track the client IP in the stick table
http-request track-sc0 src
# Define ACL: flag IPs making more than 100 requests in 10 seconds
acl too_many_requests sc_http_req_rate(0) gt 100
# Deny flagged IPs with a 429 response
http-request deny deny_status 429 if too_many_requests
default_backend web_servers
Here’s what each part does. The stick-table line creates an in-memory table. It stores up to 100,000 IP entries. Each entry expires after 30 seconds of inactivity. The store option tracks the HTTP request rate over a 10-second window. The http-request track-sc0 src line logs each request’s source IP into the table. The ACL checks if any IP exceeds 100 requests in 10 seconds. If it does, HAProxy returns a 429 Too Many Requests response immediately.
Step 6: Configure the backend
Add your backend block pointing to your actual web server:
backend web_servers
mode http
balance roundrobin
server web1 127.0.0.1:8080 check
Replace 127.0.0.1:8080 with your actual backend server address and port.
Step 7: Validate and reload HAProxy
Always validate your config before reloading. A syntax error will take down your proxy.
sudo haproxy -c -f /etc/haproxy/haproxy.cfg
You should see: Configuration file is valid
Then reload the service:
sudo systemctl reload haproxy
sudo systemctl status haproxy
Step 8: Test your rate limiting rules
Use Apache Benchmark to simulate high traffic from a single IP:
ab -n 200 -c 10 http://your-server-ip/
After 100 requests, you should start receiving 429 responses. You can also use curl in a loop:
for i in {1..120}; do curl -s -o /dev/null -w "%{http_code}n" http://your-server-ip/; done
Watch the output change from 200 to 429 after the threshold is hit. For more advanced testing strategies, see the Ubuntu Server documentation for network and firewall tools you can combine with HAProxy.
Troubleshooting Common HAProxy Rate Limiting Problems
Even with a clean setup, things can go wrong. Here are the most common issues and how to fix them.
Problem: HAProxy won’t start after config changes
Run sudo haproxy -c -f /etc/haproxy/haproxy.cfg to find the exact line causing the error. Fix the syntax and try again.
Problem: Rate limiting isn’t triggering
Double-check your ACL threshold. If your test tool isn’t sending enough requests fast enough, the counter won’t exceed the limit. Lower the threshold temporarily to 10 requests for testing, then raise it back.
Problem: All clients get blocked, not just abusers
This usually means you’re tracking the wrong source. Check that http-request track-sc0 src is using the correct client IP. If your server is behind a CDN or another proxy, the source IP might always be the same upstream address. In that case, track by req.hdr(X-Forwarded-For) instead.
Problem: Stick table fills up too fast
Increase the size parameter in your stick-table definition. Start with 200k or 500k if you handle high traffic volumes. Also reduce the expire time to flush stale entries sooner.
Warning: Don’t set your rate limit threshold too low in production. Legitimate users behind shared IPs (like office networks or mobile carriers) can share a single IP address. A threshold of 100–200 requests per 10 seconds is a reasonable starting point for most applications.
Conclusion
You now know how to configure HAProxy rate limiting with stick tables and ACLs on Ubuntu from start to finish. You installed HAProxy, set up an in-memory stick table to track per-IP request rates, wrote ACL rules to identify abusive clients, and confirmed the setup works with real traffic tests. This configuration gives your server a strong first line of defense against floods and scraping bots. From here, you can extend this setup by adding multiple stick tables for different metrics, combining rate limiting with geo-blocking, or integrating HAProxy with a logging stack like Graylog or ELK. Keep your HAProxy version updated and review your thresholds regularly as your traffic patterns change.
