Rate Limiting
Overview
Rate limiting uses HAProxy stick-tables for sliding-window quotas. Each rate limit tracks request counts per client IP (or other key) within a configurable time window and triggers an action when the threshold is exceeded.
Configuration
Rate limits are configured per listener. Each rate limit has:
| Property | Description |
|---|---|
| Name | Display name |
| Listener | Which listener to apply to |
| Requests | Maximum requests in the window |
| Window | Time window in seconds |
| Burst | Additional burst allowance |
| Key | What to track (default: client IP) |
| Action | What to do when exceeded |
Actions
| Action | Description |
|---|---|
| deny | Return 429 Too Many Requests |
| tarpit | Block the client for a duration (see below) |
| challenge | Present a CAPTCHA challenge |
| log | Log but allow through |
Block Duration (Tarpit)
When a client exceeds a rate limit with the tarpit action, they are temporarily blocked for a configurable duration. The block is stored in the stick-table’s GPC0 counter.
- Block duration — how long to block the client (e.g. 300 seconds)
- During the block, all requests from the client receive a 403
- After the block expires, the client can make requests again
deny rejects only the current request that exceeds the limit. tarpit blocks the client for a duration, rejecting all subsequent requests during that period. Use tarpit for abusive clients that continue hammering after being rate limited.
Per-Endpoint Scoping
Rate limits can be scoped to specific endpoints using:
- path_pattern — a glob or regex pattern (e.g.
/api/*,/login) - method — HTTP method (e.g.
POST)
This is particularly useful when combined with API Armor for per-endpoint API rate limiting.
The api_armor_scoped flag indicates that a rate limit is scoped to a specific API endpoint learned by API Armor.
WAF-Triggered Rate Limiting
WAF anomaly scores can trigger rate limits. When a request has a high WAF anomaly score, it can count against a separate, stricter rate limit. This allows you to progressively block clients that repeatedly trigger WAF rules without blocking all clients at the same rate.
Rate Limit Error Pages
Custom 429 error pages can be configured with template variables:
| Variable | Description |
|---|---|
{{ rate_limit_window }} | The time window in seconds |
{{ rate_limit_duration }} | The block duration (for tarpit) |
Security Rules Integration
Rate limits can be skipped via the skip_ratelimit action in Security Rules. This is useful for:
- Exempting trusted IPs from rate limits
- Skipping rate limits for authenticated requests
- Allowing specific user agents (e.g. health checks)
# Skip rate limit for health checks
http.request.uri.path == "/health" -> skip_ratelimit
# Skip rate limit for authenticated users
auth.valid -> skip_ratelimit
Step-by-Step: Create a Basic Rate Limit
- Navigate to Traffic > Rate Limiting
- Click Add Rate Limit
- Name:
api-general - Listener: select your API listener
- Requests:
100 - Window:
60(100 requests per minute) - Burst:
20(allow 20 additional burst) - Action: deny
- Save and Apply
Step-by-Step: Per-Endpoint Rate Limit
- Navigate to Traffic > Rate Limiting
- Click Add Rate Limit
- Name:
login-limit - Listener: select your listener
- Path pattern:
/login - Method:
POST - Requests:
5 - Window:
300(5 login attempts per 5 minutes) - Action: tarpit
- Block duration:
600(10 minutes) - Save and Apply
Rate limiting login endpoints is one of the most effective brute-force protections. Set a low limit (5-10 attempts per 5 minutes) with tarpit action to block attackers after a few failed attempts.
Step-by-Step: Skip Rate Limit for Trusted IPs
- Create a network Security List named
trusted-ipswith your trusted IP ranges - Navigate to Security > Security Rules
- Click Add Rule
- Name:
skip-ratelimit-trusted - Expression:
ip.src in $network:trusted_ips - Action: skip_ratelimit
- Place this rule above your rate limit rules
- Save and Apply
Verification
-
Test under the limit:
for i in $(seq 1 5); do curl -k -s -o /dev/null -w '%{http_code}\n' https://localhost/api/; doneExpect all 200s.
-
Test over the limit:
for i in $(seq 1 200); do curl -k -s -o /dev/null -w '%{http_code}\n' https://localhost/api/; doneExpect 200s initially, then 429s after the limit is exceeded.
-
Check the 429 response:
curl -k -v https://localhost/api/ 2>&1 | grep -i 'retry-after\|429' -
Check tarpit:
- After exceeding a tarpit rate limit, verify subsequent requests return 403
- Wait for the block duration to expire and verify requests succeed again
Next Steps
- Security Rules — Skip rate limits for trusted traffic
- API Armor — Per-endpoint API rate limiting
- CAPTCHA — Challenge clients that exceed limits