IT-Admin.tech

Code d'erreur 500 dans Apache après redémarrage de PHP-FPM : analyser les causes et corriger durablement

Architekturdiagramm: Apache über Unix-Socket verbunden mit PHP-FPM, ergänzt durch Logauszug mit AH01079 und Prüfliste
Fehlerursachen an der Schnittstelle Apache ↔ PHP-FPM: Socket-Pfad, Rechte, MAC-Policies und Timeouts kontrollieren.

Code d’erreur 500 dans Apache après redémarrage de PHP-FPM est un cas d’exploitation typique : un redémarrage planifié, un correctif de sécurité ou un déploiement automatique — et ensuite des endpoints PHP renvoient soudainement des HTTP 500 génériques. Dans la plupart des cas, la cause se situe à la jonction d’intégration entre Apache (serveur web) et PHP-FPM (FastCGI Process Manager). FastCGI est le protocole de transmission des requêtes HTTP aux processus PHP ; « socket » désigne ici soit un fichier de socket de domaine Unix, soit un port TCP. Les pools sont des groupes de processus FPM avec leurs propres réglages.

Code d’erreur 500 dans Apache après redémarrage de PHP-FPM: causes & démarche

HTTP 500 est une réponse générique du serveur web et signifie : l’appel vers le backend a échoué ou a été interrompu. Dans une configuration PHP-FPM, les causes typiques sont : socket/port injoignable, propriété/permissions incorrectes, Mandatory Access Control (SELinux/AppArmor), timeouts au démarrage à froid, ou un dimensionnement inadapté des pools. Cet article présente un ordre de vérification priorisé, des commandes concrètes et des mesures durables — avec un focus sur l’exploitation, le monitoring et le rollback.

Vérification rapide : le moment et la cause correspondent-ils ?

Vérifiez d’abord si le 500 coïncide réellement avec le redémarrage de PHP-FPM. Sinon, vous risquez d’investir du temps sur le composant erroné (p. ex. base de données, réseau ou stockage).

Indicateurs typiques de problèmes FPM/FastCGI

  • Journal des erreurs Apache : messages contenant „proxy_fcgi“, „AH01079“, „AH02454“, „Connection refused“ ou „Primary script unknown“.
  • Logs FPM/journal : absence de „ready to handle connections“ ou erreurs de bind/listen.
  • Les contenus statiques sont servis, les endpoints PHP dynamiques ne le sont pas.

Ordre de vérification pragmatique (Runbook)

Travaillez séquentiellement : services/logs → socket/port → config Apache → droits/politiques → ressources/timeouts → paramètres de pool. Documentez chaque constat dans le ticket d’incident.

1) Vérifier services et logs en parallèle

journald fournit des indices rapides, complété par le journal des erreurs Apache et les fichiers de log FPM.

Shell
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-pager

Pourquoi : ainsi vous voyez immédiatement les erreurs de démarrage, les problèmes de bind ou les „Permission denied“. Copiez des lignes de log précises dans le ticket.

2) Vérifier le socket/port

Vérifiez si FPM écoute sur l’endpoint attendu : socket Unix ou port TCP (p. ex. 127.0.0.1:9000).

Shell
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 | head

Pourquoi : après des mises à jour, les chemins peuvent changer ; Apache peut pointer vers un ancien socket. Si le socket existe, l’étape suivante est la vérification des droits et des politiques.

3) Examiner la configuration d’Apache

Déterminez comment Apache transfère les appels PHP : mod_proxy_fcgi (recommandé) ou mod_fcgid. Les chemins cibles correspondent-ils au paramètre ‚listen‘ de FPM ?

Shell
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 80

Pourquoi : fréquemment, un vHost pointe encore vers un ancien socket. Des fichiers d’inclusion centralisés réduisent les sources d’erreur.

4) Rechte: Socket-Besitz, Modi und Verzeichnisse

Ein Unix-Socket ist eine Datei mit Owner/Group/Mode. Apache läuft z. B. als www-data (Debian) oder apache (RHEL). Fehlt das Traversal-Bit auf Elternverzeichnissen, kann Apache den Socket nicht erreichen, auch wenn der Socket selbst offen aussieht.

Shell
# 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 -u

Warum: /run ist tmpfs; nach RESTart entstehen Runtime-Verzeichnisse neu und benötigen explizite Besitz-/Modus-Einstellungen, sonst stimmt die Verbindung nicht.

Konkrete Root Causes und wie man sie nachhaltig behebt

Socket-Pfadwechsel (Mehrere PHP-Versionen)

Bei mehreren PHP-Versionen auf einem Host ändert sich leicht der Socket-Name. Stabilisieren Sie Pfade durch eindeutige Listen oder ordnen Sie pro vHost die gewünschte PHP-Version zu.

Ini
; Beispiel pool-Konfiguration
listen = /run/php/php-fpm.sock
listen.owner = www-data
listen.group = www-data
listen.mode = 0660

