1,321 24/03/2026 07/04/2026 9 min

Su un server con più siti, il problema non è quasi mai “PHP non funziona”.

Il vero guasto arriva quando il pannello, il pool PHP-FPM e l’utente del sito non parlano la stessa lingua.

Il sintomo tipico è brutale: una home page che torna 502 Bad Gateway, un backend che non salva file, oppure log pieni di Permission denied.

In questo articolo confronto due approcci che cambiano davvero l’operatività: PHP-FPM dedicato per sito con utente separato e pool condiviso o semi-condiviso gestito dal pannello.

Li vedo spesso su cPanel, FastPanel, DirectAdmin e Plesk. Cambia l’interfaccia. Cambia anche il livello di isolamento che il pannello impone. Ma il conflitto è sempre lo stesso: chi esegue PHP, chi possiede i file, e chi può scrivere nella cartella giusta.

Il caso specifico che uso qui è questo: un sito WordPress in hosting multi-account, con upload bloccati dopo una migrazione. Il pannello mostrava tutto verde. Il sito però generava errori su wp-content/uploads e storage. Il motivo era un mismatch tra utente del virtual host, socket PHP-FPM e permessi del filesystem.

Prerequisiti

Servono accesso root o admin al server, accesso al pannello, e la possibilità di leggere i log PHP-FPM e web server.

È utile conoscere il nome dell’utente del sito. Nei pannelli cambia spesso:

  • cPanel: utente account, con pool dedicato o handler separati.
  • Plesk: utente di sistema per dominio, spesso con FPM per dominio.
  • DirectAdmin: utente account e configurazioni per dominio più manuali.
  • FastPanel: isolamento più semplice, ma meno flessibile nei dettagli.

Note: i comandi sotto sono pensati per Linux con systemd e PHP-FPM installato come servizio. I nomi dei socket e dei pool possono variare.

Warning: non cambiare i permessi con chmod -R 777. Risolve l’urgenza e crea un problema di sicurezza peggiore.

Step 1: capire chi sta scrivendo davvero i file

La prima verifica non riguarda il pannello. Riguarda l’utente effettivo che PHP usa per scrivere nel sito.

Questo serve perché un file creato da root, da apache o da un utente sbagliato rompe subito upload, cache e editor online.

Controlla proprietà e permessi delle directory critiche.

ls -ld /home/siteuser/public_html /home/siteuser/public_html/wp-content /home/siteuser/public_html/wp-content/uploads
stat -c '%U %G %a %n' /home/siteuser/public_html/wp-content/uploads

# Output: owner corretto, gruppo coerente, permessi scrivibili solo dove serve.

Se trovi un owner diverso dall’account del sito, il problema è già visibile. In hosting con pannello, spesso il file è stato creato da un processo FPM di un altro dominio o da una migrazione eseguita con privilegi errati.

Qui entrano i due approcci.

  • Approccio A: utente dedicato per il sito, con pool PHP-FPM separato. Massima coerenza e isolamento.
  • Approccio B: utente condiviso o modello più “semplificato” del pannello. Più rapido da gestire, ma più fragile nei conflitti di scrittura.

Se ospiti clienti diversi o applicazioni con requisiti di sicurezza diversi, l’Approccio A è quasi sempre quello giusto.

Se hai un singolo sito, un team piccolo, e vuoi ridurre la complessità operativa, l’Approccio B può andare bene, ma solo se controlli bene i permessi.

Step 2: verificare il pool PHP-FPM e il socket usato dal dominio

Molti errori “Permission denied” in realtà nascono dal pool sbagliato.

Il sito pensa di parlare con il proprio FPM, ma il web server punta a un socket diverso. Oppure il socket è corretto, ma il pool gira con un utente che non coincide con quello dei file.

Su sistemi con systemd puoi ispezionare i pool attivi.

systemctl list-units 'php*-fpm.service'
php-fpm -tt 2>&1 | head -n 30

