Objectif

  • Montrer comment s’articule le ballet PHP-FPM - Nginx afin de répondre aux requêtes web dans un environnement dockerisé, tout cela à travers notre reverse proxy Traefik

Introduction

La spécificité de PHP-FPM PHP-FPM (FastCGI Process Manager)

Le point clé réside dans l’approche architecturale de PHP.

Méthode traditionnelle: Dans une configuration traditionnelle (par exemple, Apache avec mod_php), le serveur web et l’interpréteur PHP ne forment qu’un seul processus monolithique. À chaque nouvelle requête web, un nouveau processus Apache est créé, lequel contient l’intégralité du moteur PHP. Cette approche est simple à mettre en place, mais elle consomme beaucoup de ressources et n’est pas très efficace pour gérer un grand nombre de requêtes.

Méthode PHP-FPM: PHP-FPM sépare les responsabilités. Le serveur web (Nginx) est optimisé pour ce qu’il fait de mieux (servir des fichiers), et PHP-FPM est un pool de processus distinct et dédié, optimisé pour l’exécution de PHP. Cette approche permet à chaque composant d’être extrêmement performant et évolutif. En cas de forte charge, vous pouvez simplement augmenter la capacité du service PHP-FPM sans affecter le serveur web. Cette méthode est bien plus efficace et résiliente pour les applications web modernes.

Le Request Flow

Une requête arrive dans Traefik sur le port 443 (HTTPS), qui la déchiffre et l’envoie à Nginx. Nginx, agissant comme un proxy, transfère la requête à PHP-FPM via un réseau interne privé. PHP-FPM exécute le code, renvoie le résultat à Nginx, et Nginx transmet le contenu final à Traefik, qui le chiffre à nouveau et le délivre à l’utilisateur. Comme illustré dans le diagramme suivant.

Diagram Overview of Traefik/Docker relationship Vue d'ensemble du workflow Docker - Traefik - Nginx - PHP-FPM


Source code

Vous trouverez ici le code source d’une page de démonstration PHP simple, montrant comment les différents conteneurs fonctionnent ensemble pour gérer les requêtes: https://github.com/a-naitslimane/anaitslimane.article.php-fpm-traefik-docker


Setup

Prérequis:

  • Docker et Docker Compose installés sur votre machine
  • Un reverse proxy Traefik dockerisé tournant en local. Si vous ne l’avez pas déjà, veuillez vous réferer à mon précédent article Traefik reverse proxy

Important!

Les configurations suivantes sont fortement liées aux configurations de mon précédent article. N’oubliez pas de les ajuster avec vos propres valeurs, en particulier le nom de réseau docker externe

Configuration locale

  1. Cloner le code source dans votre répertoire de travail

  2. Définir les variables d’environnement

    • Créez une copie de .env.exemple nommée .env.

      Vous pouvez y définir vos propres valeurs, bien sûr, à condition qu’elles soient cohérentes avec le reste de la configuration.\

  3. Lier votre DOMAIN_NAME au localhost:

    • Ajoutez votre domaine local au fichier hosts : C:\Windows\System32\drivers\etc\hosts (sous Windows) et /etc/hosts (sous Linux).

      127.0.0.1 php-fpm.demo.domain
  4. Lancer les services avec docker compose:

    • Dans votre terminal, placez-vous dans votre répertoire de travail et exécutez:
      docker compose -f docker-compose.yaml -f up

Tests

  • Vérifiez que les conteneurs nginx et php-fpm sont en cours d’exécution et en bonne santé.

  • Ouvrez l’adresse que vous aviez configuré en tant que DOMAIN_NAME dans votre navigateur web (ex: https://php-fpm.demo.domain )
    Vous devriez avoir cette page:

    Traefik Dashboard


Analyse

  • Les réseaux Docker sont définis ici:

    ## docker-compose.yaml ##
    3networks:
    4    my-external-network:
    5        external: true
    6    my-internal-network:
    7        external: false
  • Le my-external-network est le seul exposé à l’extérieur et est utilisé par le conteneur nginx pour communiquer avec Traefik:

    ## docker-compose.yaml ##
     9services:
    10    nginx:
    11        image: nginx:alpine
    12        container_name: nginx
    13        volumes:
    14            # Mount the application source code into the Nginx container.
    15            - ./public:/var/www/html
    16            # Mount the custom Nginx configuration file.
    17            - ./docker/nginx/default.conf:/etc/nginx/conf.d/default.conf:ro
    18        networks:
    19            - my-external-network
    20            - my-internal-network
  • L’autre réseau (my-internal-network) est propre aux deux conteneurs nginx et php-fpm et sert uniquement à ces derniers pour communiquer entre-eux:

    ## docker-compose.yaml ##
    31    php-fpm:
    32        image: php:8.3-fpm-alpine
    33        container_name: php-fpm
    34        volumes:
    35            # Mount the application source code into the PHP-FPM container.
    36            - ./public:/var/www/html
    37        networks:
    38            - my-internal-network
  • Dans la configuration de Nginx suivante, la ligne clé est en surbrillance. Elle indique quel hôte Docker doit recevoir les requêtes .php et sur quel port

    ## default.conf ##
    14    # This location block specifically handles files ending in .php.
    15    location ~ \.php$ {
    16        # Ensure the file exists to prevent arbitrary code execution.
    17        try_files $uri =404;
    18
    19        # Pass the request to the PHP-FPM service.
    20        fastcgi_pass php-fpm:9000;
  • Voici un test simple montrant que php-fpm est configuré pour traiter les requêtes

    ## index.php ##
    54        <?php
    55            ob_start();
    56            phpinfo();
    57            $php_info = ob_get_clean();
    58
    59            $lines = explode("\n", $php_info);
    60            foreach ($lines as $line) {
    61                if (strpos($line, 'Server API') !== false) {
    62                    echo htmlspecialchars($line);
    63                    break;
    64                }
    65            }
    66        ?>
    

Pour conclure

La mise en place d’une stack web moderne avec Docker, Traefik, Nginx et PHP-FPM est une approche puissante pour construire une application robuste et évolutive. Elle représente un changement fondamental, passant des serveurs web monolithiques tout-en-un à une architecture plus efficace et découplée.

Cette séparation des responsabilités est l’avantage clé. Elle vous permet de faire évoluer chaque partie de votre application de manière indépendante, garantissant ainsi que votre site web reste performant et résilient en cas de forte charge.