Nginx rate limiting: limit_req_zone, burst, nodelay i ochrona przed DDoS
Opublikowano: 9 kwietnia 2026 · Kategoria: VPS / Bezpieczeństwo
Rate limiting w Nginx to pierwsza linia obrony przed atakami brute force, web scraperem bez
respektu dla robots.txt i prostymi atakami DDoS na poziomie HTTP. Moduł ngx_http_limit_req_module implementuje algorytm leaky bucket — ogranicza tempo żądań per IP, per URL lub per dowolny klucz.
Poprawna konfiguracja chroni serwer bez blokowania legalnych użytkowników.
limit_req_zone — ograniczenie tempa żądań
Dyrektywa limit_req_zone definiuje strefę (shared memory zone) przechowującą stan
klientów. Musi być w bloku http, nie w server ani location.
# /etc/nginx/nginx.conf — blok http { ... }
http {
# Strefa dla ogólnego rate limiting — 10 MB pamięci (ok. 160 000 IP), limit 10 req/s
limit_req_zone $binary_remote_addr zone=general:10m rate=10r/s;
# Strefa dla endpointów logowania — bardziej restrykcyjny limit
limit_req_zone $binary_remote_addr zone=login:5m rate=5r/m;
# Strefa dla API — ograniczenie per IP
limit_req_zone $binary_remote_addr zone=api:10m rate=30r/m;
# Strefa z kluczem per user agent + IP (bardziej szczegółowa)
limit_req_zone "$binary_remote_addr$http_user_agent" zone=strict:10m rate=5r/s;
# Zmien domyslny kod bledu na 429 (Too Many Requests)
limit_req_status 429;
}
Format stawki: r/s (requestów na sekundę) lub r/m (requestów na minutę).
Klucz strefy to zazwyczaj $binary_remote_addr (4 bajty dla IPv4, 16 dla IPv6) — bardziej
kompaktowy niż $remote_addr (string).
Stosowanie limit_req w lokalizacjach
# /etc/nginx/sites-available/twoja-strona
server {
listen 443 ssl http2;
server_name twojadomena.pl;
# Ogólny rate limiting dla całej strony
limit_req zone=general burst=20 nodelay;
# Strona logowania — surowe limity
location /wp-login.php {
limit_req zone=login burst=3 nodelay;
limit_req_status 429;
# Zwróć error page z Retry-After
error_page 429 /rate-limit.html;
include fastcgi_params;
fastcgi_pass unix:/var/run/php/php8.2-fpm.sock;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
}
# Endpoint API — limit + nagłówki informacyjne
location /api/ {
limit_req zone=api burst=10 nodelay;
add_header X-RateLimit-Limit "30" always;
add_header X-RateLimit-Window "60s" always;
proxy_pass http://localhost:3000;
}
# Strona statyczna — brak rate limiting (CDN to obsługuje)
location ~* \.(css|js|png|jpg|gif|ico|woff2)$ {
expires 30d;
add_header Cache-Control "public, immutable";
}
# Strona błędu 429
location = /rate-limit.html {
internal;
add_header Retry-After 60 always;
return 429 "Za dużo żądań. Poczekaj chwilę i spróbuj ponownie.";
}
} limit_conn_zone — ograniczenie jednoczesnych połączeń
limit_conn_zone ogranicza liczbę równoczesnych połączeń TCP od jednego IP. Przydatne
do blokowania download managerów pobierających z wielu wątków i botów otwierających wiele połączeń
jednocześnie.
# W bloku http:
http {
# Strefa połączeń — 10 MB, klucz per IP
limit_conn_zone $binary_remote_addr zone=conn_per_ip:10m;
# Strefa dla serwera (wszystkie połączenia łącznie)
limit_conn_zone $server_name zone=conn_per_server:10m;
limit_conn_status 429;
}
# W bloku server lub location:
server {
# Maksymalnie 10 połączeń per IP
limit_conn conn_per_ip 10;
# Maksymalnie 1000 połączeń do serwera łącznie
limit_conn conn_per_server 1000;
# Dla plików do pobrania — mocniejsze ograniczenie
location /download/ {
limit_conn conn_per_ip 2;
limit_rate 500k; # Dodatkowo: limit prędkości 500 KB/s per połączenie
}
} Whitelist — wyłączenie limitów dla zaufanych IP
Najczystszy sposób na whitelist to blok geo, który mapuje adresy IP na zmienną.
Puste klucze w strefie limit_req są ignorowane przez Nginx.
# W bloku http — PRZED limit_req_zone:
http {
# Mapuj IP na klucz — pusty string = brak limitu
geo $limit_key {
default $binary_remote_addr; # normalni uzytkownicy: limit per IP
192.168.1.0/24 ""; # siec wewnętrzna: brak limitu
203.0.113.10 ""; # IP biura: brak limitu
127.0.0.1 ""; # localhost: brak limitu
}
# Uzyj $limit_key jako klucza strefy
limit_req_zone $limit_key zone=general:10m rate=10r/s;
limit_conn_zone $limit_key zone=conn_per_ip:10m;
} Logowanie zdarzeń rate limiting
Domyślnie Nginx loguje przekroczenia limitu na poziomie ERROR, co zaśmieca logi. Ogranicz poziom logowania do WARN, a osobny log pozwoli monitorować ataki.
# W bloku http:
http {
limit_req_zone $binary_remote_addr zone=general:10m rate=10r/s;
# Zmien poziom logowania (domyslnie: error)
# Opcje: info, notice, warn, error (im wyzsza = mniej logów)
limit_req_log_level warn;
limit_conn_log_level warn;
}
# Osobny format logu z IP i limitowanym URL
log_format rate_limit '$remote_addr - [$time_local] '
'"$request" $status "$http_user_agent" '
'zone=$limit_req_zone';
# W bloku server — osobny plik dla zdarzeń 429
server {
error_log /var/log/nginx/rate-limit.log warn;
}
# Monitoruj ataki w czasie rzeczywistym
tail -f /var/log/nginx/rate-limit.log | grep " 429 "
# Znajdz TOP 10 IP przekraczajacych limity
awk '$9 == 429 {print $1}' /var/log/nginx/access.log \
| sort | uniq -c | sort -rn | head -10 Parametry — tabela referencyjna
| Dyrektywa | Opis | Typowa wartość |
|---|---|---|
rate=Xr/s | Limit requestów na sekundę per klucz | 10r/s strona, 5r/m login |
burst=N | Bufor tolerancji — max N req do kolejkowania | 20 strona, 5 API, 3 login |
nodelay | Burst obsługiwany natychmiast (bez kolejki) | Dodaj gdy burst > 0 |
delay=N | Pierwsze N z burst natychmiast, reszta kolejkowana | delay=5 (kompromis) |
limit_conn N | Max jednoczesnych połączeń per klucz | 10 strona, 2 pobieranie |
limit_rate Xk | Limit prędkości transferu per połączenie | 500k dla plików do pobrania |