# Output: elenco servizi FPM attivi e validazione sintassi configurazione.

Se usi Plesk o cPanel, spesso il pannello genera configurazioni per dominio. In quel caso cerca il pool del sito e controlla almeno questi parametri:

user = siteuser
group = siteuser
listen = /run/php-fpm-siteuser.sock
listen.owner = nginx
listen.group = nginx
pm = ondemand

# Output: pool dedicato con socket coerente e utente del sito allineato.

Il vantaggio del pool dedicato è chiaro. Il processo PHP eredita identità e limiti del sito. Se un account viene compromesso, il danno resta più contenuto.

Il rovescio della medaglia è la manutenzione. Hai più pool, più log, più consumi di RAM, e più punti da verificare dopo aggiornamenti del pannello.

Con un pool condiviso, la configurazione è più semplice da mantenere, ma ogni errore di ownership si propaga più facilmente. È la scelta che vedo preferire in ambienti piccoli o in server con molti siti statici e poche scritture.

Step 3: scegliere il modello di permessi giusto per il tipo di applicazione

Qui serve una distinzione pratica, non teorica.

Un CMS che scrive cache, media e file temporanei ha bisogno di permessi diversi da un sito vetrina quasi statico.

Per WordPress, Laravel, Magento o PrestaShop, il modello più robusto è quello in cui il sito scrive solo nelle directory necessarie. Tutto il resto resta read-only per l’utente FPM.

Un esempio minimale di assetto sano:

chown -R siteuser:siteuser /home/siteuser/public_html
find /home/siteuser/public_html -type d -exec chmod 755 {} \;
find /home/siteuser/public_html -type f -exec chmod 644 {} \;
chmod -R u+rwX /home/siteuser/public_html/wp-content/uploads

# Output: directory leggibili, file non eseguibili, upload scrivibili solo dove serve.

Note: se il pannello usa un gruppo condiviso per servizi interni, non forzare a mano ogni gruppo. Allinea prima il comportamento del pannello, poi i permessi reali.

Approccio A, con utente dedicato e FPM separato, conviene quando hai almeno una di queste condizioni:

  • più clienti sullo stesso server;
  • applicazioni con accessi FTP o SSH diversi;
  • necessità di audit più forte;
  • frequenti deploy che riscrivono file e cache;
  • rischio di escalation tra siti sullo stesso host.

Approccio B, con modello più condiviso, conviene quando:

  • hai un solo proprietario del server e pochi siti;
  • il carico è basso e i deploy sono semplici;
  • vuoi ridurre il numero di pool e socket da gestire;
  • ti serve una gestione rapida da pannello, senza molta personalizzazione.

Step 4: leggere il log giusto, non solo la pagina di errore

Se il sito mostra 500 o 502, il pannello spesso non basta. Devi passare subito ai log del web server e di PHP-FPM.

Le linee utili di solito sono queste:

journalctl -u php8.2-fpm -n 50 --no-pager
tail -n 50 /var/log/nginx/error.log
tail -n 50 /var/log/httpd/error_log

# Output: errore di accesso al socket, permesso negato o timeout upstream.

Un messaggio molto comune è questo:

connect() to unix:/run/php-fpm-siteuser.sock failed (13: Permission denied)

Qui il problema non è il codice PHP. È il socket letto dal web server con owner o mode sbagliati.

Un altro segnale tipico è:

Primary script unknown

In quel caso spesso il path del vhost non coincide con il path reale del document root, oppure il pannello ha rigenerato la configurazione con un alias errato.

Se lavori su Plesk, controlla anche che il dominio non abbia una configurazione PHP diversa da quella prevista. Se lavori su cPanel, verifica i selettori PHP e i template generati dall’hosting. Su DirectAdmin e FastPanel, il problema nasce spesso dopo update o restore di backup.

Step 5: decidere il confine tra sicurezza e praticità