Tipp: Vermeiden Sie, dass mehrere Pools denselben Socket verwenden — sie brauchen eigene Endpoints oder TCP-Ports.

Falsche Socket-Rechte nach RESTart

Setzen Sie listen.owner/listen.group/listen.mode in der Pool-Datei; prüfen Sie, dass der Apache-User Mitglied in der Gruppe ist oder passen Sie die Group an.

Shell
# 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 httpd

Warum: Ein temporärer Modus 0666 löst kurzfristig Zugriffsprobleme, erhöht aber Angriffsfläche. Besser ist eine explizite Ownership und Gruppenmitgliedschaft.

SELinux/AppArmor blockiert Verbindungen

Mandatory Access Control (MAC) wie SELinux oder AppArmor kann Socket-Zugriff verhindern, auch wenn Unix-Rechte korrekt sind. Prüfen Sie AVC- oder AppArmor-DENIED-Einträge.

Shell
# 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 || true

Warum: MAC-Policies sind sehr effektiv, können aber bei Laufzeitpfaden ohne passende Labels Verbindungsabbrüche verursachen. Policy-Änderungen müssen über Change-Management erfolgen; Deaktivieren ist nur kurzfristig erlaubt.

Stale Socket/Port oder verwaiste PID

Manchmal bleibt eine Socket-Datei bestehen oder ein anderweitiger Prozess belegt den Port. Prüfen mit ss/lsof und bereinigen, aber löschen Sie Sockets nur, wenn kein Prozess sie verwendet.

Shell
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-fpm

Warum: Unbedachtes Löschen kann aktive Verbindungen abbrechen. Prüfen Sie PID-Informationen vorher.

Timeouts, OpCache-Kaltstart und Load-Balancer

Nach einem RESTart sind Caches leer; erste Requests dauern länger. Wenn Apache oder ein Load-Balancer Timeouts zu kurz sind, werden Requests abgebrochen und Clients sehen 500/502/504.

Shell
# 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 40

Contremesures : augmenter modérément les timeouts, effectuer un warmup de l’OpCache lors des déploiements et appliquer une procédure de redémarrage progressive : laisser les pools préchauffer avant d’autoriser le trafic.

pm.max_children et gestion des processus

Si trop peu de workers sont disponibles, la file d’attente s’accumule. Après un redémarrage, les goulots d’étranglement apparaissent immédiatement car les workers se réinitialisent. Dimensionnez pm.max_children en vous basant sur des mesures réelles de consommation mémoire et CPU.

Ini
pm = dynamic
pm.max_children = 40
pm.start_servers = 8
pm.min_spare_servers = 8
pm.max_spare_servers = 16
pm.max_requests = 500

Pourquoi : une valeur trop basse provoque des refus immédiats ; une valeur trop haute surcharge le serveur. Mesurez la consommation par worker et testez sous charge.

Primary script unknown : problèmes de chemin / chroot / open_basedir

Si FPM ne parvient pas à ouvrir le script cible, il signale „Primary script unknown“ et Apache renvoie un 500. Vérifiez le DocumentRoot, les chemins de proxy, les paramètres chroot ou les RESTrictions open_basedir.

Pratique : scripts de dépannage et extraits de runbook

Intégration systemd : RuntimeDirectory et tmpfiles.d

systemd peut garantir que /run/php existe avec les droits appropriés avant le démarrage. Utilisez RuntimeDirectory dans le fichier d’unité ou une configuration tmpfiles.d.

Shell
# 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 -

Pourquoi : le répertoire est créé systématiquement avec le propriétaire et les modes corrects avant le démarrage du service — évite les conditions de course au démarrage/redémarrage.

Repli vers TCP : configuration & remarques

Comme contournement de diagnostic à court terme, basculer du socket Unix vers TCP (127.0.0.1:9000) peut aider, car cela évite de nombreux problèmes liés aux droits et au contrôle d’accès MAC. En production, TCP introduit toutefois de la latence, une granularité d’accès moindre et des risques de collision de ports.

Ini
; php-fpm pool.conf
; unix socket
;listen = /run/php/php-fpm.sock
; TCP alternative
listen = 127.0.0.1:9000
Shell
# Apache ProxyPassMatch Beispiel TCP
# In vHost

  SetHandler "proxy:fcgi://127.0.0.1:9000"

Quand cela échoue : si des pare-feu d’infrastructure appliquent des politiques TCP locales ou si plusieurs processus utilisent déjà le port.

Script de warmup d’OpCache (exemple simple)

Un script de warmup peut, lors du déploiement ou du redémarrage, préremplir les entrées de l’OpCache et ainsi réduire les latences liées au cold start.

Shell
#!/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

Pourquoi : réduit les pics de charge et les timeouts lors des premières requêtes utilisateur après un redémarrage. Testez-le en staging.

