Risolvere i problemi di timeout PHP su LiteSpeed
Durante l’esecuzione di alcuni script PHP può capitare che un’operazione richieda più tempo rispetto ai normali limiti previsti dal server. Succede, ad esempio, durante l’importazione di grandi quantità di dati, il ripristino di un backup, la migrazione di un sito WordPress oppure l’esecuzione di processi pianificati particolarmente complessi.
Tra gli strumenti che possono richiedere tempi di elaborazione più lunghi rientrano plugin come BackupBuddy, ImportBuddy, WP All Import e, più in generale, tutte le applicazioni che utilizzano il sistema cron integrato in WordPress. Anche operazioni come la ricostruzione degli indici MySQL, la generazione di archivi compressi o l’elaborazione di numerosi file possono mantenere uno script PHP attivo per diversi minuti.
Quando il tempo massimo consentito viene superato, il processo può essere interrotto prima del completamento. In base alla configurazione del server e dell’applicazione, si possono visualizzare errori come:
Maximum execution time exceeded;504 Gateway Timeout;- una pagina bianca;
- un’importazione che si interrompe;
- un backup che rimane incompleto;
- un processo cron che non termina correttamente.
In generale, non è consigliabile consentire a uno script PHP di rimanere in esecuzione senza alcun limite. Un processo bloccato o scritto in modo inefficiente può occupare memoria, CPU e connessioni al database, incidendo sulle prestazioni del sito e del server.
Per questo motivo PHP e LiteSpeed Web Server integrano diversi sistemi di protezione. La modifica di una sola impostazione potrebbe non essere sufficiente, perché il processo può essere interrotto da PHP, dal web server oppure dalla chiusura della connessione HTTP.
Prima di applicare le configurazioni riportate di seguito è quindi opportuno verificare che lo script sia realmente destinato a eseguire un’operazione lunga e che il problema non dipenda da codice inefficiente, query lente o chiamate esterne che non restituiscono una risposta.
Il timeout PHP e il timeout di LiteSpeed
Il parametro PHP più conosciuto è max_execution_time, che indica per quanto tempo uno script può essere eseguito prima che PHP ne interrompa l’elaborazione.
Aumentare questo valore, tuttavia, non sempre risolve il problema. LiteSpeed può infatti applicare ulteriori controlli sulla richiesta e terminare il processo quando la connessione con il client viene chiusa oppure quando non viene restituito alcun dato per un determinato periodo.
Si devono quindi distinguere almeno tre situazioni:
- PHP interrompe lo script perché è stato raggiunto il valore di
max_execution_time. - LiteSpeed termina il processo perché il client ha chiuso la connessione.
- LiteSpeed chiude la connessione perché lo script non restituisce dati entro il timeout previsto.
Le direttive illustrate nei paragrafi successivi intervengono principalmente sul secondo e sul terzo caso.
Disattivare il Broken Connection Aborting
Quando il client chiude una connessione, LiteSpeed può terminare lo script PHP associato alla richiesta. La chiusura può avvenire, ad esempio, quando viene chiusa la scheda del browser, si interrompe una richiesta AJAX oppure l’applicazione avvia un processo senza attendere la risposta completa.
Questo comportamento evita che il server continui a utilizzare risorse per elaborare una risposta che il client non riceverà più. Si tratta anche di una misura utile per limitare alcuni tipi di abuso e di attacchi DoS.
In alcuni casi, però, è necessario che lo script continui a essere eseguito anche dopo la chiusura della connessione.
Un esempio è rappresentato dal cron integrato di WordPress. Il sistema può avviare una richiesta verso wp-cron.php e chiudere la connessione senza attendere che tutte le operazioni pianificate siano state completate. Se LiteSpeed termina anche il processo PHP, alcune attività cron potrebbero non essere eseguite correttamente.
Per evitare questo comportamento si può utilizzare la variabile di ambiente LiteSpeed noabort.
Quando noabort è attiva per una richiesta, LiteSpeed non termina automaticamente lo script PHP in seguito alla chiusura della connessione da parte del client.
Configurare noabort tramite .htaccess
La variabile può essere impostata tramite una regola di riscrittura nel file .htaccess.
Poiché si tratta di una direttiva specifica di LiteSpeed, è consigliabile racchiudere la configurazione all’interno di un blocco IfModule. In questo modo le regole vengono elaborate solamente quando il sito utilizza LiteSpeed Web Server.

