Configuration optimale de PHP-FPM avec Nginx, gestion des pools, performance, sécurité et exemple complet pour une API REST + frontend Angular.
PHP-FPM vs Apache mod_php
PHP-FPM (FastCGI Process Manager) est le gestionnaire de processus PHP moderne qui remplace les anciennes approches comme Apache mod_php. Voici les différences clés :
| Critère | PHP-FPM | Apache mod_php |
|---|---|---|
| Serveur web | Nginx, Apache (proxy) | Apache uniquement |
| Processus | Séparé (processus PHP indépendant) | Intégré au processus Apache |
| Performance | Meilleure (Nginx + PHP-FPM) | Plus lourd (Apache + PHP intégré) |
| Mémoire | Configurable par pool | Partagée avec Apache |
| Restart PHP | Possible sans redémarrer le web | Nécessite restart d'Apache |
| Protocole | FastCGI (TCP/Socket Unix) | Module intégré |
Installation et configuration PHP-FPM
Étape 1 : Installation sur Ubuntu/Debian
# Installer PHP et PHP-FPM
sudo apt update
sudo apt install -y php php-fpm php-mysql php-curl php-gd php-xml php-mbstring
# Vérifier la version
php -v
php-fpm -v
Étape 2 : Configuration de PHP-FPM
Éditer le fichier de pool principal :
sudo nano /etc/php/8.3/fpm/pool.d/www.conf
Paramètres essentiels :
[www]
; Utilisateur et groupe du process
user = www-data
group = www-data
; Socket Unix (recommandé pour performance)
listen = /run/php/php8.3-fpm.sock
; Ou socket TCP (si PHP-FPM sur serveur différent)
; listen = 127.0.0.1:9000
; Nombre de processus enfants
pm = dynamic
pm.max_children = 20
pm.start_servers = 5
pm.min_spare_servers = 2
pm.max_spare_servers = 10
pm.max_requests = 500
; Limites de ressources
php_admin_value[memory_limit] = 128M
php_admin_value[max_execution_time] = 30
php_admin_value[upload_max_filesize] = 50M
php_admin_value[post_max_size] = 50M
; Logs
catch_workers_output = yes
slowlog = /var/log/php8.3-fpm.log.slow
request_slowlog_timeout = 10s
Étape 3 : Démarrer PHP-FPM
sudo systemctl restart php8.3-fpm
sudo systemctl enable php8.3-fpm
# Vérifier le statut
sudo systemctl status php8.3-fpm
# Vérifier les processus
ps aux | grep php-fpm
Intégration Nginx <→ PHP-FPM
Nginx ne peut pas exécuter PHP directement. Il agit comme reverse proxy qui envoie les requêtes PHP vers PHP-FPM via FastCGI.
Configuration Nginx complète :
server {
listen 80;
server_name example.com www.example.com;
root /var/www/html;
index index.php index.html index.htm;
# Logs
access_log /var/log/nginx/example.com.access.log;
error_log /var/log/nginx/example.com.error.log;
# Gzip compression
gzip on;
gzip_types text/html text/css text/javascript application/javascript;
# Dénégation d'accès aux fichiers sensibles
location ~ /\. {
deny all;
access_log off;
log_not_found off;
}
# Bloc de configuration PHP
location ~ \.php$ {
include fastcgi_params;
fastcgi_pass unix:/run/php/php8.3-fpm.sock;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param PATH_INFO $fastcgi_path_info;
# Buffers et timeouts
fastcgi_buffer_size 128k;
fastcgi_buffers 4 256k;
fastcgi_busy_buffers_size 256k;
fastcgi_read_timeout 60s;
# Caché pour les fichiers statiques
expires 1d;
}
# Caché pour les fichiers statiques
location ~* \.(jpg|jpeg|png|gif|ico|css|js|svg|webp)$ {
expires 30d;
add_header Cache-Control "public, immutable";
}
# Rewrite pour les friendly URLs (Laravel/autres frameworks)
try_files $uri $uri/ /index.php?$query_string;
}
Différences : Socket Unix vs TCP
| Type | Configuration | Avantages | Inconvénients |
|---|---|---|---|
| Socket Unix | fastcgi_pass unix:/run/php/php8.3-fpm.sock; | Plus rapide, moins de surcharge | Même serveur seulement |
| TCP | fastcgi_pass 127.0.0.1:9000; | Extensible (serveurs différents) | Légèrement plus lent (réseau) |
Optimisation de la performance
1. OPCache — Caché d'opcodes PHP
OPCache accélère PHP en cachant le bytecode compilé :
# Vérifier qu'OPCache est installé
php -m | grep Zend
# Éditer php.ini
sudo nano /etc/php/8.3/fpm/php.ini
Paramètres recommandés pour OPCache :
[opcache]
opcache.enable=1
opcache.memory_consumption=256
opcache.interned_strings_buffer=8
opcache.max_accelerated_files=10000
opcache.validate_timestamps=0 ; Désactiver en production
opcache.revalidate_freq=0 ; Ou laisser vide
opcache.save_comments=1
2. Realpath Cache — Caché des chemins de fichiers
; Dans php.ini
realpath_cache_size = 4096K
realpath_cache_ttl = 600
3. Session Storage
Par défaut, PHP stocke les sessions dans /tmp. En production, utilisez Redis ou Memcached :
; Dans php.ini pour utiliser Redis
session.save_handler = redis
session.save_path = "tcp://127.0.0.1:6379/0"
; Ou pour Memcached
; session.save_handler = memcached
; session.save_path = "127.0.0.1:11211"
sudo systemctl restart php8.3-fpm
Gestion des erreurs et logs PHP
Configuration PHP pour les logs :
; Dans php.ini
display_errors = Off ; Ne pas afficher en production
log_errors = On
error_log = /var/log/php_errors.log
error_reporting = E_ALL
; Définir le niveau de verbosité
; E_ALL, E_ERROR, E_WARNING, E_NOTICE, E_STRICT, etc.
Logs lents avec PHP-FPM :
; Chaque pool peut avoir son propre slowlog
slowlog = /var/log/php8.3-fpm.log.slow
request_slowlog_timeout = 10s
; Consulter les requêtes lentes
tail -f /var/log/php8.3-fpm.log.slow
Permissions des logs :
sudo touch /var/log/php_errors.log
sudo chown www-data:www-data /var/log/php_errors.log
sudo chmod 644 /var/log/php_errors.log
# Idem pour les logs de pool
sudo chown www-data:www-data /var/log/php8.3-fpm*
sudo chmod 644 /var/log/php8.3-fpm*
Sécurité et restrictions d'accès
1. Restreindre l'accès à PHP-FPM
Par défaut, PHP-FPM écoute sur un socket (sûr). Si vous utilisez TCP, restreignez l'accès :
; Dans /etc/php/8.3/fpm/pool.d/www.conf
; TCP seulement pour localhost
listen = 127.0.0.1:9000
; Ou avec contrôle d'accès
listen.allowed_clients = 127.0.0.1
2. Chroot (isolation du process)
; Optionnel mais sécurisé
chroot = /var/www/html
chdir = /
3. Désactiver les fonctions dangereuses :
; Dans php.ini
disable_functions = exec,passthru,shell_exec,system,proc_open,popen,curl_exec,curl_multi_exec,parse_ini_file,show_source,proc_get_status
; Restreindre les chemins accessibles
open_basedir = /var/www/html:/tmp:/usr/share/php
4. Permissions des fichiers
# Permissions correctes pour les fichiers PHP
sudo find /var/www/html -type f -name "*.php" -exec chmod 644 {} \;
sudo find /var/www/html -type d -exec chmod 755 {} \;
# Propriétaire www-data
sudo chown -R www-data:www-data /var/www/html
Monitoring et debugging PHP
1. Vérifier le statut et les processus
# Statut général
sudo systemctl status php8.3-fpm
# Voir les processus PHP-FPM
ps aux | grep [p]hp-fpm
# Nombre de processus enfants actuels
ps aux | grep [p]hp-fpm | wc -l
2. Xdebug pour le debugging (dev)
# Installation
sudo apt install -y php8.3-xdebug
# Configuration dans php.ini (DEV ONLY)
[xdebug]
xdebug.mode = debug
xdebug.start_with_request = yes
xdebug.client_host = localhost
xdebug.client_port = 9003
xdebug.log = /var/log/xdebug.log
3. Profiling PHP (analyse de performance)
; Dans php.ini, activer SPL
[xdebug]
xdebug.mode = profile
xdebug.profiler_output_dir = /var/log/php_profiling
; Les fichiers de profil sont dans /var/log/php_profiling
; À analyser avec Webgrind ou KCacheGrind
4. Load testing avec ApacheBench
# Test basique : 1000 requêtes, 10 concurrentes
ab -n 1000 -c 10 http://example.com/
# Avec un en-tête
ab -n 1000 -c 10 -H "Authorization: Bearer token" http://example.com/api/
Exemple complet : site Angular + API PHP
Voici une configuration complète pour un site moderne : frontend Angular + API REST en PHP :
Structure de dossiers :
/var/www/example.com/
├── /dist/ → Frontend Angular buildé
├── /api/ → API PHP (backend)
│ ├── index.php → Point d'entrée
│ ├── .htaccess → Rewrite rules
│ └── /src/ → Code source
└── /uploads/ → Fichiers uploadés
Configuration Nginx complète pour cette architecture :
server {
listen 80;
listen 443 ssl http2;
server_name example.com www.example.com;
root /var/www/example.com;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
# Logs
access_log /var/log/nginx/example.com.access.log combined;
error_log /var/log/nginx/example.com.error.log;
# Sécurité headers
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-Frame-Options "DENY" always;
# Gzip
gzip on;
gzip_types text/html text/css text/javascript application/javascript application/json;
# Fichiers statiques
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ {
expires 30d;
add_header Cache-Control "public, immutable";
access_log off;
}
# API PHP
location /api {
rewrite ^/api/(.*)$ /api/index.php?$1 last;
}
location ~ ^/api/.*\.php$ {
include fastcgi_params;
fastcgi_pass unix:/run/php/php8.3-fpm.sock;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_buffer_size 128k;
fastcgi_buffers 4 256k;
}
# Frontend Angular
location / {
try_files $uri $uri/ /index.html;
}
# Dénégation des fichiers sensibles
location ~ /\. {
deny all;
access_log off;
log_not_found off;
}
}
Fichier PHP d'API simple :
<?php
// /api/index.php
header('Content-Type: application/json');
header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Methods: GET, POST, PUT, DELETE');
header('Access-Control-Allow-Headers: Content-Type, Authorization');
// Router basique
$uri = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH);
$parts = explode('/', trim($uri, '/'));
// Exemple: /api/users/123 -> GET
if ($parts[0] === 'api') {
$resource = $parts[1] ?? null;
$id = $parts[2] ?? null;
switch ($resource) {
case 'users':
if ($_SERVER['REQUEST_METHOD'] === 'GET') {
echo json_encode(['users' => [
['id' => 1, 'name' => 'John'],
['id' => 2, 'name' => 'Jane']
]]);
}
break;
default:
http_response_code(404);
echo json_encode(['error' => 'Not found']);
}
} else {
http_response_code(404);
echo json_encode(['error' => 'API not found']);
}
?>
Conclusion
PHP-FPM + Nginx est la stack de production standard pour les applications PHP modernes. Les points clés :
- Installation : PHP-FPM se configure via des pools avec contrôle granulaire des ressources
- Intégration : Nginx envoie les requêtes PHP à FPM via FastCGI (socket Unix préféré)
- Performance : OPCache + Realpath cache + gestion optimale des processus = application rapide
- Logs : Centralisez les logs et les erreurs pour une meilleure observabilité
- Sécurité : Restreignez les fonctions PHP, limitez les permissions, isolez les processus
- Monitoring : Tracez les requêtes lentes et les erreurs pour optimiser en continu
Avec cette configuration, votre application PHP sera prête pour la production, rapide et sécurisée.