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
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.
Startup rejects either setting on its own. Configuring one without the other is
treated as a misconfiguration, not a partial setup.
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.
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.