> ## Documentation Index
> Fetch the complete documentation index at: https://docs.uatu.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Rate limiting

> Per-client budgets, and how to configure them safely behind a proxy.

Requests are limited by client IP using the Redis-backed `go-limiter` store, so the
budget is shared by every application replica rather than being per-process.

IPv6 addresses are bucketed by their `/64` network, so a client cannot rotate
addresses within the same network to obtain a fresh budget.

## Budget size

| Variable              | Default | Meaning                                  |
| --------------------- | ------- | ---------------------------------------- |
| `RATE_LIMIT_TOKENS`   | `60`    | Requests allowed per client per interval |
| `RATE_LIMIT_INTERVAL` | `1m`    | Length of the budget interval            |

## Direct connections

When clients connect directly to the service, leave both proxy settings unset. The
TCP peer address is the client.

## Behind a reverse proxy

Behind a proxy you must set **both** of these: the header the proxy writes, and the
CIDRs of every trusted proxy that can connect to this service.

```env theme={null}
RATE_LIMIT_TRUSTED_HEADER=X-Forwarded-For
RATE_LIMIT_TRUSTED_PROXY_CIDRS=10.0.0.0/8,fd00:1234::/48
```

<Warning>
  Startup rejects either setting on its own. Configuring one without the other is
  treated as a misconfiguration, not a partial setup.
</Warning>

The forwarding header is ignored unless the TCP peer (`r.RemoteAddr`) belongs to that
CIDR allowlist. Without this, any client could spoof the header and be rate-limited as
someone else, or as nobody.

### How the client is resolved

For `X-Forwarded-For`, the limiter walks the chain from **right to left**, skips
trusted proxy addresses, and uses the first untrusted address as the client.

Two things this requires of your infrastructure:

* Your reverse proxy must **append** the address of its direct peer to the header.
* The service must **not** be reachable from the public internet outside the
  configured CIDRs.

### Single-value headers

For a header such as `CF-Connecting-IP` that carries one address rather than a chain,
configure the CDN or edge proxy CIDRs and ensure the edge **overwrites** the inbound
header on every request. Otherwise a client can supply its own.

## Failure behaviour

An absent or malformed forwarding header falls back to the known proxy address. That
fails closed, so several clients may share a budget, rather than trusting a value an
attacker controls.
