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:

PropertyDescription
NameDisplay name
ListenerWhich listener to apply to
RequestsMaximum requests in the window
WindowTime window in seconds
BurstAdditional burst allowance
KeyWhat to track (default: client IP)
ActionWhat to do when exceeded

Actions

ActionDescription
denyReturn 429 Too Many Requests
tarpitBlock the client for a duration (see below)
challengePresent a CAPTCHA challenge
logLog 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
Tarpit vs deny

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:

VariableDescription
{{ 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

  1. Navigate to Traffic > Rate Limiting
  2. Click Add Rate Limit
  3. Name: api-general
  4. Listener: select your API listener
  5. Requests: 100
  6. Window: 60 (100 requests per minute)
  7. Burst: 20 (allow 20 additional burst)
  8. Action: deny
  9. Save and Apply

Step-by-Step: Per-Endpoint Rate Limit

  1. Navigate to Traffic > Rate Limiting
  2. Click Add Rate Limit
  3. Name: login-limit
  4. Listener: select your listener
  5. Path pattern: /login
  6. Method: POST
  7. Requests: 5
  8. Window: 300 (5 login attempts per 5 minutes)
  9. Action: tarpit
  10. Block duration: 600 (10 minutes)
  11. Save and Apply
Login rate limiting

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

  1. Create a network Security List named trusted-ips with your trusted IP ranges
  2. Navigate to Security > Security Rules
  3. Click Add Rule
  4. Name: skip-ratelimit-trusted
  5. Expression: ip.src in $network:trusted_ips
  6. Action: skip_ratelimit
  7. Place this rule above your rate limit rules
  8. Save and Apply

Verification

  1. Test under the limit:

    for i in $(seq 1 5); do curl -k -s -o /dev/null -w '%{http_code}\n' https://localhost/api/; done

    Expect all 200s.

  2. Test over the limit:

    for i in $(seq 1 200); do curl -k -s -o /dev/null -w '%{http_code}\n' https://localhost/api/; done

    Expect 200s initially, then 429s after the limit is exceeded.

  3. Check the 429 response:

    curl -k -v https://localhost/api/ 2>&1 | grep -i 'retry-after\|429'
  4. 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