Dans cet article
- Un projet symfony docker se lance en moins de 5 minutes avec la stack dunglas/symfony-docker
- Le fichier docker-compose.yml orchestre au minimum 3 services : PHP, serveur web et base de données
- FrankenPHP remplace avantageusement le duo PHP-FPM + Nginx avec un gain de 30 à 40 % en performances
- La configuration multi-stage réduit la taille des images de production de 60 % en moyenne
- L’intégration de MySQL ou PostgreSQL dans Docker élimine les conflits de versions entre développeurs
- Le passage en production nécessite des ajustements sur les variables d’environnement, les volumes et le cache OPcache
Sommaire
- Pourquoi utiliser Docker avec Symfony
- Prérequis et outils nécessaires
- Installer Symfony Docker avec la stack Dunglas
- Configurer docker-compose manuellement
- Ajouter MySQL ou PostgreSQL à votre stack
- FrankenPHP : l’alternative moderne à PHP-FPM
- Optimiser votre configuration pour la production
- Erreurs fréquentes et solutions
Quand j’ai commencé à enseigner Symfony à mes étudiants en BTS SIO, la moitié du premier cours partait en configuration d’environnement. Chaque machine avait sa propre version de PHP, des extensions manquantes, un MySQL qui refusait de démarrer. Depuis que j’utilise symfony docker comme base de travail, ce problème a disparu. Chaque étudiant clone le dépôt, lance une commande, et tout fonctionne. Dans ce guide, je vous montre exactement comment reproduire cette configuration, que vous partiez de zéro ou que vous souhaitiez dockeriser un projet existant.
Pourquoi utiliser Docker avec Symfony
Docker résout un problème fondamental dans le développement Symfony : la cohérence des environnements. Sur un projet classique, le développeur A utilise PHP 8.3 sur macOS, le développeur B tourne sous PHP 8.2 sur Ubuntu, et le serveur de production fonctionne avec PHP 8.1 sous Debian. Les bugs liés à ces différences sont invisibles en local et explosent en production.
Avec Docker, vous définissez une seule configuration qui s’exécute de façon identique partout. Le fichier Dockerfile décrit précisément la version de PHP, les extensions installées, la configuration du serveur web. Le fichier docker-compose.yml orchestre tous les services : PHP, Nginx ou Apache, MySQL, Redis, Mailcatcher. Chaque membre de l’équipe travaille dans le même environnement, sans rien installer sur sa machine hôte en dehors de Docker lui-même.
L’écosystème Symfony a officiellement adopté Docker. Depuis Symfony 6.1, le composant symfony/runtime intègre un support natif de Docker via les variables d’environnement générées automatiquement. La documentation officielle recommande désormais Docker comme méthode d’installation privilégiée, ce qui facilite grandement la prise en main pour les débutants. Si vous découvrez Docker, je vous recommande de commencer par mon tutoriel Docker complet pour débutants avant de poursuivre ici.