Il punto non è “qual è il migliore in assoluto”. Il punto è dove vuoi mettere il costo operativo.

Con pool dedicato per sito, il pannello impone più coerenza e riduce il raggio d’azione di un incidente. Però devi monitorare più servizi e più file di configurazione.

Con modello condiviso, il pannello semplifica la vita all’amministratore. Però basta un deploy manuale, un restore incompleto o un plugin mal scritto per creare conflitti tra siti.

Se gestisci ambienti mission-critical, la mia regola pratica è questa:

  • pool dedicato per siti con dati sensibili o e-commerce;
  • permessi stretti e directory scrivibili solo dove serve;
  • log separati per dominio;
  • deploy automatizzato, mai upload manuale casuale via FTP;
  • verifica post-migrazione con owner, socket e test di scrittura.

Se invece il server è piccolo, il team è ridotto e il rischio principale è l’errore operativo, il modello condiviso può essere accettabile. Ma solo se accompagni il tutto con controlli ripetibili.

Verifica finale

Dopo aver scelto l’approccio, fai sempre questa prova pratica.

  1. Apri il sito e controlla che risponda senza errori 5xx.
  2. Carica un file piccolo nell’area admin o nella cartella prevista.
  3. Scrivi e poi leggi un file temporaneo dal percorso usato dall’applicazione.
  4. Rivedi owner e permessi sulle directory scrivibili.
  5. Confronta il socket PHP-FPM del dominio con il vhost reale.

Una verifica rapida utile è questa:

curl -I https://example.com
php -r 'file_put_contents("/home/siteuser/public_html/wp-content/uploads/test.txt", "ok\n");'
ls -l /home/siteuser/public_html/wp-content/uploads/test.txt

# Output: HTTP 200 o 301 atteso, file creato con owner coerente.

Se il file si crea ma il sito continua a fallire, il problema non è più il filesystem. È quasi sempre nel mapping tra vhost e pool FPM, oppure nella cache del pannello.

Troubleshooting

Errore 1: “connect() to unix:/run/php-fpm-siteuser.sock failed (13: Permission denied)”

Causa: il socket FPM non è leggibile dal processo web server, oppure i permessi del socket sono troppo stretti.

Fix:

grep -R "^listen\|^listen.owner\|^listen.group\|^listen.mode" /etc/php-fpm* /etc/php/*/fpm/pool.d/* 2>/dev/null
systemctl restart php8.2-fpm

# Output: socket con owner e mode coerenti, sito che riprende a collegarsi al pool.

Errore 2: “Primary script unknown”

Causa: il document root configurato nel pannello non coincide con il path reale del sito dopo migrazione o restore.

Fix:

grep -R "root\|DocumentRoot\|vhost" /etc/nginx /etc/httpd /var/www/vhosts 2>/dev/null | head -n 40

# Output: path corretto del dominio, da riallineare nel pannello e nel template vhost.

Errore 3: “Failed to open stream: Permission denied”

Causa: PHP gira con un utente corretto, ma la directory di destinazione è stata lasciata con owner sbagliato o con permessi troppo restrittivi.

Fix:

chown -R siteuser:siteuser /home/siteuser/public_html/wp-content
find /home/siteuser/public_html/wp-content -type d -exec chmod 755 {} \;
find /home/siteuser/public_html/wp-content -type f -exec chmod 644 {} \;

# Output: scrittura ripristinata nelle sole cartelle necessarie.

Conclusione

Il vero discrimine non è il nome del pannello. È il livello di isolamento che vuoi ottenere tra sito, pool PHP-FPM e permessi utente.

Se devi proteggere più account o applicazioni sensibili, scegli pool dedicato e utente separato. Se vuoi semplicità operativa e hai pochi siti, il modello condiviso può bastare, ma va governato con controlli stretti.

Il prossimo passo concreto è creare una checklist di post-migrazione con tre voci fisse: owner dei file, socket FPM del dominio, e test di scrittura su una directory reale.