504 Gateway Timeout: quale richiesta sta impiegando troppo e come scoprirlo
Guida pratica per trovare quale richiesta causa il 504, su Nginx+PHP-FPM e su cPanel, con i comandi esatti e perché alzare il timeout quasi sempre non risolve.
Redazione UptimeMag · 8 ottobre 2026 · 6 minuti di lettura

La verifica più rapida: guarda l'ora esatta dell'errore
Prima di leggere la teoria, fai questo. Prendi l'ora precisa in cui è comparso il 504 (dal browser, da un monitor esterno o dall'access log) e cerca quello stesso minuto nel log di errore del server. Su Ubuntu 24.04 con Nginx il percorso di default è /var/log/nginx/error.log (confermato dalla documentazione ufficiale nginx). Il comando:
sudo grep "2026/10/08 1" /var/log/nginx/error.log
Su cPanel il log di Nginx non esiste (si usa Apache/LiteSpeed); il file da guardare è /usr/local/apache/logs/error_log per le installazioni EasyApache 3, oppure /etc/apache2/logs/error_log su EasyApache 4. Se vedi una riga che contiene upstream timed out hai già la causa tecnica: un backend non ha risposto in tempo. Se non vedi nulla, il problema sta più a monte (load balancer del provider, firewall, rete) e lo spieghiamo in fondo.
502 e 504, la differenza in due righe
Il 502 vuol dire che il proxy ha ricevuto una risposta sporca o nessuna connessione dall'upstream (il processo PHP è morto, la porta non risponde). Il 504 vuol dire che la connessione c'era, ma nessuno ha risposto entro il tempo massimo. Il 502 è un upstream rotto, il 504 è un upstream lento.
Dove stanno i timeout, e chi scade per primo
In una richiesta PHP dietro Nginx ci sono almeno tre timer indipendenti, in cascata:
| Livello | Direttiva | Valore di default |
|---|---|---|
| Nginx (proxy verso PHP-FPM) | fastcgi_read_timeout / proxy_read_timeout |
60 secondi |
| PHP-FPM (singola richiesta) | request_terminate_timeout |
0 = disattivato |
| MySQL (query lenta, solo log, non blocco) | long_query_time |
10 secondi |
Il dato su Nginx è confermato da più fonti tecniche indipendenti, che concordano su un default di 60 secondi per proxy_read_timeout. Il dato su PHP-FPM l'ho letto direttamente nel manuale ufficiale PHP, dove request_terminate_timeout ha valore di default 0, cioè "Off". Questo significa una cosa scomoda: se il tuo script PHP resta bloccato 10 minuti (una query senza indice, una chiamata esterna che non risponde), PHP-FPM non lo uccide da solo. È Nginx a stancarsi per primo, dopo 60 secondi, e a restituire il 504. Il processo PHP-FPM però resta lì, occupato, finché non finisce da solo o finché non esaurisci i worker disponibili.
Su MySQL il discorso è diverso: long_query_time serve solo a registrare le query lente nello slow query log, non le interrompe. Il minimo e il default di long_query_time sono 0 e 10 secondi rispettivamente, e di norma il registro delle query lente è disabilitato di default.
Come trovare la richiesta lenta — Nginx + PHP-FPM su Ubuntu 24.04
Primo passo, il log di errore di Nginx. Il messaggio tipico è quello che la documentazione tecnica riporta come riga standard di questi eventi: "upstream timed out (110: Connection timed out) while reading response header from upstream". Quella riga ti dice anche l'URL richiesto e l'IP del backend, quindi sai subito quale pagina ha causato il timeout.
Se il log di Nginx non basta (magari perché il timeout è scaduto lato PHP-FPM prima ancora che Nginx finisse di aspettare, cosa rara ma possibile con timeout configurati male), guarda lo slowlog di PHP-FPM. Non è attivo di default: va abilitato nel file di pool, tipicamente /etc/php/8.3/fpm/pool.d/www.conf su Ubuntu 24.04 con PHP 8.3, aggiungendo:
request_slowlog_timeout = 10s
slowlog = /var/log/php8.3-fpm-slow.log
Dopo aver modificato il file, ricarica il servizio:
sudo systemctl reload php8.3-fpm
Da quel momento, ogni richiesta che supera 10 secondi finisce nello slowlog con lo stack trace PHP completo: funzione, file, riga. È il modo più diretto per capire se il collo di bottiglia è una query, una chiamata HTTP esterna o un ciclo infinito nel codice.
Come trovare la richiesta lenta — cPanel
Su cPanel con PHP-FPM attivo per l'account, il file di slowlog per utente è già tracciato dal sistema: si trova in /var/cpanel/php-fpm/USERNAME/logs/slow.log (sostituisci USERNAME con l'utente cPanel reale). Se il sito usa ancora PHP come modulo Apache (mod_php) invece di PHP-FPM, questo file non esiste: in quel caso l'unica traccia utile è il log generico di Apache, /usr/local/apache/logs/error_log, che però non mostra lo stack trace, solo l'URL e l'orario.
Per sapere quale motore PHP sta usando il tuo account, in WHM vai su MultiPHP Manager: se nella colonna del dominio compare "PHP-FPM" attivo, lo slowlog per-utente è disponibile e vale la pena attivarlo (in MultiPHP INI Editor, voce request_slowlog_timeout, impostala a un valore inferiore al timeout di Apache/Nginx davanti, ad esempio 10s se il gateway timeout è 60s).
Le cause più frequenti, in ordine
1. Query senza indice o lock lungo. È la causa più comune su siti con CMS (WooCommerce, cataloghi grandi, report). Si riconosce perché nello slowlog PHP lo stack trace finisce dentro una chiamata a mysqli_query o a un ORM, e il log lento di MySQL (se attivo) mostra la stessa query con Rows_examined molto alto rispetto a Rows_sent. Si risolve con EXPLAIN sulla query e aggiungendo l'indice mancante, non toccando i timeout.
2. Import, export o cron pesanti lanciati da una richiesta HTTP. Si riconosce perché l'URL nello slowlog è sempre lo stesso endpoint (/admin/import.php, /export/csv) e la richiesta è manuale, non periodica. La soluzione corretta è spostare il lavoro in background (coda, cron da riga di comando) e far rispondere subito la pagina con "elaborazione in corso".
3. Chiamata a un servizio esterno che non risponde. Lo stack trace nello slowlog mostra una funzione come curl_exec o file_get_contents su un URL esterno (gateway di pagamento, API terze, webhook). Si risolve impostando un timeout breve lato codice (CURLOPT_TIMEOUT) così è l'applicazione a fallire in fretta, non Nginx a bloccare tutto per 60 secondi.
4. Backup o snapshot che satura I/O e CPU nello stesso momento. Si riconosce perché i 504 compaiono a orari fissi (es. le 3 di notte) e colpiscono richieste qualsiasi, non un endpoint specifico. Si risolve spostando la finestra di backup o limitando l'I/O del processo di backup (ionice), non alzando il timeout del gateway.
Perché alzare il timeout è la soluzione sbagliata (tranne due casi)
Alzare proxy_read_timeout o fastcgi_read_timeout non rende la query più veloce: tiene solo il visitatore e il worker PHP in attesa più a lungo, occupando una connessione e un processo che in quel momento non stanno servendo nessun altro. Su un server con un numero finito di worker PHP-FPM (pm.max_children), bastano pochi di questi "blocchi lunghi" in parallelo per saturare il pool e far apparire 502 e 504 anche su richieste normalissime.
I due casi in cui alzare il timeout è legittimo:
- Operazioni amministrative pianificate e uniche (import massivo una tantum, migrazione dati), su un endpoint separato e isolato dal traffico normale, con timeout alzato solo per quella
locationin Nginx e non globalmente. - Integrazioni verso servizi esterni dichiaratamente lenti per natura (generazione PDF complessa, rendering video, chiamate a provider che dichiarano tempi di risposta oltre i 60 secondi), a patto che il codice gestisca comunque un timeout interno più basso per non restare appeso indefinitamente.
In entrambi i casi il timeout va alzato solo sulla location specifica, mai nel blocco http globale.
Come verificare che è risolto
Dopo l'intervento (indice aggiunto, lavoro spostato in coda, timeout interno sul servizio esterno), rifai la stessa richiesta che prima falliva e controlla due cose: che non compaiano più righe upstream timed out nel log di Nginx per quell'URL, e che il tempo di risposta misurato (con curl -o /dev/null -s -w "%{time_total}\n" https://tuosito.it/pagina) sia stabilmente sotto il timeout configurato, non appena sotto per un pelo. Se lo slowlog PHP era attivo, verifica che smetta di registrare quell'endpoint.
Se il 504 può essere colpa del fornitore
Se il log di Nginx o di Apache non mostra nessuna riga di timeout in corrispondenza dell'errore, il problema è probabilmente a monte: un load balancer o una CDN del provider con un timeout più corto del tuo, o un firewall che taglia connessioni lunghe. In questo caso apri un ticket all'assistenza allegando: l'URL esatto, l'ora precisa (con fuso orario) in cui è comparso il 504, l'IP del client se disponibile, e l'esito del controllo sul tuo log locale ("nessuna riga di timeout nel nostro error log in quell'intervallo"). Questo permette al provider di controllare i propri log di edge senza dover fare domande di ritorno, e accorcia il tempo di risposta del ticket.
Testo redatto con il supporto dell'intelligenza artificiale e verificato dalla redazione (AI Act, art. 50).