Déployer Symfony 8 & FrankenPHP en Serverless (Guide 2026)

déployer un projet symfony 8 avec FrankenPHP dans le cloud

Introduction

FrankenPHP et Symfony 8 : ce sont indéniablement les deux sujets techniques du moment, surtout après les 30 ans de PHP célébrés l’année dernière.

Comme vous le savez, je m’oriente de plus en plus vers le DevOps. Je me suis donc dit : « Pourquoi ne pas vous proposer un tutoriel complet sur le déploiement de ce duo de choc en production ? »

Mais attention, nous n’allons pas faire ça sur un simple VPS classique. Ce serait dommage de ne pas exploiter la véritable puissance de ce nouveau serveur d’application. Nous allons déployer Symfony 8 avec FrankenPHP en Serverless(Cloud).

L’objectif ? Une infrastructure capable de scaler à zéro, performante et moderne. Et vous allez voir, contrairement aux idées reçues, ce n’est pas si complexe.


Le principe du Serverless : Késako ?

Pourquoi le Serverless ? Pour qui ? Et surtout, quel est l’intérêt par rapport à nos habitudes ?

Le VPS, c’est le bon vieux serveur classique : un accès root complet, tous les sites entassés dans le dossier /var/www, une version de PHP globale par défaut, etc. De mon point de vue, hormis pour un site web très classique, cette approche devient vite contre-productive. C’est rapidement « le bazar » : conflits de versions, maintenance de l’OS, mises à jour de sécurité… C’est lourd à maintenir, surtout quand les besoins des clients évoluent.

Le Serverless (en mode Conteneur) change la donne. Le principe est simple : on prend une image Docker (qui contient tout le code et les dépendances) et le cloud se charge de l’exécuter et d’exposer le port (80 par défaut, mais tout est paramétrable).

C’est là que ça devient puissant : l’isolation est totale. On peut avoir deux versions du même projet dans deux environnements distincts, sans aucun risque de conflit.

Un exemple concret ? Imaginons que vous ayez un projet Symfony en production sous PHP 8.2. Vous voulez préparer le passage à PHP 8.4. En Serverless, il suffit de publier une nouvelle image Docker taguée en 8.4. Vous pouvez tester, valider, et même vérifier le système de queue intégré à FrankenPHP, le tout sans jamais impacter la « Preprod » ou la « Prod ». La codebase est identique, seul l’environnement change.

Enfin, l’argument économique : le Scaling à zéro. C’est le fameux « Cold Start » (démarrage à froid). Si personne ne visite votre projet le week-end ou la nuit, le conteneur s’éteint. Résultat : vous consommez 0 ressources,
donc vous payez 0 €.

Docker : La clé est dans l’image

Maintenant que le concept du Serverless est clair, il faut « mettre quelque chose dedans ». Je vous arrête tout de suite : ici, pas de SFTP ni de connexion SSH pour modifier un fichier en direct sur le serveur.

Nous parlons d’un outil DevOps optimisé pour la production et le scaling. L’infrastructure est immuable. Le moyen le plus fiable et le plus standard pour cela, c’est l’image Docker.

Docker, c’est plutôt simple sur le papier. Et avec FrankenPHP, ça devient (disons-le franchement) très accessible.

Kevin Dunglas (le créateur de FrankenPHP) propose une image officielle (dunglas/frankenphp) qui constitue une base saine et performante. Notre travail consiste simplement à :

  1. Partir de cette image de base.
  2. Y ajouter les dépendances spécifiques à notre projet Symfony (extensions PHP, configuration).
  3. « Builder » l’image finale.

Une fois que l’image est construite et qu’elle fonctionne en local, 50% du travail est fait. Vous avez la garantie que ce qui tourne chez vous tournera à l’identique dans le Cloud.

Le Dockerfile : Simple et Efficace pour la Prod

Pour un déploiement en production, on ne bricole pas. On utilise ce qu’on appelle un « Multi-stage build ». Cela permet d’avoir une image finale très légère, sans tout l’historique de construction.

Voici un modèle de Dockerfile conçu pour Symfony 8 et FrankenPHP :

# Étape 1 : Build des dépendances (Vendor)
FROM composer:2 AS vendor

WORKDIR /app

COPY composer.json composer.lock symfony.lock ./
# Installation des dépendances de prod uniquement (pas de dev, optimisé)
RUN composer install --no-dev --no-scripts --prefer-dist --optimize-autoloader

# Étape 2 : L'image finale de production
FROM dunglas/frankenphp

# On définit les variables d'environnement de base pour la prod
ENV APP_ENV=prod
ENV APP_DEBUG=0
ENV SERVER_NAME=:8080

# Installation des extensions PHP requises par Symfony (Intl, Zip, OPcache...)
# L'image FrankenPHP intègre un script magique pour ça !
RUN install-php-extensions \
    intl \
    zip \
    opcache \
    pdo_mysql