Prérequis et outils nécessaires
Avant de lancer votre premier conteneur Symfony, vérifiez que votre poste de travail dispose des éléments suivants :
- Docker Engine version 24 ou supérieure (vérifiez avec
docker --version) - Docker Compose v2 (intégré à Docker Desktop, sinon installez le plugin
docker-compose-plugin) - Git pour cloner les dépôts et gérer vos versions
- Au moins 4 Go de RAM alloués à Docker (8 Go recommandés pour les projets avec Webpack Encore)
- Un éditeur de code comme VS Code ou PhpStorm avec le plugin Docker
Vous n’avez pas besoin d’installer PHP, Composer, Symfony CLI ou MySQL sur votre machine. Tout sera conteneurisé. C’est justement l’intérêt de la démarche. Pour bien comprendre le fonctionnement des images que nous allons utiliser, consultez mon article sur les images Docker et leur utilisation.
Installer Symfony Docker avec la stack Dunglas
La méthode la plus rapide pour démarrer un projet Symfony avec Docker reste la stack officielle maintenue par Kévin Dunglas. Ce projet, hébergé sur le dépôt GitHub dunglas/symfony-docker, est recommandé par la core team Symfony et utilisé en production par des centaines d’entreprises.
Voici les commandes pour créer un nouveau projet :
# Cloner la stack
git clone https://github.com/dunglas/symfony-docker.git mon-projet
cd mon-projet
# Lancer la construction et le démarrage
docker compose build --no-cache
docker compose up -d
Au premier lancement, Docker télécharge les images de base, installe les dépendances Composer et génère un certificat TLS local. Le processus prend entre 2 et 5 minutes selon votre connexion. Une fois terminé, votre application est accessible à l’adresse https://localhost.
Cette stack inclut par défaut FrankenPHP comme serveur d’application, Composer pour la gestion des dépendances, et un support complet des workers Symfony Messenger. Elle génère automatiquement les variables DATABASE_URL et MAILER_DSN grâce à l’intégration Docker de Symfony.
Pour un projet existant, copiez simplement les fichiers compose.yaml, compose.override.yaml et le dossier frankenphp/ dans votre répertoire de travail, puis adaptez la configuration.
Configurer docker-compose manuellement
Si vous préférez maîtriser chaque composant ou si votre projet nécessite une architecture spécifique avec PHP-FPM et Apache ou Nginx, voici comment construire votre configuration pas à pas.
Commencez par le fichier Dockerfile pour le service PHP :
FROM php:8.3-fpm-alpine
# Extensions PHP nécessaires à Symfony
RUN apk add --no-cache \
icu-dev \
libzip-dev \
&& docker-php-ext-install \
intl \
pdo_mysql \
zip \
opcache
# Installation de Composer
COPY --from=composer:latest /usr/bin/composer /usr/bin/composer
WORKDIR /var/www/html
COPY . .
RUN composer install --no-dev --optimize-autoloader
EXPOSE 9000
CMD ["php-fpm"]
Ensuite, créez le fichier docker-compose.yml qui orchestre vos services :
version: '3.8'
services:
php:
build:
context: .
dockerfile: Dockerfile
volumes:
- ./:/var/www/html
depends_on:
- database
environment:
DATABASE_URL: mysql://app:secret@database:3306/app_db?serverVersion=8.0
nginx:
image: nginx:alpine
ports:
- "8080:80"
volumes:
- ./:/var/www/html
- ./docker/nginx/default.conf:/etc/nginx/conf.d/default.conf
depends_on:
- php
database:
image: mysql:8.0
environment:
MYSQL_ROOT_PASSWORD: root
MYSQL_DATABASE: app_db
MYSQL_USER: app
MYSQL_PASSWORD: secret
volumes:
- db_data:/var/lib/mysql
ports:
- "3306:3306"
volumes:
db_data:
Il vous faut également le fichier de configuration Nginx (docker/nginx/default.conf) adapté à Symfony :
server {
listen 80;
server_name localhost;
root /var/www/html/public;
location / {
try_files $uri /index.php$is_args$args;
}
location ~ ^/index\.php(/|$) {
fastcgi_pass php:9000;
fastcgi_split_path_info ^(.+\.php)(/.*)$;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
fastcgi_param DOCUMENT_ROOT $realpath_root;
internal;
}
location ~ \.php$ {
return 404;
}
}
Lancez ensuite docker compose up -d --build et accédez à http://localhost:8080. Cette configuration manuelle vous donne un contrôle total sur chaque brique de votre infrastructure.

