Skip to content
[menu][close]

FOUNDRYNETNo. 001SEPTEMBER 2026LOAD BALANCING

Crawler Rate Limiting on a Load Balancer or Reverse Proxy

Rate limiting a crawler is a queueing problem with a policy decision on top: pick the right client key, the right bucket and the right refusal, and let the cache absorb most of the load first.

Duotone plate of a tray of evenly spaced off-white tokens with the overflow spilling out of a chute, one token in hot pink.
PlateCrawler Rate Limiting on a Load Balancer or Reverse Proxy
On this page

01 Why crawlers need their own limits

A crawler differs from a user in the way that matters to capacity: it walks the long tail. People concentrate on a few popular pages that stay in cache. A crawler requests every archive page, tag listing and paginated view, most of them cold, so each request lands on the origin. Ten requests a second from one crawler can cost more origin CPU than a thousand users. This procedure belongs to the load balancing hub and assumes you already know which crawlers you accept, from measuring and verifying crawler traffic.

02 Token bucket and leaky bucket

A token bucket holds up to B tokens and refills at R tokens per second. Each request spends one; with the bucket empty, the request is refused. It allows a burst of B, then a sustained rate of R, which suits crawlers that fetch a sitemap and then pause. A leaky bucket queues requests and releases them at a fixed rate R; the queue depth is the burst allowance. It smooths traffic into the origin but adds latency to queued requests. Many proxy implementations use leaky bucket semantics with an optional burst that is served immediately rather than delayed, which behaves much like a token bucket.

Wider keys catch distributed crawlers and hit more innocent clients. Use the narrowest key that works.
Client keyCatchesCollateral risk
Verified crawler identityOne named crawler across all its addressesNone if verification is correct
Single address (/32 or /128)A single noisy hostCorporate and carrier NAT users
IPv4 /24 or IPv6 /48A crawler spread over one allocationNeighbours in shared hosting
Origin ASA fleet across many prefixesEvery customer of a large provider
Fingerprint plus addressUnverified bots rotating user-agentsProxies that share a fingerprint
Illustrative limits per keyILLUSTRATIVE LIMITS PER KEYHuman, per address20 req/sVerified crawler5 req/sUnverified bot, /241 req/sIllustrative limits per keyILLUSTRATIVE LIMITS PER KEYHuman, per address20 req/sVerified crawler5 req/sUnverified bot, /241 req/s
Illustrative values only. Derive real numbers from origin capacity and measured traffic.

03 Procedure

  1. Cache before you limit

    Set cache lifetimes on the balancer or proxy for pages that tolerate them, and serve stale content while revalidating. A cache hit costs the origin nothing, and most crawler load vanishes once deep pages are cacheable for even a few minutes.

  2. Classify the client

    Tag each request as verified crawler, claimed but unverified crawler, suspected bot or other. Use DNS or published-range verification for the first, and fingerprint and behaviour scoring for the third. The class selects the bucket.

  3. Choose the key and bucket

    Key verified crawlers on their identity, other clients on address or prefix. Size rate R from what the origin can serve uncached, and burst B from what a well-behaved crawler does after reading a sitemap.

  4. Refuse correctly

    Return 429 Too Many Requests with a Retry-After value in seconds. Compliant crawlers back off. Keep 503 for genuine origin overload, because some crawlers read repeated 503s as the site being down and change how they schedule it.

  5. Protect health checks and the origin

    Exempt the balancer's own health checks and your monitoring addresses from every limit, and apply limits in front of the real server pool, never on the path the balancer uses to test it. A limiter that fails health checks takes servers out of rotation and turns a crawler problem into an outage.

  6. Log and review

    Log key, class, rule, bucket level and decision for every refused request and a sample of passed ones. Review weekly: rising 429s to a verified crawler mean the limit is too tight or the cache too cold.

04 Illustrative config shape

The shape below uses generic open-source reverse proxy syntax with leaky bucket semantics. A map chooses the key: verified crawlers share a key per identity, everyone else is keyed on address. It is a sketch, not a drop-in configuration.

Per-class limit with 429 and Retry-After (illustrative)
map $crawler_class $limit_key {
    verified    $crawler_name;
    default     $binary_remote_addr;
}
limit_req_zone $limit_key zone=crawl:10m rate=5r/s;
limit_req_status 429;
server {
    listen 443 ssl;
    server_name www.example.com;
    location = /healthz { limit_req off; }
    location / {
        limit_req zone=crawl burst=20 nodelay;
        error_page 429 = @throttled;
        # hand off to the real server pool here
    }
    location @throttled {
        add_header Retry-After 30 always;
        return 429;
    }
}

05 Where the limiter sits

Put it at the first device that terminates HTTP, usually a Layer 7 balancer or reverse proxy, because it needs the user-agent and path. A Layer 4 device can only limit connections per address, which is blunt. Keep limiter state local to each balancer unless the pair shares it; two units each allowing 5 requests a second allow 10 in total. That matters under persistence rules that pin a crawler to one unit, and it matters in reverse when they do not. Watch the effect on volume by prefix with sampled flow data after each change.

WARNING

Do not rate limit robots.txt and sitemaps harder than pages. A crawler that cannot read your rules cannot obey them.

Rate limits are the last line. Before them, caching rules that absorb crawler requests remove most repeat load, and a written AI crawler policy decides who is limited at all.

06 Questions

Should crawlers get 429 or 503 when they exceed a limit?

429 Too Many Requests with Retry-After. It says the client is the problem and when to return. 503 says the server is the problem; use it only for real overload, since crawlers may treat repeated 503s as downtime.

What is the difference between a token bucket and a leaky bucket?

A token bucket allows a burst up to its size, then a steady rate. A leaky bucket queues requests and releases them at a steady rate, adding delay instead of refusing. Proxies that serve the burst immediately behave much like a token bucket.

Is limiting by /24 safe?

Safe enough for unverified bots on hosting ranges, risky on residential or corporate networks where one /24 holds many unrelated users. Prefer verified identity for known crawlers and single addresses elsewhere.

Why is caching called the cheapest rate limiter?

A cache hit is served without touching the origin, so crawler requests for cacheable pages cost almost nothing. Tuning cache lifetimes often removes more origin load than any limit and never refuses a legitimate client.

How do I stop rate limits from breaking health checks?

Exempt the health check path and the balancer and monitoring source addresses from every limit rule, and test by watching pool member state while you load the limiter.