Ce que change FrankenPHP
FrankenPHP est un serveur d'application PHP écrit en Go, construit sur Caddy. Il embarque directement l'interpréteur PHP dans le binaire du serveur web : plus besoin de séparer Nginx et PHP-FPM, ni de gérer un socket Unix entre les deux. Un seul processus sert les requêtes, gère le HTTPS automatique (Let's Encrypt) et HTTP/3, et peut charger l'application en worker mode pour éviter de rebootstrapper le framework à chaque requête.
Dockerfile minimal
L'image officielle dunglas/frankenphp sert de base. Un Dockerfile typique pour une app Symfony ou Laravel ressemble à ceci :
FROM dunglas/frankenphp:1-php8.3
RUN install-php-extensions \
pdo_pgsql \
opcache \
zip
COPY . /app
WORKDIR /app
RUN composer install --no-dev --optimize-autoloader
ENV SERVER_NAME=":80"
ENV FRANKENPHP_CONFIG="worker ./public/index.php"
EXPOSE 80
La variable SERVER_NAME pilote le comportement Caddy (domaine, port, HTTPS auto). Le FRANKENPHP_CONFIG active le mode worker : le script index.php est chargé une fois en mémoire, puis FrankenPHP lui délègue chaque requête via une boucle, à la manière de Swoole ou RoadRunner.
Le mode worker, avec précaution
En mode classique, chaque requête recharge le framework depuis zéro, comme avec PHP-FPM. En mode worker, l'état PHP (connexions DB, conteneur de services) reste résident entre les requêtes : gain de performance important, mais attention aux fuites d'état. Toute variable statique ou singleton mal réinitialisé entre deux requêtes peut fuiter d'un utilisateur à l'autre. Symfony et Laravel exposent des points d'entrée dédiés (frankenphp-worker.php, package laravel/octane avec le driver FrankenPHP) qui réinitialisent proprement le conteneur de services à chaque itération.
Docker Compose pour le développement
services:
app:
build: .
ports:
- "80:80"
- "443:443"
volumes:
- ./:/app
- caddy_data:/data
environment:
SERVER_NAME: "localhost"
volumes:
caddy_data:
Le volume caddy_data conserve les certificats TLS générés automatiquement entre les redémarrages du conteneur.
Points d'attention en production
- Compiler les extensions PHP nécessaires au build via
install-php-extensions, pas au runtime. - Activer
opcacheavecopcache.preloadpointant vers l'autoload Composer pour cumuler les gains du worker mode. - Séparer les workers HTTP des workers de queue (Symfony Messenger, Laravel Queue) : ne pas faire tourner les jobs asynchrones dans le même worker que le serveur web.
- Surveiller la mémoire : un worker qui vit longtemps peut accumuler des fuites invisibles en mode FPM classique.