PHP-FPM (FastCGI Process Manager) : Guide complet d’installation, de configuration et d’optimisation
PHP-FPM (PHP FastCGI Process Manager) est un gestionnaire de processus PHP alternatif haute performance qui implémente le protocole FastCGI pour découpler l’exécution PHP du processus du serveur web. Au lieu de créer un nouvel interpréteur PHP pour chaque requête HTTP entrante — comme le fait le CGI traditionnel — PHP-FPM maintient un pool persistant de processus workers qui acceptent, exécutent et retournent les réponses PHP avec une surcharge considérablement réduite.
Pour tout serveur web de production exécutant WordPress, Laravel, Symfony, ou des applications PHP personnalisées, PHP-FPM est le gestionnaire standard. Il permet un contrôle précis du cycle de vie des processus, des limites mémoire, de la mise en file d’attente des requêtes et de l’isolation par application — des capacités tout simplement indisponibles avec mod_php ou le CGI brut.
En quoi PHP-FPM diffère du CGI et de mod_php
Pour comprendre pourquoi PHP-FPM est important, il est utile de voir exactement ce qu’il remplace et pourquoi ces alternatives sont insuffisantes à grande échelle.
| Fonctionnalité | CGI | mod_php | PHP-FPM |
|---|---|---|---|
| — | — | — | — |
| Modèle de processus | Nouveau processus par requête | Intégré dans Apache | Pool de workers persistants |
| Efficacité mémoire | Très faible | Modérée | Excellente |
| Couplage au serveur web | Étroit | Étroit (Apache uniquement) | Découplé (tout serveur) |
| Isolation par site | Aucune | Aucune | Complète (pools séparés) |
| Rechargement gracieux | Non | Non | Oui |
| Slow log / profilage | Non | Non | Oui |
| Mise à l’échelle dynamique des processus | Non | Non | Oui |
| Support des sockets Unix | Non | Non | Oui |
| Compatible avec NGINX | Non | Non | Oui |
CGI crée un nouveau processus OS pour chaque requête. Sous un trafic modéré, cela génère des milliers de cycles fork/exec/exit par minute, saturant le CPU et la mémoire. mod_php intègre l’interpréteur PHP directement dans chaque worker Apache, ce qui signifie que chaque processus Apache — même celui servant une image statique — embarque l’intégralité du runtime PHP en mémoire. PHP-FPM résout ces deux problèmes : les workers sont persistants et complètement séparés du serveur web, de sorte que NGINX ou Apache gère les fichiers statiques nativement tandis que PHP-FPM ne gère que l’exécution PHP.
Architecture PHP-FPM : flux de requêtes en détail
Comprendre le chemin interne des requêtes est essentiel pour l’optimisation et le débogage.
- Un navigateur envoie une requête HTTP pour une ressource
.php. - Le serveur web (NGINX ou Apache) reçoit la requête et la fait correspondre à un bloc location ou à une directive
FilesMatch. - Le serveur web transmet la requête à PHP-FPM via le protocole FastCGI — soit via un socket de domaine Unix (
/run/php/php8.2-fpm.sock), soit via un socket TCP (127.0.0.1:9000). - Le processus maître de PHP-FPM achemine la requête vers un worker disponible du pool configuré.
- Le worker exécute le script PHP, écrit dans
stdout, et retourne la réponse au serveur web. - Le serveur web délivre le HTML rendu au client.
- Le processus worker ne se termine pas — il retourne dans le pool inactif, prêt pour la prochaine requête.
Les sockets Unix sont préférés aux sockets TCP pour la communication locale car ils contournent entièrement la pile TCP/IP, réduisant la latence de 10 à 20 % dans les benchmarks et éliminant la surcharge liée à la liaison de port et au routage en loopback.
Modes de gestion des processus
PHP-FPM prend en charge trois modes pm (gestionnaire de processus), et choisir le mauvais est l’une des erreurs de configuration les plus courantes.
pm = static
Un nombre fixe de workers est toujours en cours d’exécution, quel que soit le trafic. Utilisez ce mode sur des serveurs dédiés où vous souhaitez une mémoire préallouée prévisible et pouvez vous permettre la surcharge en veille.
pm = static
pm.max_children = 20pm = dynamic
PHP-FPM démarre un nombre de base de workers et monte ou descend en charge dans des limites définies. C’est le mode le plus couramment utilisé et le bon choix par défaut pour la plupart des environnements d’hébergement VPS.
pm = dynamic
pm.max_children = 50
pm.start_servers = 5
pm.min_spare_servers = 5
pm.max_spare_servers = 10
pm.max_requests = 500pm = ondemand
Les workers sont créés uniquement lorsqu’une requête arrive et supprimés après pm.process_idle_timeout secondes d’inactivité. Cela minimise la consommation mémoire en veille et est idéal pour les sites à faible trafic ou les environnements partagés où des dizaines de pools coexistent.
pm = ondemand
pm.max_children = 20
pm.process_idle_timeout = 10sPiège critique : ondemand introduit une latence de démarrage à froid lors de la première requête après une période d’inactivité. Pour les applications sensibles à la latence, dynamic est toujours le meilleur choix.
Calculer pm.max_children correctement
C’est là que la plupart des administrateurs commettent des erreurs coûteuses. Définir pm.max_children trop haut provoque un épuisement de la mémoire et des kills OOM ; trop bas provoque une mise en file d’attente des requêtes et des erreurs 502 sous charge.
La formule correcte :
pm.max_children = (Available RAM for PHP) / (Average PHP worker memory usage)Pour trouver la mémoire moyenne de vos workers PHP :
ps --no-headers -o "rss,cmd" -C php-fpm8.2 | awk '{ sum+=$1 } END { printf "Average: %d MBn", sum/NR/1024 }'Sur un VPS avec 2 Go de RAM où NGINX, MySQL et l’OS consomment ~600 Mo, il vous reste environ 1 400 Mo pour PHP. Si chaque worker utilise ~70 Mo, votre pm.max_children sécurisé est de 20. Ne le définissez jamais au hasard.
Installation de PHP-FPM
Debian / Ubuntu
sudo apt update
sudo apt install php8.2-fpm
sudo systemctl enable php8.2-fpm
sudo systemctl start php8.2-fpmCentOS / AlmaLinux / RHEL (avec le dépôt Remi)
sudo dnf install epel-release
sudo dnf install https://rpms.remirepo.net/enterprise/remi-release-9.rpm
sudo dnf module enable php:remi-8.2
sudo dnf install php-fpm
sudo systemctl enable php-fpm
sudo systemctl start php-fpmVérifiez que le service est en cours d’exécution et confirmez le chemin du socket :
sudo systemctl status php8.2-fpm
ls -la /run/php/Configuration des pools PHP-FPM
La configuration principale de PHP-FPM se trouve dans /etc/php/8.2/fpm/php-fpm.conf, mais les définitions de pools individuels appartiennent à /etc/php/8.2/fpm/pool.d/. Sur les systèmes basés sur RHEL, les fichiers de pool résident dans /etc/php-fpm.d/.
Chaque pool est un environnement d’exécution isolé. Exécuter plusieurs applications PHP sur le même serveur — par exemple, un site WordPress et une API Laravel — signifie créer des fichiers de pool séparés avec des utilisateurs, des chemins de socket et des limites de ressources distincts. C’est l’architecture correcte pour les configurations multi-locataires et est bien plus sécurisée que de partager un seul pool.
Exemple : configuration de pool en production
[myapp]
user = myapp
group = myapp
; Unix socket — always prefer this over TCP for local communication
listen = /run/php/myapp-fpm.sock
listen.owner = www-data
listen.group = www-data
listen.mode = 0660
; Process manager
pm = dynamic
pm.max_children = 30
pm.start_servers = 5
pm.min_spare_servers = 3
pm.max_spare_servers = 10
pm.max_requests = 1000
; Slow log — log requests taking longer than 2 seconds
slowlog = /var/log/php-fpm/myapp-slow.log
request_slowlog_timeout = 2s
; Status and ping endpoints
pm.status_path = /fpm-status
ping.path = /fpm-ping
; Environment isolation
clear_env = yes
env[HOSTNAME] = $HOSTNAME
env[PATH] = /usr/local/bin:/usr/bin:/bin
; PHP value overrides per pool
php_admin_value[error_log] = /var/log/php-fpm/myapp-error.log
php_admin_flag[log_errors] = on
php_admin_value[memory_limit] = 256M
php_admin_value[upload_max_filesize] = 64M
php_admin_value[post_max_size] = 64MLa directive clear_env = yes est un paramètre critique pour la sécurité qui est fréquemment négligé. Sans elle, les workers PHP héritent de toutes les variables d’environnement du processus maître, pouvant potentiellement exposer des données sensibles au niveau système dans le $_ENV de votre application.
Intégration de PHP-FPM avec NGINX
NGINX n’a aucune capacité d’exécution PHP native — il s’appuie entièrement sur FastCGI pour déléguer les requêtes PHP. C’est en réalité un avantage architectural : NGINX gère les fichiers statiques à un coût quasi nul tandis que PHP-FPM ne gère que ce qui nécessite une exécution.
server {
listen 80;
server_name example.com;
root /var/www/myapp/public;
index index.php index.html;
# Serve static files directly, no PHP involvement
location / {
try_files $uri $uri/ /index.php?$query_string;
}
# Delegate PHP to PHP-FPM
location ~ .php$ {
# Security: prevent executing uploaded files as PHP
try_files $uri =404;
fastcgi_split_path_info ^(.+.php)(/.+)$;
fastcgi_pass unix:/run/php/myapp-fpm.sock;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
include fastcgi_params;
# Performance tuning
fastcgi_buffers 16 16k;
fastcgi_buffer_size 32k;
fastcgi_read_timeout 300;
}
# Block access to the FPM status page from public
location ~ ^/(fpm-status|fpm-ping)$ {
allow 127.0.0.1;
deny all;
fastcgi_pass unix:/run/php/myapp-fpm.sock;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
}Note de sécurité : La ligne try_files $uri =404; avant fastcgi_pass n’est pas optionnelle. Sans elle, NGINX transmettra les requêtes pour des fichiers inexistants à PHP-FPM, permettant des attaques par traversée de chemin où un attaquant télécharge une image contenant du code PHP et trompe le serveur pour qu’il l’exécute.
Intégration de PHP-FPM avec Apache
Apache nécessite mod_proxy_fcgi pour communiquer avec PHP-FPM. Contrairement à mod_php, cette approche permet à Apache d’exécuter PHP-FPM en tant qu’utilisateur séparé, améliorant l’isolation.
sudo a2enmod proxy_fcgi setenvif
sudo systemctl restart apache2Configuration de l’hôte virtuel :
<VirtualHost *:80>
ServerName example.com
DocumentRoot /var/www/myapp/public
<Directory /var/www/myapp/public>
Options -Indexes +FollowSymLinks
AllowOverride All
Require all granted
</Directory>
<FilesMatch ".php$">
SetHandler "proxy:unix:/run/php/myapp-fpm.sock|fcgi://localhost/"
</FilesMatch>
ErrorLog ${APACHE_LOG_DIR}/myapp-error.log
CustomLog ${APACHE_LOG_DIR}/myapp-access.log combined
</VirtualHost>Activation et utilisation de la page de statut PHP-FPM
La page de statut intégrée est l’un des outils de diagnostic les moins utilisés de PHP-FPM. Une fois pm.status_path configuré dans le fichier de pool, interrogez-le directement :
sudo -u www-data SCRIPT_NAME=/fpm-status SCRIPT_FILENAME=/fpm-status REQUEST_METHOD=GET cgi-fcgi -bind -connect /run/php/myapp-fpm.sockOu, plus pratiquement, via curl après l’avoir exposé sur un endpoint interne restreint :
curl http://127.0.0.1/fpm-status?fullMétriques clés à surveiller :
listen queue: Requêtes en attente d’un worker libre. Toute valeur supérieure à 0 sous charge soutenue signifie quepm.max_childrenest trop faible.active processes: Workers exécutant actuellement du PHP. Si cela est constamment égal àpm.max_children, vous êtes à capacité maximale.slow requests: Nombre cumulatif de requêtes ayant dépassérequest_slowlog_timeout. Un nombre croissant indique des goulots d’étranglement au niveau applicatif.
Utilisation du slow log pour le débogage des performances
Le slow log capture une trace de pile PHP complète pour toute requête dépassant le seuil configuré. C’est inestimable pour identifier les problèmes de requêtes N+1, les appels I/O bloquants ou les boucles inefficaces sans avoir besoin d’un profileur complet.
slowlog = /var/log/php-fpm/myapp-slow.log
request_slowlog_timeout = 2sUne entrée de slow log ressemble à ceci :
[21-Jun-2025 14:32:11] [pool myapp] pid 18432
script_filename = /var/www/myapp/public/index.php
[0x00007f3b4c001e80] PDOStatement->execute() /var/www/myapp/vendor/laravel/framework/src/Illuminate/Database/Connection.php:338
[0x00007f3b4c001d40] runQueryCallback() /var/www/myapp/vendor/laravel/framework/src/Illuminate/Database/Connection.php:295Cela vous indique immédiatement que le goulot d’étranglement est une requête de base de données, et non la logique PHP — orientant précisément votre effort d’optimisation.
PHP-FPM avec OPcache : l’association essentielle
PHP-FPM seul gère la gestion des processus ; OPcache élimine le coût d’analyse et de compilation des fichiers source PHP à chaque requête. Ensemble, ils forment la pile de performance complète pour PHP sous Linux.
Activez et configurez OPcache dans /etc/php/8.2/fpm/php.ini ou un fichier /etc/php/8.2/fpm/conf.d/10-opcache.ini dédié :
opcache.enable=1
opcache.memory_consumption=256
opcache.interned_strings_buffer=16
opcache.max_accelerated_files=20000
opcache.revalidate_freq=0
opcache.validate_timestamps=0
opcache.jit_buffer_size=128M
opcache.jit=tracingDéfinir validate_timestamps=0 désactive les vérifications de modification de fichiers à chaque requête — un gain de performance significatif en production. Lorsque vous déployez du nouveau code, déclenchez une réinitialisation du cache explicitement :
sudo systemctl reload php8.2-fpmSur un VPS avec cPanel, les paramètres OPcache sont souvent exposés dans l’interface de configuration PHP, mais la configuration manuelle via les fichiers .ini offre toujours un contrôle plus précis.
Renforcement de la sécurité pour PHP-FPM
Exécuter chaque pool en tant qu’utilisateur système dédié
N’exécutez jamais les pools PHP-FPM en tant que root ou en tant qu’utilisateur www-data partagé entre plusieurs applications. Créez un utilisateur système dédié par application :
sudo useradd --system --no-create-home --shell /usr/sbin/nologin myappDéfinissez ensuite user = myapp et group = myapp dans la configuration du pool. Cela garantit qu’une application PHP compromise ne peut pas lire les fichiers appartenant à d’autres applications sur le même serveur.
Restreindre les fonctions PHP
Dans le bloc php_admin_value du pool, désactivez les fonctions qui n’ont aucune utilisation légitime dans les applications web :
php_admin_value[disable_functions] = exec,passthru,shell_exec,system,proc_open,popen,curl_exec,curl_multi_exec,parse_ini_file,show_sourceLimiter open_basedir
Limitez l’accès aux fichiers PHP au répertoire de l’application :
php_admin_value[open_basedir] = /var/www/myapp:/tmpUtiliser des sockets Unix avec des permissions strictes
Les sockets TCP (127.0.0.1:9000) sont accessibles à tout processus sur le serveur. Les sockets Unix avec listen.mode = 0660 restreignent l’accès à l’utilisateur et au groupe propriétaires uniquement.
Vérification de la pile complète
Après avoir configuré PHP-FPM et votre serveur web, vérifiez toute la chaîne avant de mettre en production.
Rechargez tous les services :
sudo systemctl reload php8.2-fpm
sudo systemctl reload nginx
# or
sudo systemctl reload apache2Testez la syntaxe de la configuration NGINX avant de recharger :
sudo nginx -tCréez un fichier info temporaire (supprimez-le après vérification — il expose des données sensibles du serveur) :
echo "<?php phpinfo();" | sudo tee /var/www/myapp/public/phpinfo.phpOuvrez http://example.com/phpinfo.php dans un navigateur et confirmez :
- Server API affiche
FPM/FastCGI - PHP Version correspond à la version installée
- La section OPcache est présente et activée
Puis supprimez immédiatement le fichier :
sudo rm /var/www/myapp/public/phpinfo.phpPHP-FPM dans les environnements multi-applications et à fort trafic
Sur un Serveur Dédié hébergeant des dizaines d’applications PHP, l’architecture multi-pool devient essentielle. Chaque application dispose de son propre pool avec des pm.max_children, des limites mémoire et des chemins de slow log configurés indépendamment. Une application défaillante qui épuise son pool de workers n’affecte pas les autres applications.
Pour les scénarios à fort trafic, combinez PHP-FPM avec :
- La mise en cache FastCGI NGINX (
fastcgi_cache) pour servir les réponses PHP mises en cache comme des fichiers statiques, contournant entièrement PHP-FPM pour les requêtes répétées - Redis ou Memcached pour le stockage des sessions PHP, remplaçant les sessions basées sur des fichiers par défaut qui créent une contention I/O sous charge
- La mise à l’échelle horizontale en exécutant PHP-FPM sur des serveurs d’application derrière un load balancer, avec NGINX sur un nœud frontal séparé
Si votre stack inclut la terminaison SSL, associer PHP-FPM à des Certificats SSL correctement configurés au niveau NGINX garantit que les handshakes TLS sont gérés avant que les requêtes n’atteignent PHP-FPM, permettant aux workers PHP de se concentrer exclusivement sur la logique applicative.
Pour les charges de travail PHP intensives en calcul — inférence d’apprentissage automatique via des liaisons PHP, traitement d’images ou transcodage vidéo — envisagez l’hébergement GPU où PHP-FPM peut déléguer les calculs lourds à des bibliothèques accélérées par GPU tout en maintenant la gestion standard des requêtes pour la couche web.
Matrice de décision clé et liste de contrôle technique
Avant de déployer PHP-FPM en production, vérifiez chaque élément de cette liste de contrôle :
Sélection du gestionnaire de processus
- Utilisez
pm = dynamicpour les charges de travail VPS à usage général - Utilisez
pm = staticuniquement sur des serveurs dédiés avec un trafic prévisible et soutenu - Utilisez
pm = ondemanduniquement pour les pools à faible trafic ou de développement
Planification de la capacité
- Mesurez la mémoire réelle des workers avec
psavant de définirpm.max_children - Réservez au moins 20 % de la RAM totale pour l’OS, le serveur web et la base de données
- Définissez
pm.max_requestsentre 500 et 1000 pour éviter l’accumulation de fuites mémoire
Sécurité
- Chaque pool d’application s’exécute avec son propre utilisateur système
clear_env = yesest défini dans chaque poolopen_basedirrestreint l’accès aux fichiers au répertoire de l’applicationdisable_functionsbloque les fonctions d’exécution shell- Les sockets Unix sont utilisés à la place des sockets TCP
Observabilité
pm.status_pathest configuré et accessible uniquement depuis localhostslowlogest activé avec unrequest_slowlog_timeoutde 2 à 5 secondes- La rotation des logs est configurée pour tous les fichiers de log PHP-FPM
Performance
- OPcache est activé avec
validate_timestamps=0en production - La mise en cache FastCGI NGINX est configurée pour les endpoints pouvant être mis en cache
- Le gestionnaire de sessions PHP est défini sur Redis ou Memcached, pas sur les fichiers
Opérationnel
sudo systemctl reload php8.2-fpmest utilisé pour les changements de configuration sans interruption (pasrestart)phpinfo.phpest supprimé de la racine du document immédiatement après vérification- La configuration du pool est versionnée avec le code de l’application
FAQ
Quelle est la différence entre PHP-FPM et mod_php ?
mod_php intègre l’interpréteur PHP dans chaque processus worker Apache, consommant de la mémoire même lors du service de fichiers statiques et couplant étroitement PHP à Apache. PHP-FPM s’exécute comme un service complètement séparé, communique via FastCGI, fonctionne avec n’importe quel serveur web y compris NGINX, et permet l’isolation des processus par application avec des limites de ressources indépendantes.
Comment choisir entre un socket Unix et un socket TCP pour PHP-FPM ?
Utilisez un socket Unix (listen = /run/php/app-fpm.sock) lorsque PHP-FPM et le serveur web s’exécutent sur la même machine physique ou virtuelle. Les sockets Unix contournent la pile TCP/IP, réduisant la latence et éliminant les conflits de ports. Utilisez un socket TCP (listen = 127.0.0.1:9000) uniquement lorsque PHP-FPM s’exécute sur un hôte différent de celui du serveur web.
Pourquoi est-ce que j’obtiens des erreurs 502 Bad Gateway sous charge ?
Une erreur 502 de NGINX pointant vers PHP-FPM signifie presque toujours que la file d’attente d’écoute est pleine — tous les workers sont occupés et les nouvelles connexions sont refusées. Vérifiez pm.status_path pour une valeur listen queue non nulle. La solution est soit d’augmenter pm.max_children (si la RAM le permet), soit d’optimiser les scripts PHP lents identifiés via le slow log.
Comment recharger PHP-FPM sans interrompre les connexions actives ?
Utilisez sudo systemctl reload php8.2-fpm plutôt que restart. Le signal reload (SIGUSR2) amène le processus maître à redémarrer gracieusement les workers : les requêtes existantes se terminent normalement tandis que les nouveaux workers prennent en charge la configuration mise à jour. Un restart brutal termine immédiatement tous les workers, abandonnant les requêtes en cours.
PHP-FPM peut-il exécuter plusieurs versions de PHP simultanément sur un seul serveur ?
Oui. Installez plusieurs versions de PHP (par exemple, php7.4-fpm et php8.2-fpm) et configurez chaque pool d’application pour utiliser le chemin de socket approprié. Dans NGINX, pointez fastcgi_pass vers le socket correct par bloc server. C’est un modèle standard sur l’infrastructure partagée gérée via les Panneaux de contrôle VPS et est entièrement pris en charge sur l’hébergement VPS avec accès root.
