PHP-FPM et Nginx : configuration pour la production

🏷️ Administration Serveur 📅 10/04/2026 22:00:00 👤 Mezgani Said
Php-Fpm Nginx Performance Production Fastcgi
PHP-FPM et Nginx : configuration pour la production

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é
À retenir : PHP-FPM + Nginx est la combinaison recommandée pour la production. Elle offre meilleure performance, flexibilité et est la norme de l'industrie.

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"
Note : Après modification de php.ini, redémarrez PHP-FPM : 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']);
}
?>
À retenir : Cette architecture sépare complètement le frontend (static) du backend (API PHP), permettant un scaling et un déploiement indépendants.

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.