Script de rollback rapide : basculement Socket ↔ TCP

Shell
#!/bin/bash
# rollback-to-tcp.sh - bascule le Pool sur TCP et recharge les services
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

Pourquoi : un rollback contrôlé minimise le temps d'indisponibilité. Testez ce script dans un environnement sécurisé avant de l'exécuter en production.

Monitoring, Alarme et prévention

Complétez un monitoring générique des 5xx par des indicateurs spécifiques : motifs du Apache-Error-Log (proxy_fcgi), statistiques du pool FPM (active processes, listen queue), alarmes pm.max_children ainsi que les métriques système (RAM/IO). Vous distinguerez ainsi les effets de cold start des goulots d'étranglement structurels.

Recommandations pour les alertes

  • Alarme en cas de lignes AH01079/AH02454 répétées dans l'Apache-Error-Log sur une courte période.
  • FPM : alerte si la listen queue > 0 de façon persistante ou si „reached pm.max_children“ apparaît dans les logs.
  • Système : forte utilisation de swap/IO ou entrées du OOM-Killer immédiatement avant des erreurs 500.

Post-incident : analyse des causes profondes et mesures préventives

Après une correction temporaire, réalisez toujours une RCA structurée : quel changement a déclenché l'erreur ? S'agissait-il d'une mise à jour, d'une modification de configuration ou d'une condition de concurrence au démarrage ? Ajustez le gestionnaire de configuration (Git), les modèles de changement pour les pools et les overrides systemd, et documentez les leçons apprises dans le Runbook.

Checklist pour un ticket d'incident (compact)

  1. Horodatage du redémarrage et durée de l'incident
  2. Lignes exactes de l'Apache-Error-Log
  3. Extrait du journal FPM autour du redémarrage
  4. Sortie ss/ls/find pour le socket/port
  5. Sortie namei -l du chemin du socket
  6. SELinux/AppArmor-Status et lignes AVC/deny pertinentes
  7. Métriques courtes mémoire/IO/CPU
  8. Si le basculement sur TCP a aidé (oui/non)

Bonnes pratiques opérationnelles et savoir-faire

  • Versionnez les fichiers de pool et les includes Apache dans Git ; déployez uniquement via CI avec tests.
  • Utilisez systemd RuntimeDirectory ou tmpfiles.d pour garantir que /run/php est préparé correctement.
  • Prévoyez les labels pour SELinux tôt dans le processus de changement, pas au débotté.
  • Implémentez des healthchecks et des scripts de warmup pour les redémarrages.
  • Testez les scripts de rollback avant de les documenter comme outil d'urgence.

Conclusion

Un 500 après un redémarrage de PHP-FPM est le plus souvent un problème d'intégration à l'interface Apache ↔ PHP-FPM : socket/port, propriété/permissions, MAC-Policies, timeouts et dimensionnement des pools sont les causes typiques. La solution pérenne combine une analyse d'erreur immédiate basée sur les logs et des mesures durables : chemins de socket stables, ownership explicite dans les fichiers de pool, intégration systemd pour les répertoires Runtime, labels SELinux/AppArmor appropriés, procédures de warmup et monitoring ciblé. Par ailleurs, des mécanismes de rollback testés et des Runbooks documentés réduisent le risque de récidive.

Utilisez les étapes de vérification ci-dessus comme template d'incident et produisez après chaque perturbation une RCA et un ajustement de politique. Ainsi, le prochain redémarrage de PHP-FPM redeviendra une opération de routine.

Aspects opérationnels : orchestration, healthchecks et conteneurs

Les redémarrages automatisés via systemd, des outils de gestion de configuration ou des orchestrateurs peuvent générer des conditions de concurrence (race‑conditions) si les load‑balancers ou frontends ne sont pas vidés (drained). Planifiez des redémarrages échelonnés avec des phases de drain et des healthchecks (readiness/liveness), afin de terminer de manière contrôlée les sessions et les connexions entrantes.

L’activation de socket systemd (Socket-Activation) peut constituer un élément stable : l’unité socket maintient le point de terminaison à travers les cycles de redémarrage et réduit les cas de „Connection refused“. Veillez toutefois aux répertoires Runtime et à la persistance tmpfs.

Dans des environnements conteneurisés, les sockets Unix sur OverlayFS ou dans des volumes montés sont plus susceptibles de rencontrer des problèmes de permissions et d’inodes ; vérifiez donc l’utilisation de liaisons TCP ou optez pour des volumes partagés dédiés avec des règles claires de propriété.

Améliorez l’observabilité : corrélez les logs Apache et FPM via des Request‑IDs et exportez les métriques du pool (listen‑queue, active) pour une alerte précoce.

Pour ce sujet, Apache Http 500 et Php-Fpm Socket sont également importants. Le billet situe ces aspects de façon claire et précise ce qui compte dans la pratique.