HAProxy Rate-Limiting Example
HAProxy Rate-Limiting Example
One of the benefits of haproxy is how easy it is to rate-limit aggressive ips.
Recently I had to start rate-limiting aggressive ips that are attempting to hack your site or just cause a small ddos attack.
I added the following to my configuration right before the backends.
##Whitelist acl whitelist_ip hdr_ip(x-forwarded-for,1) -f /etc/haproxy/whitelist_ip.txt acl whitelist_ip src -m ip -f /etc/haproxy/whitelist_ip.txt ## IP Rate Limiting ## stick-table type ipv6 size 100k expire 30s store http_req_rate(10s) http-request track-sc0 src http-request deny deny_status 429 if { sc_http_req_rate(0) gt 20 } !whitelist_ip ## Route to chosen backend use_backend %[var(req.backend)] if { var(req.backend) -m found } default_backend apache-backend
Rules Explained
The rule says if they create 20 sessions in 10s from a specific ip address (aggressive ips), you block them for 30 seconds if the ip address is NOT whitelisted.
I use the whitelist for my ip and most good bots.
Explainations and Customizations
The stick-table directive creates a key-value store for storing counters like the HTTP request rate per client. The key is the client’s IP address, as configured by the type parameter, which is used to store and aggregate that client’s number of requests. The http-request track-sc0 src line adds the client as a record in the stick table. The counters begin to be recorded as soon as the IP is added.
A stick table record expires and is removed after a period of inactivity by the client, as set by the expire parameter. That’s just a way of freeing up space. Without an expire parameter, the oldest records are evicted when the storage becomes full. Here, we’re allowing 100,000 records.
The http-request deny line sets the rate limit threshold and the action to take when someone exceeds it. Here, we’re allowing up to 20 concurrent requests and denying additional ones with a 429 Too Many Requests response until the count during the last 10 seconds is below the threshold again. Other actions include forwarding the client to a dedicated backend or silently dropping the connection. The sc_http_req_rate fetch method returns the client’s current request rate.
You can play with the time period or the threshold. Instead of counting requests over 10 seconds, you might extend it to something like 1000 requests during the last 24 hours. Simply change the counter specified on the stick-table line from http_req_rate(10s) to http_req_rate(24h). Then update the http-request deny line to allow no more than 1000 requests.