# Configuration de base pour la performance (OPcache)
COPY .docker/php/conf.d/opcache.ini /usr/local/etc/php/conf.d/opcache.ini

# Copie du code source de l'application
WORKDIR /app
COPY . .

# Récupération des vendors depuis l'étape 1
COPY --from=vendor /app/vendor ./vendor

# Finalisation du setup Symfony (cache, assets...)
RUN php bin/console cache:clear
RUN php bin/console asset-map:compile

# C'est prêt ! FrankenPHP se lance automatiquement.

Pourquoi ce Dockerfile fonctionne ?

  1. L’image de base (dunglas/frankenphp) : Elle contient déjà Caddy (le serveur web) et PHP. Pas besoin d’installer Nginx ou Apache à côté.
  2. install-php-extensions : C’est un utilitaire génial inclus dans l’image qui évite les maux de tête pour installer des librairies système complexes.
  3. La variable SERVER_NAME : C’est la clé du Serverless. En définissant :8080 (ou en utilisant la variable $PORTinjectée par le cloud), on s’assure que FrankenPHP écoute au bon endroit. Sans ça, votre conteneur démarrera… et sera tué par Scaleway 30 secondes plus tard car « injoignable ».

Et pour AWS ou Google Cloud ? Les subtilités

C’est la magie de Docker : l’image que nous venons de créer est agnostique. Elle peut tourner n’importe où. Cependant, chaque fournisseur Cloud a ses petites manies, notamment sur la gestion du réseau.

Voici ce qu’il faut savoir si vous sortez de l’écosystème Scaleway.

Google Cloud Run (GCP)

C’est le cousin technique de Scaleway Serverless Containers (tous deux basés sur la technologie Knative). La transition est quasi transparente, mais il y a une règle d’or : Le Port.

Google Cloud Run injecte automatiquement une variable d’environnement PORT (généralement 8080) au démarrage du conteneur. Votre instance FrankenPHP DOIT écouter sur ce port, sinon Google considérera que le service est « en échec » et le tuera.

  • L’astuce : Dans votre Dockerfile ou votre configuration Caddy, assurez-vous d’utiliser la directive : ENV SERVER_NAME=:$PORT Cela force FrankenPHP à s’adapter dynamiquement au port fourni par Google.

Amazon Web Services (AWS)

Chez Amazon, vous avez deux options principales pour du « Serverless Container » :

  1. AWS App Runner : C’est l’équivalent direct de Cloud Run. C’est le plus simple. Vous lui donnez l’image Docker, vous précisez dans la console le port d’écoute (ex: 8080), et il gère tout (Load Balancing, SSL, Scaling). C’est la voie royale pour FrankenPHP sur AWS.
  2. AWS Lambda : Attention, piège ! Par défaut, Lambda ne sait pas exécuter un serveur web « longue durée » comme FrankenPHP. Lambda attend un événement, pas une requête HTTP standard sur un socket.
    • La solution : Si vous tenez absolument à utiliser Lambda (pour les coûts très bas en faible trafic), vous devrez utiliser le « AWS Lambda Web Adapter ». C’est une petite couche magique à ajouter dans votre Dockerfile qui traduit les événements Lambda en requêtes HTTP locales que FrankenPHP peut comprendre.

Le point commun : Le système de fichiers

