Errore 429 Too Many Requests: come capire chi sta limitando e come risolvere
Il 429 può venire dal tuo server, dal CDN davanti o dall'API esterna. Come distinguerli dalle intestazioni di risposta e come scrivere un client che aspetta invece di insistere.
Redazione UptimeMag · 14 ottobre 2026 · 6 minuti di lettura

Se il sito risponde 429 la prima domanda non è "perché", è "chi": il tuo Nginx, il CDN o il WAF davanti, oppure un'API esterna che il sito interroga (pagamenti, mappe, posta). Lo si capisce in trenta secondi guardando le intestazioni della risposta, prima di toccare qualsiasi configurazione.
Cosa significa l'errore
Il 429 non è un server rotto. Secondo RFC 6585, il codice indica che il client ha mandato troppe richieste in un dato intervallo di tempo: è una regola di traffico, non un guasto. Chi riceve un 429 deve smettere di mandare richieste, aspettare e riprovare — non insistere.
Verifica più rapida: guarda le intestazioni
Con curl -I https://esempio.it/percorso (o curl -v per vedere anche la richiesta) si leggono le intestazioni della risposta 429. Tre indizi distinguono la fonte:
- Server: cloudflare o un header
cf-ray→ il blocco arriva dal CDN/WAF davanti al sito, non dal tuo webserver. - Server: nginx e nessun header di terze parti → il limite è nella tua configurazione Nginx.
- Header tipo
x-ratelimit-remaining,x-ratelimit-resetoRateLimit-*→ la risposta arriva da un'API esterna che il tuo codice sta chiamando, non dal sito stesso.
L'header che conta di più, quando c'è, è Retry-After. Secondo RFC 9110 §10.2.3, il Retry-After dice al client quanto aspettare prima di una nuova richiesta, ed è definito in RFC 9110 (IETF, giugno 2022) e richiamato in RFC 6585 (IETF, aprile 2012) per il 429. Il valore può essere espresso in due modi, entrambi validi secondo lo standard: come numero intero di secondi da attendere dal momento della risposta, oppure come data HTTP assoluta.
Causa 1: limite impostato sul tuo server (la più frequente)
Come si capisce se è la tua. Su Ubuntu 24.04 con Nginx: sudo tail -f /var/log/nginx/error.log mentre il sito riceve traffico. La riga che conta è quella che inizia con [error] e contiene la dicitura "limiting requests, excess": indica che il modulo limit_req ha rifiutato una richiesta perché superava la soglia configurata, con lo zone name e l'IP del client coinvolto.
Un dettaglio che cambia la diagnosi: di default Nginx non risponde 429 a chi sfora il limite, risponde 503 Service Unavailable. Il 429 lo si ottiene solo impostando esplicitamente limit_req_status 429; nel blocco server o location. Se il tuo monitoraggio vede 503 invece di 429 ma nel log compare "limiting requests", il problema è comunque questo: la differenza è solo nel codice restituito, non nella causa.
Su cPanel/Plesk con Apache, il meccanismo equivalente è mod_ratelimit o le regole di ModSecurity/Fail2ban che il pannello applica agli IP che superano una soglia di richieste: in quel caso il controllo va fatto nel log di ModSecurity o nelle regole Fail2ban attive, non nell'error log di Nginx.
Come si risolve. Se il limite è troppo stretto per il traffico reale (bot legittimi, una SPA che fa polling, un cron che interroga troppo spesso), si alza la soglia nella direttiva limit_req_zone oppure si aggiunge un margine di burst:
limit_req_zone $binary_remote_addr zone=api:10m rate=10r/s;
location /api/ {
limit_req zone=api burst=20 nodelay;
limit_req_status 429;
}
burst=20 accetta fino a 20 richieste in eccesso prima di rifiutare, nodelay le serve subito invece di metterle in coda.
Come si verifica che è risolto. Si ripete il traffico che prima falliva (lo stesso script, lo stesso bot) e si controlla che l'error log non produca più righe "limiting requests" per quel client, e che curl -I sulla stessa risorsa torni 200 invece di 429/503.
Causa 2: limite applicato dal CDN o dal WAF davanti al server
Come si capisce se è la tua. Se la risposta 429 arriva con header Server: cloudflare o con un cf-ray nelle intestazioni, il tuo Nginx non ha nemmeno visto la richiesta: il blocco è successo prima, al perimetro. In questo caso tail sul tuo error log locale non mostrerà nulla, perché la richiesta non è arrivata al server di origine.
Come si risolve. Si entra nel pannello del CDN/WAF e si controlla la regola di rate limiting attiva su quel percorso: soglia, finestra temporale, azione (block/challenge). Se il traffico bloccato è legittimo (un partner, un servizio di monitoraggio, un webhook), si aggiunge un'eccezione per quell'IP o user-agent invece di alzare il limite globale, che abbasserebbe la protezione per tutti.
Come si verifica che è risolto. Si ripete la richiesta dallo stesso IP/client che prima otteneva 429 e si controlla che la risposta non contenga più l'header del CDN tipico del blocco (varia per fornitore: va controllato nella pagina di stato della regola).
Causa 3: è l'API esterna che il tuo sito chiama a limitarti
Come si capisce se è la tua. Qui il 429 non lo riceve il visitatore del sito, lo riceve il tuo codice quando chiama un servizio terzo (gateway di pagamento, API di mappe, servizio di invio email). Si verifica nei log applicativi (PHP-FPM slow log, log dell'applicazione) cercando le chiamate HTTP uscenti che falliscono con 429, e leggendo le intestazioni della risposta di quell'API.
Un esempio concreto di come funzionano questi limiti, preso dalla documentazione ufficiale di GitHub: il limite primario per le richieste non autenticate è 60 richieste all'ora, mentre usando un token di accesso personale il limite sale a 5.000 richieste all'ora. Questo è un limite "a finestra": conta le richieste in un intervallo fisso e lo azzera allo scadere. Lo stato in tempo reale si legge dagli header di ogni risposta: x-ratelimit-limit indica il massimo orario, x-ratelimit-remaining le richieste rimaste nella finestra corrente, x-ratelimit-reset il momento in cui la finestra si azzera, in secondi epoch UTC.
GitHub aggiunge anche un secondo livello di controllo, più facile da sottovalutare: non sono ammesse più di 100 richieste concorrenti, e non più di 900 punti al minuto per endpoint della REST API. Chi resta sotto il limite orario dichiarato può comunque ricevere 429 per questo secondo limite, se manda troppe richieste in parallelo o troppo ravvicinate: è la causa più comune di 429 "inspiegabili" su integrazioni che sembrano rispettare la quota.
Come si risolve. Non si aumenta nulla lato proprio: si rallenta. Si riduce la concorrenza delle chiamate, si introduce una cache per le risposte che non cambiano spesso, e soprattutto si rispetta l'header quando l'API lo manda.
Un client che rispetta Retry-After e usa attesa crescente quando l'header manca:
import time
import random
def chiama_con_backoff(fai_richiesta, tentativi_massimi=6):
attesa = 1
for tentativo in range(tentativi_massimi):
risposta = fai_richiesta()
if risposta.status_code != 429:
return risposta
retry_after = risposta.headers.get("Retry-After")
if retry_after is not None:
secondi = int(retry_after) if retry_after.isdigit() else 5
else:
secondi = attesa
time.sleep(secondi + random.uniform(0, 1))
attesa = attesa * 2
raise RuntimeError("ancora 429 dopo tutti i tentativi")
Il punto non negoziabile: se Retry-After c'è, si usa quel valore, non una stima propria. Se manca, si raddoppia l'attesa a ogni tentativo (1s, 2s, 4s, 8s...) aggiungendo un piccolo margine casuale (jitter) per evitare che più client ritentino tutti nello stesso istante.
Come si verifica che è risolto. Si monitora per qualche ora il tasso di 429 nei log applicativi verso quell'API: deve scendere a zero o quasi, e x-ratelimit-remaining nelle risposte non deve più toccare lo zero prima della fine della finestra.
Quando chiamare l'assistenza del fornitore
Se il 429 arriva dal CDN/WAF o dall'hosting condiviso e non si ha accesso alla regola che lo genera, va aperto un ticket con: l'URL esatto che fallisce, l'ora precisa (con fuso orario) di almeno tre richieste rifiutate, l'IP sorgente delle richieste, e il testo completo delle intestazioni della risposta 429 (compreso qualsiasi header con ray, request-id o simili, che il supporto usa per rintracciare l'evento nei propri log interni). Senza questi dati l'assistenza non può distinguere un blocco legittimo da un falso positivo.
Nessun prodotto Prime Software citato in questo articolo.
Testo redatto con il supporto dell'intelligenza artificiale e verificato dalla redazione (AI Act, art. 50).