Reverse Proxy

Rate limiting

Token bucket per IP z bounded memory, rozproszony limiting przez Redis (atomowy Lua) i fail-open. Konfiguracja i trusted proxies.

Token bucket per IP#

Każdy klient (IP) ma własny token bucket:

  • requests_per_minute — sustained rate (domyślnie 100),
  • burst — maksymalny jednorazowy wystrzał (domyślnie 50).
yaml
rate_limit:
  requests_per_minute: 100
  burst: 50
  trusted_proxies: []

Bucket napełnia się ze stałą prędkością; każdy request zabiera token. Brak tokenu → 429 rate_limit_exceeded.

Bounded memory#

Limiter memory ma ograniczoną pamięć: wpisy bezczynnych klientów są usuwane (idle-entry eviction), więc atak z milionów unikalnych IP nie zjada RAM-u.

Trusted proxies#

Za load balancerem/CDN socket address to adres pośrednika, nie klienta. trusted_proxies mówi, którym pośrednikom ufać przy czytaniu X-Forwarded-For:

yaml
rate_limit:
  trusted_proxies:
    - 10.0.0.0/8
    - 192.168.1.1

Bez trusted proxies nagłówki są ignorowane

Jeśli trusted_proxies jest puste, client-supplied X-Forwarded-For jest ignorowany, a limit liczony po socket address. Inaczej każdy klient mógłby spoofować IP i omijać limity.

Rozproszony rate limiting (Redis)#

Wiele instancji proxy może współdzielić jeden budżet limitów przez Redis:

yaml
redis:
  addr: redis:6379
bash
export REDIS_PASSWORD=secret
docker compose --profile redis up -d

Limity są egzekwowane atomowo w Redis skryptem Lua (token bucket), więc wszystkie instancje widzą ten sam stan licznika.

Fail-open#

Jeśli Redis jest nieosiągalny, ruch płynie dalej (availability over strict limiting), a błędy są liczone:

text
rate_limit_errors_total 3

To świadoma decyzja: lepiej przepuścić ruch niż zabić produkcję przy awarii Redis.

Przykłady konfiguracji#

Publiczne API#

yaml
rate_limit:
  requests_per_minute: 60
  burst: 20
  trusted_proxies:
    - 172.16.0.0/12

Wewnętrzny mikroserwis (hojny limit)#

yaml
rate_limit:
  requests_per_minute: 6000
  burst: 1000

Wiele instancji proxy + Redis#

yaml
redis:
  addr: redis:6379

rate_limit:
  requests_per_minute: 300
  burst: 100
  trusted_proxies:
    - 10.0.0.0/8

Metryki#

MetrykaOpis
rate_limit_rejected_totalRequesty odrzucone z 429
rate_limit_errors_totalBłędy backendu limitingu (np. Redis down)
bash
curl -s http://localhost:8080/metrics | grep rate_limit

Testowanie limitów#

bash
for i in $(seq 1 60); do
  curl -s -o /dev/null -w "%{http_code}\n" http://localhost:8080/
done | sort | uniq -c
text
  50 200
  10 429

Pierwsze burst requestów przechodzi, kolejne dostają 429, aż bucket się napełni.