Ce que FrankenPHP change dans un conteneur
FrankenPHP est un serveur d'application écrit en Go qui embarque Caddy et le moteur PHP dans un seul binaire. Contrairement au duo classique nginx + php-fpm, il n'y a plus deux processus à orchestrer ni de socket FastCGI à configurer : un seul conteneur suffit, ce qui simplifie nettement le Dockerfile et le déploiement.
Image de base
L'image officielle dunglas/frankenphp fournit déjà PHP compilé avec les extensions courantes et Caddy intégré. Un Dockerfile minimal pour une application Symfony ou Laravel ressemble à ceci :
FROM dunglas/frankenphp:1-php8.3
WORKDIR /app
RUN install-php-extensions \
pdo_pgsql \
opcache \
zip \
intl
COPY . /app
COPY frankenphp/Caddyfile /etc/caddy/Caddyfile
RUN composer install --no-dev --optimize-autoloader
Le script install-php-extensions, préinstallé dans l'image, évite de recompiler PHP à la main.
Mode worker : le vrai gain de performance
Le mode classique (vanilla) réexécute le framework à chaque requête, comme avec php-fpm. Le mode worker garde l'application en mémoire entre les requêtes, à la manière d'un runtime Node.js ou de Swoole, ce qui réduit fortement la latence sur les frameworks lourds. Il s'active dans le Caddyfile :
{
frankenphp {
worker /app/public/index.php
num_threads 4
}
}
:80 {
root * /app/public
php_server
}
Attention : en mode worker, l'état global n'est plus réinitialisé automatiquement entre les requêtes. Il faut que le framework gère lui-même le reset du conteneur de services (Symfony le fait nativement depuis la 6.3 via le composant runtime, Laravel via Octane).
Variables d'environnement utiles
FRANKENPHP_CONFIG— injecte des directives Caddyfile directement depuis l'environnement, pratique pour un déploiement sans fichier de config versionné.SERVER_NAME— définit le nom d'hôte écouté par Caddy, y compris pour l'obtention automatique de certificats TLS via Let's Encrypt.CADDY_GLOBAL_OPTIONS— ajuste des options globales comme la désactivation d'auto-HTTPS en environnement de dev.
Points de vigilance
- Le mode worker complique le débogage : une fuite mémoire ou une variable statique mal réinitialisée persiste entre requêtes.
- Les extensions PHP compilées statiquement dans l'image ne peuvent pas être ajoutées à chaud ; toute extension supplémentaire nécessite un rebuild.
- Pour le multi-stage, séparez la compilation des assets front (Node) de l'étape FrankenPHP finale afin de garder l'image de production légère.