Ajouter MySQL ou PostgreSQL à votre stack
La base de données est le service le plus critique de votre stack symfony docker. Voici un comparatif pour choisir entre MySQL et PostgreSQL :
| Critère | MySQL 8.0 | PostgreSQL 16 |
|---|---|---|
| Image Docker officielle | mysql:8.0 (environ 580 Mo) | postgres:16-alpine (environ 230 Mo) |
| Support Doctrine | Natif, très répandu | Natif, types avancés (JSON, arrays) |
| Performance lecture | Excellent pour les requêtes simples | Excellent pour les requêtes complexes |
| Extensions Symfony | pdo_mysql | pdo_pgsql |
| Réplication Docker | Configuration manuelle | Streaming replication intégrée |
| Idéal pour | Projets classiques, CMS, e-commerce | Projets avec données géospatiales, recherche full-text |
Pour intégrer PostgreSQL à la place de MySQL, modifiez le service database dans votre docker-compose.yml :
database:
image: postgres:16-alpine
environment:
POSTGRES_DB: app_db
POSTGRES_USER: app
POSTGRES_PASSWORD: secret
volumes:
- db_data:/var/lib/postgresql/data
ports:
- "5432:5432"
Adaptez ensuite le DATABASE_URL dans votre fichier .env :
DATABASE_URL="postgresql://app:secret@database:5432/app_db?serverVersion=16&charset=utf8"
Un point important : utilisez toujours un volume nommé pour persister les données de votre base. Sans volume, vous perdez toutes vos données à chaque docker compose down. C’est une erreur que je vois régulièrement chez mes étudiants, et elle peut coûter des heures de travail. Pour gérer vos données efficacement, pensez à bien structurer votre application selon les principes du développement web full stack.
FrankenPHP : l’alternative moderne à PHP-FPM
FrankenPHP est un serveur d’application PHP construit sur Caddy, créé par Kévin Dunglas. Il remplace à la fois PHP-FPM et Nginx en un seul binaire. L’avantage pour un projet Symfony est considérable : une image Docker plus légère, des performances supérieures et une configuration simplifiée.
Voici ce que FrankenPHP apporte concrètement :
- Worker mode : l’application Symfony reste en mémoire entre les requêtes, éliminant le coût de bootstrap (gain de 30 à 40 % en temps de réponse)
- HTTPS automatique : certificats Let’s Encrypt générés et renouvelés sans intervention
- HTTP/3 et Early Hints (103) supportés nativement, améliorant le chargement des pages
- Image unique : plus besoin de deux conteneurs PHP-FPM + Nginx
Le Dockerfile avec FrankenPHP est plus concis :
FROM dunglas/frankenphp:latest-php8.3-alpine
RUN install-php-extensions \
intl \
pdo_mysql \
zip \
opcache
COPY --from=composer:latest /usr/bin/composer /usr/bin/composer
WORKDIR /app
COPY . .
RUN composer install --no-dev --optimize-autoloader
ENTRYPOINT ["frankenphp", "run", "--config", "/etc/caddy/Caddyfile"]
La stack dunglas/symfony-docker utilise FrankenPHP par défaut depuis fin 2023. Si vous démarrez un nouveau projet, c’est la solution que je recommande. La documentation officielle Symfony sur Docker détaille les configurations avancées pour exploiter pleinement le worker mode.
Optimiser votre configuration pour la production
Passer de l’environnement de développement à la production nécessite plusieurs ajustements. La sécurité, les performances et la fiabilité deviennent prioritaires.
Build multi-stage
Le build multi-stage sépare les étapes de construction et d’exécution. Résultat : une image finale qui ne contient ni Composer, ni les dépendances de développement, ni le code source non compilé.
# Étape 1 : construction
FROM php:8.3-fpm-alpine AS builder
COPY --from=composer:latest /usr/bin/composer /usr/bin/composer
WORKDIR /app
COPY composer.json composer.lock ./
RUN composer install --no-dev --no-scripts --optimize-autoloader
COPY . .
RUN composer dump-autoload --optimize
# Étape 2 : image finale
FROM php:8.3-fpm-alpine
RUN docker-php-ext-install intl pdo_mysql opcache
COPY --from=builder /app /var/www/html
RUN chown -R www-data:www-data /var/www/html/var
Cette approche réduit la taille de l’image finale de 60 % en moyenne, passant souvent de 800 Mo à moins de 300 Mo.

