Raise rate limit thresholds to avoid false positives on normal traffic
All checks were successful
HAProxy Manager Build and Push / Build-and-Push (push) Successful in 1m22s

Previous thresholds (200/500 req/10s) were too aggressive — WordPress
login pages with their CSS/JS/image assets can easily burst 30-50
requests per page load, triggering tarpits and blocks on legitimate
users.

New thresholds:
- Request rate: tarpit at 1000/10s (100 req/s), block at 2000/10s (200 req/s)
- Connection rate: 300/10s (was 150)
- Concurrent connections: 200 (was 100)
- Error rate: 50/30s (was 20)

These still catch real floods and scanners while giving normal web
traffic plenty of headroom.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-03-31 14:10:53 -07:00
parent 53d259bd3f
commit 5390ebb8a6

View File

@@ -30,16 +30,20 @@ frontend web
acl is_whitelisted var(txn.real_ip),map_ip(/etc/haproxy/trusted_ips.map,0) -m int gt 0
# --- Rate limit rules (applied in order, first match wins) ---
# Hard block: >500 req/10s per IP (sustained flood)
http-request deny deny_status 429 if { sc_http_req_rate(0) gt 500 } !is_local !is_trusted_ip !is_whitelisted !is_health_check
# Tarpit: >200 req/10s per IP (aggressive scraping / light flood)
http-request tarpit deny_status 429 if { sc_http_req_rate(0) gt 200 } !is_local !is_trusted_ip !is_whitelisted !is_health_check
# Connection rate limit: >150 new connections per 10s per IP
http-request deny deny_status 429 if { sc_conn_rate(0) gt 150 } !is_local !is_trusted_ip !is_whitelisted !is_health_check
# Concurrent connection limit: >100 simultaneous connections per IP
http-request deny deny_status 429 if { sc_conn_cur(0) gt 100 } !is_local !is_trusted_ip !is_whitelisted !is_health_check
# High error rate: >20 errors in 30s (scanner/fuzzer behavior)
http-request tarpit deny_status 403 if { sc_http_err_rate(0) gt 20 } !is_local !is_trusted_ip !is_whitelisted !is_health_check
# Thresholds sized for real-world web traffic: a heavy page load can
# generate 30-50 requests and multiple rapid page navigations can burst
# well above 100 req/10s legitimately.
#
# Hard block: >2000 req/10s per IP (200 req/s — only real floods)
http-request deny deny_status 429 if { sc_http_req_rate(0) gt 2000 } !is_local !is_trusted_ip !is_whitelisted !is_health_check
# Tarpit: >1000 req/10s per IP (100 req/s — sustained aggressive scraping)
http-request tarpit deny_status 429 if { sc_http_req_rate(0) gt 1000 } !is_local !is_trusted_ip !is_whitelisted !is_health_check
# Connection rate limit: >300 new connections per 10s per IP
http-request deny deny_status 429 if { sc_conn_rate(0) gt 300 } !is_local !is_trusted_ip !is_whitelisted !is_health_check
# Concurrent connection limit: >200 simultaneous connections per IP
http-request deny deny_status 429 if { sc_conn_cur(0) gt 200 } !is_local !is_trusted_ip !is_whitelisted !is_health_check
# High error rate: >50 errors in 30s (scanner/fuzzer behavior)
http-request tarpit deny_status 403 if { sc_http_err_rate(0) gt 50 } !is_local !is_trusted_ip !is_whitelisted !is_health_check
# IP blocking using map file (manual blocks only)
# Map file format: /etc/haproxy/blocked_ips.map contains "<ip_or_cidr> 1" per line