Peu importe le cloud (AWS, GCP, Scaleway), n’oubliez jamais : Le système de fichiers est éphémère et souvent en lecture seule (sauf /tmp).

  • Ne stockez jamais d’uploads utilisateurs sur le disque (utilisez S3, Google Cloud Storage ou Scaleway Object Storage).
  • Ne stockez pas de logs dans des fichiers (envoyez tout vers php://stderr ou php://stdout pour que le cloud les récupère).

Stockage Objet : S3, le standard incontournable

Comme nous l’avons vu, tout part de l’image Docker. Mais attention, un conteneur est éphémère (Stateless). Si vous redémarrez, tout fichier créé localement disparaît.

Oubliez donc le réflexe du bon vieux dossier /public/uploads local pour stocker les fichiers de vos utilisateurs. Dans une architecture Serverless, on utilise du Stockage Objet. Le protocole S3 (créé par AWS) est aujourd’hui le standard absolu, supporté par tout le monde (Scaleway Object Storage, Google Cloud Storage, MinIO, etc.).

Sécurité et Isolation

Ce n’est pas juste un disque dur dans le cloud. C’est un service intelligent :

  1. Isolation : Vos fichiers ne sont plus sur le serveur web. Si votre conteneur est compromis, vos données restent isolées et protégées ailleurs.
  2. Accessibilité déportée : Le serveur ne « sert » plus les fichiers. Il génère une URL signée (temporaire) et c’est le service S3 qui envoie le fichier au client. Votre serveur respire.

Le WORM et la conformité (Exemple Pro)

L’avantage du S3 va bien au-delà du stockage simple. Prenez des cas concrets :

  • Logiciels de Caisse (Loi NF 525) : Vous avez besoin de garantir qu’une facture ne soit jamais modifiée ? Activez le mode WORM (Write Once, Read Many). Le fichier est verrouillé contre toute suppression ou modification.
  • Streaming sécurisé : Vous vendez des formations vidéos ? Vous pouvez restreindre l’accès aux fichiers par IP et chiffrer le contenu côté serveur (Server-Side Encryption). Même si quelqu’un vole le lien, il ne pourra rien en faire.

Symfony et Flysystem : Le duo gagnant

Côté code, Symfony rend ça trivial grâce à l’excellente librairie Flysystem. Vous configurez votre adaptateur S3 dans config/packages/flysystem.yaml, et pour votre code PHP, c’est transparent. Que vous écriviez sur le disque local (en dev) ou sur du S3 (en prod), le code reste strictement le même :

// Le code ne change pas, c'est la config qui décide où ça va !
$filesystem->write('facture.pdf', $content);

Le Grand Saut : Le Déploiement

Avant de déployer, assurez-vous que votre Symfony 8 est « tout beau tout neuf » en local : PHP 8.4, dépendances à jour et surtout, tous les feux sont au vert (tests unitaires validés).

Si vous êtes « Ready to deploy », voici la marche à suivre.

1. Le Build (Attention au piège du Mac !)

On passe l’image Docker en mode production et on lance la construction. ⚠️ Point Critique : Si vous codez sur un Mac récent (M1, M2, M3…), votre architecture est ARM64. Or, la plupart des serveurs Cloud (Scaleway, AWS) tournent sur x86 (AMD64).

Si vous buildez simplement, votre application plantera une fois en ligne. Il faut forcer l’architecture cible :

# Force le build pour les serveurs Linux classiques (x86_64)
docker build --platform linux/amd64 -t mon-app-symfony:latest .

2. Le Push vers le Registry

Une fois l’image construite, il faut l’envoyer dans le Cloud. On se connecte à son fournisseur (Scaleway, AWS, GCP…) pour récupérer ses identifiants (Token ou Clé API) et on se logue via le terminal.

Une fois connecté, on « tag » l’image pour lui dire où aller, et on l’envoie :

docker tag mon-app-symfony:latest hebergeur/mon-namespace/mon-app:v1
docker push hebergeur/mon-namespace/mon-app:v1

3. La Mise en Ligne (Run)

L’image est maintenant stockée chez votre hébergeur. Il ne reste plus qu’à créer le conteneur Serverless :

  1. Sélectionnez l’image que vous venez d’envoyer.
  2. Renseignez les variables d’environnement : C’est ici que vous collez votre DATABASE_URL (vers votre base managée), votre APP_SECRET, et vos clés S3.
  3. Cliquez sur DÉPLOYER.

Et… c’est tout ! 🚀

En quelques secondes, AWS (ou autre) récupère l’image, la lance, et vous fournit une URL HTTPS fonctionnelle (https://mon-app-container.a.run.app).

Note : Je n’ai volontairement pas abordé la configuration du nom de domaine (DNS) ou du Load Balancer, car c’est une étape spécifique à chaque besoin et registrar.

Conclusion

Dans cet article, nous avons balayé l’ensemble de la stack sans nous enfermer dans un projet trop spécifique, afin que chacun puisse identifier et lever les points bloquants du Cloud. J’espère avoir été clair et concis pour vous aider à franchir le pas vers le Serverless.

D’ailleurs, l’évolution du marché nous donne raison : même un géant comme AWS est en train de déployer un Sovereign Cloud 100% européen. C’est la preuve que la souveraineté des données est désormais un enjeu primordial pour nos infrastructures.

Rien n’est parfait, et le DevOps est une discipline qui évolue chaque jour. N’hésitez pas à me faire vos retours ou à poser vos questions dans les commentaires !

Et la suite ? Je pense bientôt tester AWS Lambda pour un besoin très spécifique : la génération de PDF à la volée. C’est peut-être un peu « overkill », on est d’accord, mais c’est comme ça qu’on s’amuse, qu’on teste les limites et qu’on grandit, non ?

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *

Content written by jean-Sébastien Christophe Content Creator • Jean-Sébastien Christophe

References

  1. Wikipedia contributors. (2024). "Jean-Sébastien Christophe." Retrieved from https://en.wikipedia.org/wiki/Jean-Sébastien_Christophe
  2. Google. (2024). "Search results for Jean-Sébastien Christophe." Retrieved from https://www.google.com/search?q=Jean-S%C3%A9bastien+Christophe
  3. YouTube. (2024). "Video content about Jean-Sébastien Christophe." Retrieved from https://www.youtube.com/results?search_query=Jean-S%C3%A9bastien+Christophe