Rate limiting su NGINX: configurare limit_req senza bloccare gli utenti veri
Come configurare limit_req_zone e limit_req su NGINX, testare con nginx -t e verificare nei log senza bloccare traffico legittimo.
Redazione UptimeMag · 24 ottobre 2026 · 4 minuti di lettura

Un endpoint di login preso a forza bruta, uno scraper che martella la stessa pagina, un bot che ignora il robots.txt: il sintomo è sempre lo stesso, CPU al tappeto e utenti veri che aspettano. Il rate limiting di NGINX risolve il problema con due direttive, ma va tarato: una soglia troppo bassa blocca anche chi naviga normalmente. Questa guida configura limit_req_zone e limit_req, li testa con nginx -t e verifica il risultato nei log, su Ubuntu 24.04.
Versione dichiarata
Le prove sono fatte con NGINX installato da apt su Ubuntu 24.04. Il repository ufficiale Ubuntu per questa release pacchettizza nginx version: nginx/1.24.0 (Ubuntu), confermato anche dalla documentazione di Vultr con lo stesso output di nginx -version. Chi vuole una versione più recente deve passare al repository ufficiale di nginx.org (stabile o mainline): è un altro pacchetto, con un altro percorso di aggiornamento, e va scelto consapevolmente.
Le due direttive: limit_req_zone e limit_req
La configurazione sta in due righe. La prima, limit_req_zone, va nel blocco http e definisce la zona di memoria condivisa, la chiave di conteggio (di solito l'IP del client) e la soglia:
limit_req_zone $binary_remote_addr zone=mylimit:10m rate=10r/s;
La sintassi è limit_req_zone key zone=name:size rate=rate [sync], e imposta i parametri per una zona di memoria condivisa che conserva lo stato per varie chiavi, in particolare il numero corrente di richieste eccedenti; la chiave può contenere testo, variabili o la loro combinazione; le richieste con un valore di chiave vuoto non vengono conteggiate. Questo significa che si può costruire un allowlist mettendo a vuoto la chiave per gli IP interni, invece di escluderli con un if.
La seconda direttiva, limit_req, applica la zona dove serve - http, server o location:
server {
location /login/ {
limit_req zone=mylimit;
proxy_pass http://backend;
}
}
Da sola, senza parametri aggiuntivi, rifiuta ogni richiesta che superi la soglia media: con rate=10r/s la decima richiesta nello stesso secondo dallo stesso IP riceve 503.
Scegliere la soglia senza bloccare traffico legittimo
Il traffico reale non arriva mai a intervalli regolari: un browser carica una pagina e in un attimo scarica CSS, JS, immagini, tutte dalla stessa chiave IP. Per questo esiste burst:
limit_req zone=mylimit burst=20 nodelay;
Con rate=1r/s e burst=5 si consente non più di 1 richiesta al secondo in media, con picchi che non superano le 5 richieste. Senza nodelay le richieste in eccesso rispetto al rate medio vengono messe in coda e processate con ritardo; se non si vuole ritardare le richieste eccedenti va usato il parametro nodelay, mentre il parametro delay (dalla versione 1.15.7) fissa il limite da cui le richieste eccedenti iniziano a essere ritardate, e il valore predefinito è zero, cioè tutte le richieste eccedenti vengono ritardate. Un compromesso intermedio, usato per endpoint che ricevono traffico a ondate come una pagina di ricerca, è il delay esplicito: limit_req zone=ip burst=12 delay=8 lascia passare le prime 8 richieste in eccesso subito e mette in coda solo quelle oltre.
Per endpoint diversi conviene separare le zone invece di usarne una sola troppo larga o troppo stretta:
| Endpoint | Zona | rate | burst | Comportamento |
|---|---|---|---|---|
| Login / form | login | 1r/s | 5 | nodelay, blocca subito oltre soglia |
| API generiche | api | 10r/s | 20 | coda breve, assorbe i picchi del browser |
| Sito statico | general | 50r/s | 50 | limite solo contro scraping aggressivo |
Si parte sempre da soglie larghe e si stringe guardando i log, non il contrario: una soglia indovinata a tavolino rischia di bloccare utenti reali dietro NAT o proxy aziendali, dove molte persone condividono lo stesso IP.
Testare la configurazione prima del reload
limit_req_zone è valido solo nel contesto http; se finisce per errore dentro un blocco server o location, nginx -t fallisce prima che la configurazione possa essere ricaricata, con un messaggio del tipo "limit_req_zone" directive is not allowed here. Per questo il comando va lanciato sempre prima del reload:
sudo nginx -t
sudo systemctl reload nginx
Se il test passa, il reload non interrompe le connessioni già aperte.
Verificare che il limite funzioni
Prima di mettere in produzione una soglia aggressiva conviene osservarla senza farle rifiutare nulla. NGINX offre limit_req_dry_run: con questa direttiva attiva, ogni richiesta che supererebbe il limite viene registrata nel log con il contrassegno "dry run", senza bloccare davvero il traffico. È il modo per capire quanto è stretta una soglia prima di attivarla sul serio.
Attivato il blocco, la verifica sta nei codici di risposta: con burst e nodelay, le richieste eccedenti il burst vengono rifiutate con errore 503, quindi un controllo rapido è:
grep ' 503 ' /var/log/nginx/access.log | tail -50
Se il codice 503 compare anche per IP che non sono bot ma browser reali, la soglia è troppo bassa e va alzata. Per distinguere il rate limiting da altri 503 (backend giù, ad esempio) si può cambiare il codice restituito con limit_req_status, impostandolo per esempio a 429, il codice HTTP pensato proprio per "troppe richieste", e poi filtrare i log su quel valore.
Questa guida non riguarda prodotti Prime Software.
Testo redatto con il supporto dell'intelligenza artificiale e verificato dalla redazione (AI Act, art. 50).