Un errore 502 Bad Gateway significa che un server che fa da gateway o da proxy ha ricevuto una risposta non valida dal server alle sue spalle. Il visitatore ha raggiunto qualcosa, di solito nginx, Apache, un load balancer o una CDN, ma quel livello non è riuscito a ottenere una risposta corretta dalla tua applicazione. L’applicazione si è bloccata, si sta riavviando, è in ascolto da un’altra parte o ha chiuso la connessione a metà.
Per questo un 502 è un messaggio che riguarda due server, non uno. Questa guida ti mostra come capire quale livello lo ha restituito, come risolvere le cause più comuni e come venire a sapere del prossimo 502 prima dei tuoi clienti.
Cosa ti dice un errore 502
La maggior parte dei siti web ha almeno due livelli tra il visitatore e il codice. Davanti c’è una CDN o un load balancer, un web server come nginx termina la connessione e un processo applicativo, come PHP-FPM, Node.js, Gunicorn o un server Java, costruisce la pagina. Ogni livello inoltra la richiesta al successivo e ripassa indietro la risposta.
Un 502 compare quando uno di questi livelli inoltra una richiesta e non riceve indietro nulla di utilizzabile. Confrontalo con gli altri errori di gateway:
502 Bad Gateway: il server upstream ha risposto con qualcosa di non valido, ha resettato la connessione o l’ha rifiutata.
503 Service Unavailable: il servizio è sovraccarico, in manutenzione o non ha un server funzionante a cui inviare la richiesta.
504 Gateway Timeout: il server upstream non ha risposto in tempo.
Quindi un 502 di solito significa rotto o fermo, un 504 di solito significa lento. Il nostro prontuario dei codici di stato HTTP elenca il resto della famiglia, e la guida agli errori 503 tratta sovraccarico e manutenzione.
Trova il livello che ha restituito il 502
Prima di cambiare qualsiasi cosa, scopri chi ha risposto. La pagina di errore e gli header della risposta di solito lo dicono chiaramente:
curl -sI https://www.example.com/checkout
HTTP/2 502
server: cloudflare
cf-ray: 8d2f1c3a5b7e4a21-ARN
server: cloudflare con una pagina di errore Cloudflare che indica il tuo host: Cloudflare ha raggiunto la tua origine, ed è l’origine ad aver fallito.
server: nginx o Apache con una semplice pagina di errore: il tuo web server non è riuscito a raggiungere l’applicazione alle sue spalle.
server: awselb/2.0 o un altro load balancer: il load balancer non ha ricevuto una risposta valida da nessun target, o da quello che ha scelto.
Poi confronta con una richiesta che salta il livello esterno. Inviala direttamente all’origine o alla porta dell’applicazione sul server stesso:
curl -sI –resolve www.example.com:443:203.0.113.10 https://www.example.com/checkout
curl -sI http://127.0.0.1:3000/checkout
Se l’applicazione risponde in locale ma non attraverso il proxy, controlla la configurazione del proxy. Se non risponde nemmeno in locale, il problema è l’applicazione.
Cause comuni e come risolverle
Il processo applicativo si è bloccato o si sta riavviando
È la causa più comune. Il processo dietro il proxy ha esaurito la memoria, ha incontrato un’eccezione non gestita o è stato terminato, e il proxy non ha più nessuno con cui parlare. nginx lo registra senza giri di parole:
connect() failed (111: Connection refused) while connecting to upstream,
upstream: “http://127.0.0.1:3000/checkout”
Verifica se il processo è in esecuzione e perché si è fermato:
systemctl status myapp
journalctl -u myapp –since “30 min ago”
dmesg -T | grep -i “killed process”
Una riga dell’OOM killer del kernel significa che il server ha esaurito la memoria. Un riavvio rimette online il sito, ma la vera soluzione è più memoria, meno worker o un memory leak individuato e corretto. Assicurati che il servizio si riavvii da solo dopo un crash, per esempio con Restart=on-failure nella sua unit systemd.
PHP-FPM è fermo o ha esaurito i worker
Sui siti PHP, nginx passa le richieste a PHP-FPM tramite un socket o una porta. Se PHP-FPM è fermo, il percorso del socket è sbagliato o i permessi del socket tengono fuori nginx, ogni pagina PHP restituisce 502:
connect() to unix:/run/php/php8.3-fpm.sock failed (2: No such file or directory)
Quel messaggio di solito arriva dopo un aggiornamento di PHP: nginx punta ancora al socket della versione precedente. Fai puntare fastcgi_pass al nuovo socket e ricarica nginx. Se invece il log riporta server reached pm.max_children, tutti i worker sono occupati, spesso in attesa di un database lento o di un’API esterna. Alza il limite solo se il server ha memoria in avanzo; altrimenti scopri cosa tiene occupati i worker.
Indirizzo o porta upstream sbagliati
Dopo una migrazione, la ricostruzione di un container o un cambio di porta, il proxy potrebbe ancora inoltrare al vecchio indirizzo. Il log degli errori mostra l’indirizzo che ha provato. Confrontalo con quello su cui l’applicazione è davvero in ascolto:
ss -ltnp | grep -E ‘:(3000|8000|9000)’
In Docker e Kubernetes la causa è spesso il nome di un servizio che non viene più risolto, un container in ascolto su 127.0.0.1 all’interno del container invece che su 0.0.0.0, oppure un readiness check che segna ogni pod come non pronto.
L’upstream ha chiuso la connessione in anticipo
upstream prematurely closed connection while reading response header significa che l’applicazione ha accettato la richiesta e poi ha riagganciato. I motivi tipici sono un crash a metà della richiesta, un worker terminato perché ha superato il proprio limite di tempo, come il –timeout di Gunicorn o il max_execution_time di PHP, e connessioni keep-alive che l’applicazione chiude prima di quanto si aspetti il proxy. Allinea i timeout in modo che il proxy aspetti un po’ più dell’applicazione, mai il contrario, e guarda quali richieste sono abbastanza lente da raggiungere il limite.
Header di risposta troppo grandi
Cookie di grandi dimensioni o molti header Set-Cookie possono superare il buffer di nginx per gli header di risposta dell’upstream. nginx allora registra upstream sent too big header while reading response header from upstream e restituisce 502. Aumenta i buffer con cautela:
proxy_buffer_size 16k;
proxy_buffers 8 16k;
# for PHP-FPM
fastcgi_buffer_size 32k;
fastcgi_buffers 8 16k;
Poi scopri perché gli header sono cresciuti. Un cookie che cresce a ogni visita è un bug che vale la pena correggere.
La CDN non riesce a comunicare con la tua origine
Quando una CDN o un load balancer restituisce 502, controlla cosa c’è tra quel livello e il tuo server. Un firewall che blocca gli intervalli di indirizzi della CDN, un certificato dell’origine che la CDN non accetta, un’origine che parla solo HTTP/1.0 o chiude le connessioni troppo presto, oppure un record DNS che punta a un vecchio server finiscono tutti allo stesso modo. Testa direttamente l’origine, come mostrato sopra, e controlla il firewall e le impostazioni TLS su entrambi i lati.
Errori 502 durante i deploy
Se i 502 compaiono per dieci o venti secondi alla volta e sempre in corrispondenza di un rilascio, a causarli è il deploy stesso. Il vecchio processo si ferma, quello nuovo impiega qualche secondo ad avviarsi e ogni richiesta nel frattempo fallisce. La soluzione è un ordine di rilascio in cui c’è sempre qualcosa pronto a rispondere:
Avvia la nuova versione accanto a quella vecchia.
Aspetta che superi l’health check. La nostra guida alla creazione di un endpoint di health check spiega cosa dovrebbe verificare quel controllo.
Sposta il traffico sulla nuova versione.
Lascia che la vecchia versione completi le richieste in corso, poi fermala.
Process manager e orchestratori supportano questo approccio come reload progressivi o a zero downtime. Usali al posto di un semplice riavvio.
Come il monitoraggio intercetta gli errori 502
Un 502 spesso dura poco. Un deploy causa venti secondi di errori, un worker si blocca e si riavvia, una cache nasconde il problema alla maggior parte dei visitatori. Quando qualcuno apre il sito funziona di nuovo, ma un cliente a metà del checkout ha visto l’errore.
Un monitor di uptime richiede le tue pagine a intervalli regolari e registra il codice di stato e il tempo di risposta di ogni controllo. Un 502 è un controllo fallito. Quello che conta è cosa succede dopo:
Conferma l’errore. Una singola richiesta fallita può essere un’anomalia passeggera. Uptimecheck esegue controlli fino a ogni minuto da Stoccolma, Londra e New York e conferma ogni errore da una seconda località prima di aprire un incidente, così un reset isolato non sveglia nessuno.
Mostra le prove. L’incidente include la risposta fallita, così vedi il codice di stato, l’header server e la pagina di errore, oltre a uno screenshot di ciò che hanno visto i visitatori. Quando il server non ha risposto affatto, ottieni invece il percorso di rete.
Raggiungi le persone giuste. Gli avvisi arrivano via email, Slack, Microsoft Teams, PagerDuty, webhook e gli altri canali di notifica che usa il tuo team.
Non monitorare solo la homepage. La homepage è spesso in cache su una CDN e continua a funzionare mentre checkout, login e API restituiscono 502. Aggiungi monitor di uptime per le pagine che portano fatturato e monitor delle API per gli endpoint chiamati dalle tue app. Quando il 502 arriva da un’applicazione che ha esaurito la memoria, il monitoraggio dei server mostra l’andamento della memoria accanto all’interruzione.
Checklist per l’errore 502
Leggi l’header server e la pagina di errore per capire quale livello ha restituito il 502.
Interroga direttamente l’origine e la porta dell’applicazione per restringere il campo.
Leggi il log degli errori del proxy allo stesso timestamp: connessione rifiutata, chiusa in anticipo o header troppo grande.
Verifica che il processo applicativo sia in esecuzione e, se non lo è, perché si è fermato.
Confronta indirizzo upstream, socket e porta con quelli su cui l’applicazione è in ascolto.
Allinea i timeout in modo che il proxy aspetti più a lungo dell’applicazione.
Fai i deploy avviando la nuova versione prima di fermare quella vecchia.
Monitora pagine ed endpoint chiave ogni minuto e conferma ogni errore prima di inviare un avviso.