Configuration OPcache
En production, OPcache doit être configuré de manière agressive. Ajoutez ces paramètres dans un fichier docker/php/opcache.ini :
opcache.enable=1
opcache.memory_consumption=256
opcache.max_accelerated_files=20000
opcache.validate_timestamps=0
opcache.preload=/var/www/html/config/preload.php
opcache.preload_user=www-data
Le paramètre validate_timestamps=0 est essentiel en production : PHP ne vérifie plus si les fichiers ont changé sur le disque, ce qui améliore significativement les performances. En développement, laissez-le à 1 pour que vos modifications soient prises en compte immédiatement.
Variables d’environnement et secrets
Ne stockez jamais de secrets dans votre Dockerfile ou votre docker-compose.yml. Utilisez les Docker secrets ou un fichier .env.local monté en volume :
services:
php:
env_file:
- .env.prod.local
secrets:
- db_password
secrets:
db_password:
file: ./secrets/db_password.txt
La sécurité informatique est un sujet que je prends très au sérieux. Assurez-vous que vos fichiers de secrets sont dans votre .gitignore et jamais commités dans votre dépôt.
Health checks
Ajoutez des vérifications de santé à vos services pour que Docker redémarre automatiquement les conteneurs défaillants :
php:
healthcheck:
test: ["CMD", "php-fpm-healthcheck"]
interval: 30s
timeout: 5s
retries: 3
start_period: 40s
Erreurs fréquentes et solutions
Après plusieurs années à accompagner des développeurs dans leur découverte de symfony docker, voici les problèmes que je rencontre le plus souvent et leurs solutions :
| Erreur | Cause probable | Solution |
|---|---|---|
| Permission denied sur var/cache | UID/GID différents entre le conteneur et l’hôte | Ajoutez user: "${UID}:${GID}" dans le service PHP du compose |
| Connection refused sur port 3306 | Le service database n’est pas prêt | Utilisez depends_on avec la condition service_healthy |
| Composer out of memory | Limite mémoire PHP trop basse | Ajoutez COMPOSER_MEMORY_LIMIT=-1 en variable d’environnement |
| Fichiers non synchronisés | Volume mal configuré sur macOS/Windows | Utilisez la synchronisation Mutagen ou les volumes natifs Docker Desktop |
| HTTPS non fonctionnel en local | Certificat auto-signé non approuvé | Installez le certificat CA avec docker compose exec php symfony server:ca:install |
| Extensions PHP manquantes | Extensions non installées dans le Dockerfile | Ajoutez l’extension avec docker-php-ext-install ou install-php-extensions |
Un conseil que je donne systématiquement à mes étudiants : lisez les logs. La commande docker compose logs -f php affiche en temps réel tout ce qui se passe dans votre conteneur PHP. C’est la première chose à faire quand quelque chose ne fonctionne pas. Si vous êtes en formation et souhaitez approfondir ces compétences, renseignez-vous sur les formations informatiques à distance qui couvrent ces sujets.
Pour les problèmes de performances sur macOS, la lenteur des volumes montés est un problème connu. Depuis Docker Desktop 4.x, l’option VirtioFS améliore considérablement la vitesse de synchronisation des fichiers. Activez-la dans les préférences de Docker Desktop sous l’onglet « General ».
Si vous rencontrez des conflits de ports, vérifiez qu’aucun autre service n’utilise les ports 80, 443 ou 3306 sur votre machine hôte. Utilisez docker compose ps pour lister les conteneurs actifs et lsof -i :3306 pour identifier les processus occupant un port spécifique.
Pour aller plus loin dans la conteneurisation de vos applications, la maîtrise des outils de base du trio HTML, CSS et JavaScript reste indispensable pour bien structurer le frontend de vos projets Symfony. Le développement web sur mesure bénéficie énormément d’une infrastructure Docker bien pensée, car elle garantit la reproductibilité entre les environnements.
À retenir
- Utilisez la stack dunglas/symfony-docker pour démarrer un projet en moins de 5 minutes avec une configuration éprouvée
- Privilégiez FrankenPHP plutôt que PHP-FPM + Nginx pour simplifier votre stack et gagner en performances
- Configurez un build multi-stage pour réduire la taille de vos images de production de 60 %
- Utilisez toujours des volumes nommés pour vos bases de données afin d’éviter toute perte de données
- Activez OPcache avec validate_timestamps=0 en production pour des performances optimales
Questions fréquentes
Comment installer Symfony avec Docker en une seule commande ?
Clonez la stack officielle avec git clone https://github.com/dunglas/symfony-docker.git mon-projet, puis lancez docker compose up -d depuis le dossier du projet. Docker construit automatiquement les images, installe les dépendances Composer et démarre le serveur. Votre application est accessible à l’adresse https://localhost en quelques minutes.
Les deux sont parfaitement supportés par Doctrine et fonctionnent très bien dans Docker. MySQL convient aux projets classiques (CMS, e-commerce) tandis que PostgreSQL excelle pour les requêtes complexes, les données JSON et la recherche full-text. L’image PostgreSQL Alpine est aussi plus légère (230 Mo contre 580 Mo pour MySQL). Choisissez en fonction de vos besoins métier.Faut-il utiliser MySQL ou PostgreSQL avec Symfony Docker ?
FrankenPHP intègre un serveur web (Caddy) et PHP en un seul binaire, là où PHP-FPM nécessite un serveur web séparé comme Nginx ou Apache. FrankenPHP offre un worker mode qui garde l’application en mémoire entre les requêtes, réduisant le temps de réponse de 30 à 40 %. Il gère aussi automatiquement le HTTPS et supporte HTTP/3 nativement.Quelle est la différence entre FrankenPHP et PHP-FPM pour Symfony ?
Les erreurs de permission sur le dossier var/cache ou var/log proviennent d’une différence d’UID entre votre utilisateur hôte et l’utilisateur du conteneur. Ajoutez Comment résoudre les problèmes de permissions avec Docker et Symfony ?
user: "${UID}:${GID}" dans votre service PHP du docker-compose.yml. Vous pouvez aussi exécuter chown -R www-data:www-data var/ dans le Dockerfile pour attribuer les bons droits au dossier var.
Activez VirtioFS dans les préférences de Docker Desktop (onglet General) pour améliorer la vitesse de synchronisation des fichiers. Vous pouvez aussi utiliser Mutagen pour une synchronisation plus rapide des volumes. Enfin, excluez les dossiers vendor/ et var/ de la synchronisation en les plaçant dans des volumes nommés dédiés, ce qui réduit considérablement la latence.Comment optimiser les performances Docker pour Symfony sur macOS ?
Utilisez un build multi-stage pour réduire la taille de l’image. Désactivez le mode debug Symfony (APP_ENV=prod, APP_DEBUG=0). Configurez OPcache avec validate_timestamps=0 et activez le preloading. Stockez vos secrets via Docker secrets ou des fichiers .env.local montés en volume. Ajoutez des health checks à vos services pour garantir leur disponibilité.Comment passer un projet Symfony Docker en production ?
Formatrice IT indépendante depuis 2016, ancienne étudiante BTS SIO SLAM. 6 ans d'expérience en entreprise.