Rate limiting
Token-bucket rate limits live under [security.rate_limit] (global), [domains.security.rate_limit] (per domain), and [domains.routes.security.rate_limit] (per route). Dynamic.
Per-domain and per-route blocks are whole-block replaces: the most specific scope that defines a rate_limit block replaces the parent’s block entirely. There is no field-level inheritance.
See examples/config/rate-limit-example.toml on GitHub for a full file.
Strategies
Section titled “Strategies”Key limit_by values:
ip: client IP (resolved fromX-Forwarded-Forwhen[security].trusted_proxiesis set; see below)header: value of a named header (limit_by_header)route: shared limit per route pathcombined: IP + route
Responses use 429 when exceeded. Counters are in-memory and per process; they are not shared across replicas.
Real client IP behind a load balancer
Section titled “Real client IP behind a load balancer”When the proxy sits behind a trusted load balancer, set [security].trusted_proxies (a global CIDR list) so limit_by = "ip" and "combined" resolve the real client IP from X-Forwarded-For instead of the proxy’s IP:
security: trusted_proxies: - "10.0.0.0/8" - "172.16.0.0/12" rate_limit: enabled: true requests_per_second: 500 burst: 1000 limit_by: "ip"[security]trusted_proxies = ["10.0.0.0/8", "172.16.0.0/12"]
[security.rate_limit]enabled = truerequests_per_second = 500burst = 1000limit_by = "ip"trusted_proxies is global only: it is a property of the network topology, not of any individual domain or route.
Global default
Section titled “Global default”security: rate_limit: enabled: true requests_per_second: 1000 burst: 2000 window_seconds: 1 limit_by: "ip"[security.rate_limit]enabled = truerequests_per_second = 1000burst = 2000window_seconds = 1limit_by = "ip"Per-domain override
Section titled “Per-domain override”The domain block replaces the global rate-limit config entirely for all requests that match this domain.
domains: - host: "api.example.com" security: rate_limit: enabled: true requests_per_second: 50 burst: 100 limit_by: "combined"[[domains]]host = "api.example.com"
[domains.security.rate_limit]enabled = truerequests_per_second = 50burst = 100limit_by = "combined"Per-route override
Section titled “Per-route override”The route block replaces the domain (or global) rate-limit config for requests matching this route.
domains: - host: "api.example.com" routes: - prefix: "/api" backend: "backend-a:9000" security: rate_limit: enabled: true requests_per_second: 50 burst: 100 limit_by: "combined" - prefix: "/public" backend: "backend-b:9000" security: rate_limit: enabled: false[[domains]]host = "api.example.com"
[[domains.routes]] prefix = "/api" backend = "backend-a:9000"
[domains.routes.security.rate_limit] enabled = true requests_per_second = 50 burst = 100 limit_by = "combined"
[[domains.routes]] prefix = "/public" backend = "backend-b:9000"
[domains.routes.security.rate_limit] enabled = false # disable for this routeRate limit by header
Section titled “Rate limit by header”security: rate_limit: enabled: true requests_per_second: 200 burst: 400 limit_by: "header" limit_by_header: "X-API-Key"[security.rate_limit]enabled = truerequests_per_second = 200burst = 400limit_by = "header"limit_by_header = "X-API-Key"Related
Section titled “Related”- Security:
trusted_proxies, connection limits, security headers - IP filtering:
[security.ip_filter] - Routes & Domains: prefix and backend selection
- Configuration overview