Applicare noabort a tutte le richieste
Per impedire l’interruzione degli script su tutte le richieste del sito si può utilizzare:
<IfModule LiteSpeed>
RewriteEngine On
RewriteRule .* - [E=noabort:1]
</IfModule>
La configurazione deve essere posizionata nella parte iniziale del file .htaccess, prima di eventuali regole che potrebbero intercettare o terminare la riscrittura della richiesta.
Questa soluzione va utilizzata con cautela. Applicare noabort a tutte le richieste permette infatti a qualsiasi script di continuare l’esecuzione anche quando il client non è più connesso.
È quindi preferibile limitare la regola ai soli file che richiedono realmente questo comportamento.
Applicare noabort solo ad alcuni script
Per applicare la variabile esclusivamente a wp-cron.php, backupbuddy.php e importbuddy.php si può utilizzare:
<IfModule LiteSpeed>
RewriteEngine On
RewriteRule ^(wp-cron|backupbuddy|importbuddy)\.php$ - [E=noabort:1]
</IfModule>
La regola viene applicata solamente quando la richiesta corrisponde esattamente a uno dei file indicati.
Nel caso in cui lo script si trovi all’interno di una sottocartella, la regola deve essere adattata al percorso effettivo.
Per applicare la configurazione solamente al file wp-cron.php presente nella directory principale di WordPress si può utilizzare:
<IfModule LiteSpeed>
RewriteEngine On
RewriteRule ^wp-cron\.php$ - [E=noabort:1]
</IfModule>
Sovrascrivere il timeout di connessione di LiteSpeed
Un altro problema può verificarsi quando uno script impiega molto tempo a completare l’elaborazione senza restituire dati al client.
Il processo PHP potrebbe essere ancora attivo, ma LiteSpeed può considerare la connessione inattiva e chiuderla. Questo comportamento serve a impedire che script bloccati o scritti in modo inefficiente mantengano aperte le connessioni del server per un periodo eccessivo.
Per evitare il timeout della connessione è possibile utilizzare la variabile di ambiente LiteSpeed noconntimeout.
Questa variabile indica a LiteSpeed di non applicare il normale timeout di connessione alla richiesta interessata.
noconntimeout non deve essere confusa con noabort. La prima evita che LiteSpeed applichi il timeout alla connessione, mentre la seconda consente al processo PHP di continuare anche quando il client ha già interrotto la connessione.
In base al comportamento dell’applicazione può essere necessario utilizzare una sola variabile oppure entrambe.
Configurare noconntimeout tramite .htaccess
Applicare noconntimeout a tutte le richieste
Per disattivare il timeout di connessione su tutte le richieste si può utilizzare:
<IfModule LiteSpeed>
RewriteEngine On
RewriteRule .* - [E=noconntimeout:1]
</IfModule>
Anche in questo caso la configurazione globale va utilizzata solamente quando è realmente necessaria. Uno script bloccato potrebbe infatti mantenere occupato un processo PHP per molto tempo.
Applicare noconntimeout solo ad alcuni script
Per limitare la configurazione a wp-cron.php, backupbuddy.php e importbuddy.php si può utilizzare:
<IfModule LiteSpeed>
RewriteEngine On
RewriteRule ^(wp-cron|backupbuddy|importbuddy)\.php$ - [E=noconntimeout:1]
</IfModule>
Per applicarla solamente al cron di WordPress:
<IfModule LiteSpeed>
RewriteEngine On
RewriteRule ^wp-cron\.php$ - [E=noconntimeout:1]
</IfModule>
Combinare noabort e noconntimeout
Quando uno script deve continuare a essere eseguito anche se il client chiude la connessione e, contemporaneamente, non deve essere interrotto dal timeout di LiteSpeed, le due variabili possono essere inserite nella stessa regola.
Per applicarle a wp-cron.php, backupbuddy.php e importbuddy.php:
<IfModule LiteSpeed>
RewriteEngine On
RewriteRule ^(wp-cron|backupbuddy|importbuddy)\.php$ - [E=noabort:1,E=noconntimeout:1]
</IfModule>
Per applicarle solamente a wp-cron.php:
<IfModule LiteSpeed>
RewriteEngine On
RewriteRule ^wp-cron\.php$ - [E=noabort:1,E=noconntimeout:1]
</IfModule>
È possibile applicare entrambe le variabili anche a tutte le richieste:
<IfModule LiteSpeed>
RewriteEngine On
RewriteRule .* - [E=noabort:1,E=noconntimeout:1]
</IfModule>
La regola globale deve essere considerata una soluzione eccezionale. In condizioni normali è preferibile indicare solamente gli script che necessitano di un tempo di esecuzione prolungato.
Dove inserire le regole nel file .htaccess
Le regole devono essere inserite nel file .htaccess presente nella document root del sito, generalmente la stessa directory in cui si trovano file come wp-config.php e wp-cron.php.
Nel caso di WordPress, è consigliabile posizionare la configurazione prima del blocco generato automaticamente dal CMS, cioè prima della riga:
# BEGIN WordPress
Un esempio completo può essere il seguente:
<IfModule LiteSpeed>
RewriteEngine On
RewriteRule ^wp-cron\.php$ - [E=noabort:1,E=noconntimeout:1]
</IfModule>
# BEGIN WordPress
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
RewriteBase /
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
</IfModule>
# END WordPress
Prima di modificare il file è consigliabile crearne una copia di sicurezza. Un errore di sintassi nel file .htaccess può causare un errore HTTP 500 e rendere temporaneamente irraggiungibile il sito.
Aumentare max_execution_time
Le variabili noabort e noconntimeout controllano il comportamento di LiteSpeed, ma non modificano direttamente il limite massimo configurato in PHP.
Se lo script viene interrotto con un messaggio simile al seguente:
Maximum execution time of 30 seconds exceeded
può essere necessario aumentare anche il valore di max_execution_time.
In base alla configurazione del servizio hosting, il parametro può essere modificato dal pannello di controllo, dal file php.ini, dal file .user.ini oppure attraverso altri strumenti messi a disposizione dal provider.
Un esempio per il file .user.ini è:
max_execution_time = 300
Il valore è espresso in secondi. Nell’esempio lo script può essere eseguito per un massimo di cinque minuti.
Su alcune configurazioni può essere disponibile anche la direttiva nel file .htaccess:
php_value max_execution_time 300
Questa sintassi non è supportata in tutti gli ambienti PHP e può generare un errore HTTP 500. Va quindi utilizzata solamente quando il server consente le direttive php_value nel file .htaccess.
L’aumento di max_execution_time non sostituisce necessariamente le regole LiteSpeed. Se il processo viene terminato a causa della chiusura della connessione, potrebbe essere comunque necessario utilizzare noabort. Se invece interviene il timeout della connessione del web server, potrebbe essere necessario aggiungere noconntimeout.
Verificare la causa del timeout
Prima di modificare la configurazione è utile controllare i log degli errori PHP e del web server.
Nel caso di un limite PHP si possono trovare messaggi come:
PHP Fatal error: Maximum execution time of 30 seconds exceeded
Se il problema dipende da LiteSpeed, il log può mostrare la terminazione della richiesta o del processo LSAPI. In altri casi il timeout può essere generato da un reverse proxy, da una CDN oppure da un servizio esterno posizionato davanti al server.
Un errore HTTP 504, quindi, non indica automaticamente un problema con max_execution_time.
Si deve verificare quale componente sta chiudendo la connessione:
- PHP;
- LiteSpeed Web Server;
- un reverse proxy;
- una CDN;
- il browser o il client;
- un servizio esterno utilizzato dallo script.
Quando è disponibile l’accesso ai log, il messaggio registrato permette generalmente di distinguere un timeout generato da PHP da una chiusura applicata dal web server.
Timeout causati da proxy e CDN
Anche dopo aver aumentato i limiti PHP e applicato le variabili di ambiente di LiteSpeed, la richiesta può essere interrotta da un componente esterno.
Una CDN o un reverse proxy può avere un proprio tempo massimo di attesa. Se lo script non restituisce una risposta entro tale limite, il servizio intermedio può mostrare un errore 504 o interrompere la connessione, anche se il processo PHP continua a essere eseguito sul server.
In questa situazione la modifica del file .htaccess non cambia il limite imposto dal servizio esterno. Si deve quindi verificare la configurazione della CDN, del proxy o del bilanciatore di carico utilizzato.
Se il limite del servizio non può essere aumentato, l’operazione lunga dovrebbe essere eseguita in background oppure suddivisa in più richieste di durata inferiore.
Quando non conviene rimuovere il timeout
La rimozione del timeout non deve essere utilizzata per nascondere problemi di prestazioni.
Se un’importazione rimane bloccata, una query MySQL richiede diversi minuti oppure un plugin esegue un ciclo infinito, consentire al processo di continuare senza limiti può aumentare il consumo di risorse e peggiorare la stabilità del sito.
Prima di aumentare i valori è opportuno controllare:
- la presenza di errori nei log PHP;
- il consumo di memoria del processo;
- le query MySQL lente;
- le chiamate verso servizi esterni;
- la dimensione dei file elaborati;
- la presenza di processi cron sovrapposti;
- eventuali limiti imposti dal piano hosting.
Quando possibile, le operazioni lunghe dovrebbero essere suddivise in più passaggi oppure eseguite tramite processi in background.
Nel caso di WordPress può essere utile sostituire il cron interno con un cron di sistema che richiami periodicamente wp-cron.php. In questo modo l’esecuzione delle attività pianificate non dipende dalle visite ricevute dal sito e può essere gestita in maniera più prevedibile.
Applicare le regole solo dove necessario
È preferibile applicare le eccezioni solamente agli script che necessitano realmente di tempi di esecuzione prolungati, evitando regole generiche come:
RewriteRule .* - [E=noabort:1,E=noconntimeout:1]
Una configurazione selettiva riduce il rischio che script non previsti rimangano in esecuzione per un periodo eccessivo.
Per esempio, se il problema riguarda solamente il cron di WordPress, è sufficiente utilizzare:
<IfModule LiteSpeed>
RewriteEngine On
RewriteRule ^wp-cron\.php$ - [E=noabort:1,E=noconntimeout:1]
</IfModule>
Se invece il timeout riguarda uno script personalizzato, si deve indicare il nome e il percorso effettivo del file.
Per uno script chiamato importazione.php presente nella directory principale del sito:
<IfModule LiteSpeed>
RewriteEngine On
RewriteRule ^importazione\.php$ - [E=noabort:1,E=noconntimeout:1]
</IfModule>
Se il file si trova nella directory scripts:
<IfModule LiteSpeed>
RewriteEngine On
RewriteRule ^scripts/importazione\.php$ - [E=noabort:1,E=noconntimeout:1]
</IfModule>
Conclusioni
I timeout degli script PHP su LiteSpeed possono dipendere da più livelli della configurazione.
max_execution_time controlla il tempo massimo previsto da PHP. La variabile noabort impedisce a LiteSpeed di terminare lo script quando il client chiude la connessione. La variabile noconntimeout evita invece che il web server applichi il normale timeout di connessione alla richiesta.
Nei casi in cui uno script debba proseguire indipendentemente dallo stato della connessione si possono combinare entrambe le variabili:
<IfModule LiteSpeed>
RewriteEngine On
RewriteRule ^wp-cron\.php$ - [E=noabort:1,E=noconntimeout:1]
</IfModule>
La configurazione deve essere limitata agli script che necessitano realmente di tempi di esecuzione prolungati. Prima di aumentare o rimuovere i timeout è sempre opportuno controllare i log e verificare che l’applicazione non presenti errori, query lente o processi bloccati.



