Codice di errore 500 in Apache dopo il riavvio di PHP-FPM è un caso operativo tipico: un riavvio programmato, una patch di sicurezza o un deployment automatico — e dopo i punti di accesso PHP RESTituiscono improvvisamente HTTP 500 generici. Nella maggior parte dei casi la causa risiede al punto di integrazione tra Apache (web server) e PHP-FPM (FastCGI Process Manager). FastCGI è il protocollo per il passaggio delle richieste HTTP ai processi PHP; per socket si intende qui un file di socket di dominio Unix o una porta TCP. I pool sono gruppi di processi FPM con impostazioni dedicate.
Codice di errore 500 in Apache dopo il riavvio di PHP-FPM: Ursachen & Vorgehen
HTTP 500 è una risposta aggregata del web server e significa: la chiamata al backend è fallita o è stata interrotta. In un setup PHP-FPM le cause tipiche sono: socket/porta non raggiungibile, proprietà/permessi errati, Mandatory-Access-Control (SELinux/AppArmor), timeout al cold start, o una dimensionamento inadeguato del pool. Questo contributo mostra un ordine di verifica prioritario, comandi concreti e misure sostenibili — con focus su esercizio, monitoring e rollback.
Kurzcheck: Stimmen Zeitpunkt und Ursache?
Verificate prima se il codice 500 coincide effettivamente con il riavvio di PHP-FPM. Altrimenti rischiate di spendere tempo sulla componente sbagliata (es. database, rete o storage).
Typische Indikatoren für FPM-/FastCGI-Probleme
- Apache-Error-Log: voci con „proxy_fcgi“, „AH01079“, „AH02454“, „Connection refused“ o „Primary script unknown“.
- FPM-Logs/journal: assenza di „ready to handle connections“ o errori di bind/listen.
- I contenuti statici vengono serviti, gli endpoint PHP dinamici no.
Pragmatische Prüfreihenfolge (Runbook)
Lavorate in sequenza: Dienste/Logs → Socket/Port → Apache-Config → Rechte/Policies → Ressourcen/Timeouts → Pool-Parameter. Documentate ogni evidenza per il ticket dell’incidente.
1) Dienste und Logs parallel prüfen
journald fornisce indicazioni rapide, integrate dai log di Apache e dai file di log di FPM.
systemctl status apache2 --no-pager || systemctl status httpd --no-pager
systemctl status php-fpm --no-pager || systemctl status php8.2-fpm --no-pager
journalctl -u php-fpm -n 200 --no-pager
journalctl -u apache2 -n 200 --no-pager || journalctl -u httpd -n 200 --no-pagerPerché: così individuate immediatamente errori di avvio, problemi di bind o voci „Permission denied“. Copiate righe di log precise nel ticket.
2) Socket/Port prüfen
Verificate se FPM ascolta sull’endpoint atteso: socket Unix o porta TCP (es. 127.0.0.1:9000).
ss -ltnp | grep -E 'php-fpm|:9000' || true
ss -lxnp | grep -E 'php-fpm|fpm' || true
ls -lah /run/php || true
find /run -maxdepth 3 -type s -name '*fpm*.sock' -ls 2>/dev/null | headPerché: dopo aggiornamenti i percorsi possono cambiare; Apache potrebbe puntare a un socket obsoleto. Se il socket esiste, il passo successivo è verificare permessi e policy.
3) Apache-Konfiguration anschauen
Identificate come Apache instrada le richieste PHP: mod_proxy_fcgi (consigliato) o mod_fcgid. I percorsi di destinazione corrispondono alla direttiva listen di FPM?
apache2ctl -M 2>/dev/null | grep -E 'proxy|fcgi' || httpd -M 2>/dev/null | grep -E 'proxy|fcgi'
apache2ctl -S 2>/dev/null || httpd -S 2>/dev/null
grep -R --line-number -E 'proxy_fcgi|SetHandler|FilesMatch|.sock|:9000' /etc/apache2 /etc/httpd 2>/dev/null | head -n 80Perché: spesso un vHost punta ancora a un socket vecchio. File di include configurati centralmente riducono le sorgenti di errore.
4) Permessi: proprietà del Socket, modalità e directory
Un Unix-Socket è un file con proprietario/gruppo/modalità. Apache gira ad esempio come www-data (Debian) o apache (RHEL). Se manca il bit di traversal sulle directory padre, Apache non può raggiungere il socket, anche se il socket stesso sembra accessibile.
# Beispiel: Socket prüfen
SOCK="/run/php/php-fpm.sock" # anpassen
ls -lah "${SOCK}" 2>/dev/null || true
namei -l "${SOCK}" 2>/dev/null || true
# Apache-User ermitteln
ps -eo user,comm | awk '$2 ~ /apache2|httpd/ {print $1}' | sort -uPerché: /run è tmpfs; dopo il riavvio le directory di runtime vengono ricreate e richiedono impostazioni esplicite di proprietà/modalità, altrimenti la connessione non funziona.
Cause radice concrete e come risolverle in modo duraturo
Cambio del percorso del Socket (più versioni di PHP)
Con più versioni di PHP su un host, il nome del socket può cambiare facilmente. Stabilizzate i percorsi tramite elenchi univoci oppure assegnate per ogni vHost la versione PHP desiderata.
; Beispiel pool-Konfiguration
listen = /run/php/php-fpm.sock
listen.owner = www-data
listen.group = www-data
listen.mode = 0660Consiglio: Evitate che più pool utilizzino lo stesso socket — devono avere endpoint separati o porte TCP dedicate.
Permessi errati del Socket dopo il riavvio
Impostate listen.owner/listen.group/listen.mode nel file del pool; verificate che l’utente Apache sia membro del gruppo o adattate il gruppo.
# Apache in Gruppe aufnehmen (sorgfältig verwenden)
usermod -aG www-data apache 2>/dev/null || usermod -aG www-data www-data 2>/dev/null
systemctl reload apache2 || systemctl reload httpdPerché: una modalità temporanea 0666 risolve i problemi di accesso nel breve termine, ma aumenta la superficie d’attacco. È preferibile una proprietà esplicita e l’appartenenza al gruppo.
SELinux/AppArmor blocca le connessioni
Il Mandatory Access Control (MAC), come SELinux o AppArmor, può impedire l’accesso ai socket anche quando i permessi Unix sono corretti. Controllate le voci AVC o AppArmor-DENIED.
# SELinux prüfen
getenforce 2>/dev/null || true
ausearch -m avc -ts recent | tail -n 40 || true
# Falls SELinux aktiv ist: Socket-Context setzen
semanage fcontext -a -t httpd_var_run_t '/run/php(/.*)?' || true
RESTorecon -Rv /run/php || true
# AppArmor prüfen
aa-status 2>/dev/null || true
journalctl -k | grep -i apparmor | tail -n 40 || truePerché: le policy MAC sono molto efficaci, ma possono causare interruzioni di connessione per percorsi di runtime privi di label appropriate. Le modifiche alle policy devono passare per il change management; la disattivazione è ammessa solo temporaneamente.
Socket/porta obsolete o PID orfane
A volte un file socket rimane presente o un altro processo occupa la porta. Controllate con ss/lsof e pulite la situazione, ma eliminate i socket solo se nessun processo li sta utilizzando.
ss -ltnp | grep ':9000' || true
lsof /run/php/php-fpm.sock 2>/dev/null || true
# Wenn sicher: rm /run/php/php-fpm.sock && systemctl RESTart php-fpmPerché: la cancellazione avventata può interrompere connessioni attive. Verificate prima le informazioni sul PID.
Timeout, avvio a freddo di OpCache e bilanciatore di carico
Dopo un riavvio le cache sono vuote; le prime richieste richiedono più tempo. Se Apache o un bilanciatore di carico hanno timeout troppo brevi, le richieste vengono interrotte e i client vedono 500/502/504.
# Beispiel: Apache-Timeouts prüfen
apache2ctl -t -D DUMP_RUN_CFG 2>/dev/null | head -n 40 || true
# FPM: slowlog/request_terminate_timeout in Pool-Dateien prüfen
grep -R --line-number -E 'request_terminate_timeout|slowlog' /etc/php* 2>/dev/null | head -n 40Contromisure: aumentare moderatamente i timeout, eseguire il warmup di OpCache durante i deploy e prevedere una procedura di RESTart graduale: lasciare i pool riscaldare prima di consentire il traffico.
pm.max_children e gestione dei processi
Se sono disponibili troppo pochi worker, la coda si accumula. Dopo un riavvio i colli di bottiglia si manifestano immediatamente perché i worker si inizializzano. Dimensionate pm.max_children in base ai valori misurati di memoria e CPU.
pm = dynamic
pm.max_children = 40
pm.start_servers = 8
pm.min_spare_servers = 8
pm.max_spare_servers = 16
pm.max_requests = 500Perché: un valore troppo basso provoca rifiuti immediati; troppo alto sovraccarica il server. Misurate il consumo per worker e testate sotto carico.
Primary script unknown: problemi di percorso/chroot/open_basedir
Se FPM non riesce ad aprire lo script di destinazione, FPM riporta „Primary script unknown“ e Apache RESTituisce 500. Controllate DocumentRoot, il percorso del proxy, le impostazioni chroot o le RESTrizioni di open_basedir.
Pratica: script di troubleshooting e snippet per runbook
Integrazione con systemd: RuntimeDirectory e tmpfiles.d
systemd può garantire che /run/php esista con i permessi corretti prima dell’avvio. Utilizzate RuntimeDirectory nell’unit-file o una configurazione tmpfiles.d.
# Beispiel systemd-Override (speichern unter /etc/systemd/system/php-fpm.service.d/10-run.conf)
[Service]
RuntimeDirectory=php
RuntimeDirectoryMode=0755
RuntimeDirectoryPreserve=yes
# tmpfiles.d Alternative (z. B. /etc/tmpfiles.d/php-fpm.conf)
# d /run/php 0755 www-data www-data -
Perché: in questo modo la directory viene sempre creata con owner/mode corretti prima dell’avvio del servizio — evita le race condition al boot/riavvio.
Fallback a TCP: Configurazione & note
Come bypass diagnostico a breve termine, può aiutare passare da Unix-Socket a TCP (127.0.0.1:9000), poiché si aggirano molti problemi di permessi e MAC. A lungo termine tuttavia il TCP introduce latenza, controllo di accesso meno granulare e possibili collisioni di porta.
; php-fpm pool.conf
; unix socket
;listen = /run/php/php-fpm.sock
; TCP alternative
listen = 127.0.0.1:9000# Apache ProxyPassMatch Beispiel TCP
# In vHost
SetHandler "proxy:fcgi://127.0.0.1:9000"
Quando fallisce: se i firewall di infrastruttura applicano policy TCP locali o se più processi occupano la stessa porta.
Script di warmup OpCache (esempio semplice)
Un warmup scriptato può, durante il deploy o il riavvio, popolare le voci della OpCache e ridurre così le latenze da cold start.
#!/bin/bash
# opcache-warmup.sh - ruft eine Liste relevanter URLs sequentiell ab
URLS=( "/" "/login" "/app/home" )
HOST="https://localhost"
for u in "${URLS[@]}"; do
curl -ksS --fail "${HOST}${u}" >/dev/null || echo "Warmup failed for ${u}"
sleep 0.5
done
Perché: riduce i picchi di carico e i timeout alle prime richieste utente dopo il riavvio. Testatelo in staging.
Script di rollback rapido: commutare Socket ↔ TCP
#!/bin/bash
# rollback-to-tcp.sh - schaltet Pool auf TCP um und reloadet Dienste
POOL_CONF="/etc/php/8.2/fpm/pool.d/www.conf"
cp ${POOL_CONF} ${POOL_CONF}.bak.$(date +%s)
sed -i 's|listen = /run/php/php-fpm.sock|listen = 127.0.0.1:9000|' ${POOL_CONF}
systemctl RESTart php-fpm && systemctl reload apache2 || systemctl RESTart httpd
Perché: un rollback controllato minimizza i tempi di inattività. Testate lo script in un ambiente sicuro prima di impiegarlo in produzione.
Monitoraggio, allarmi e prevenzione
Integrate il monitoraggio generico dei 5xx con indicatori specifici: pattern nel log di errori di Apache (proxy_fcgi), statistiche del pool FPM (active processes, listen queue), allarmi per pm.max_children e metriche di sistema (RAM/IO). In questo modo distinguete gli effetti di cold start dai colli di bottiglia strutturali.
Raccomandazioni per gli alert
- Alert in caso di ripetute righe AH01079/AH02454 nel log errori di Apache in un breve intervallo di tempo.
- FPM: alert se la listen queue > 0 in modo persistente o se compare „reached pm.max_children“ nei log.
- Sistema: elevata utilizzazione di swap/I/O o voci dell’OOM-Killer immediatamente prima di casi 500.
Post-Incident: analisi della causa radice e misure preventive
Dopo una risoluzione temporanea eseguite sempre una RCA strutturata: quale modifica ha scatenato l’errore? È stato un aggiornamento, una modifica di configurazione o una race condition durante l’avvio? Adeguate il configuration management (Git), i template di change per i pool e gli override systemd e documentate le lezioni apprese nel runbook.
Checklist per un ticket di incidente (compatta)
- Orario del RESTart e durata dell’incidente
- Righe esatte del log errori di Apache
- Estratto del journal FPM intorno al RESTart
- Output di ss/ls/find per socket/porta
- Output di namei -l del percorso del socket
- SELinux/stato AppArmor e righe AVC/deny rilevanti
- Metriche brevi di memoria/IO/CPU
- Se il passaggio a TCP ha aiutato (sì/no)
Pratiche operative e conoscenze operative
- Versionate i file dei pool e gli include di Apache in Git; deployment solo tramite CI con test.
- Usate systemd RuntimeDirectory o tmpfiles.d, in modo che /run/php sia preparato correttamente.
- Considerate i label per SELinux precocemente nel processo di change, non in modo ad hoc.
- Implementate healthcheck e script di warmup per i RESTart.
- Testate gli script di rollback prima di documentarli come strumento di emergenza.
Conclusione
Un errore 500 dopo il RESTart di PHP-FPM è nella maggior parte dei casi un problema di integrazione all’interfaccia Apache ↔ PHP-FPM: socket/porta, ownership/mode, politiche MAC, timeout e dimensionamento del pool sono le cause tipiche. La soluzione sostenibile combina un’analisi immediata guidata dai log con misure permanenti: percorsi di socket stabili, ownership esplicita nei file dei pool, integrazione con systemd per i runtime directory, label SELinux/AppArmor adeguate, procedure di warmup e monitoraggio mirato. Inoltre meccanismi di rollback testati e runbook documentati riducono il rischio di incidenti successivi.
Usate i passaggi di verifica sopra come template per gli incidenti e dopo ogni interruzione redigete una RCA e un adeguamento delle policy. In questo modo il prossimo RESTart di PHP-FPM tornerà a essere un’operazione di routine.
Aspetti operativi: orchestrazione, healthcheck e container
I riavvii automatizzati tramite systemd, gestione della configurazione o orchestratori possono generare condizioni di race (Race‑Conditions) se i load balancer o i frontend non vengono posti in modalità drain. Pianificate riavvii scaglionati con fasi di drain e healthcheck (readiness/liveness), in modo che sessioni e connessioni in ingresso siano chiuse in modo controllato.
Systemd-Socket-Activation può essere qui un elemento stabile: l’unità socket mantiene l’endpoint attraverso i cicli di riavvio e riduce i casi di „Connection refused“. PRESTate però attenzione alle directory runtime e alla persistenza tmpfs.
Negli ambienti containerizzati i socket Unix su OverlayFS o in volumi montati sono più soggetti a problemi di permessi e di inode; verificate quindi i binding TCP o volumi condivisi dedicati con regole chiare di proprietà.
Migliorate l’osservabilità: correlate i log di Apache e FPM tramite Request‑IDs ed esportate le metriche del pool (listen‑queue, active) per un allertamento tempestivo.
Per questo tema sono importanti anche Apache Http 500 e Php-Fpm Socket. L’articolo inquadra questi aspetti in modo comprensibile e mostra cosa conta nella pratica quotidiana.