Deployer une application Symfony : checklist 2026
Le deploiement est le moment de verite. Votre code Symfony fonctionne en local, les tests passent, le client a valide - mais tout cela ne vaut rien si la mise en production est approximative. Voici une checklist methodique pour deployer Symfony en 2026, que vous utilisiez Deployer PHP, Docker ou un pipeline CI/CD.
Pre-deploiement : la checklist avant de lancer
Avant toute mise en production, verifiez systematiquement ces points. J'ai vu des deploiements echouer pour chacun d'entre eux, souvent un vendredi apres-midi :
- Variables d'environnement - toutes les variables de
.envsont definies sur le serveur (APP_ENV=prod,APP_SECRET,DATABASE_URL,MAILER_DSN) - APP_DEBUG=0 - jamais de debug en production, meme "juste pour tester"
- Dependances a jour -
composer install --no-dev --optimize-autoloader - Migrations testees - executez les migrations sur un dump de la base de production d'abord
- Cache warmup -
php bin/console cache:clear --env=prodsuivi decache:warmup - Assets compiles - si vous utilisez Webpack Encore ou AssetMapper, les assets doivent etre builds
- Tests verts - idealement automatises dans la CI, pas lances a la main
# Script de pre-deploiement - a automatiser
#!/bin/bash
set -e
echo "=== Pre-deployment checks ==="
# Verifier que les variables critiques sont definies
for var in APP_ENV APP_SECRET DATABASE_URL; do
if [ -z "${!var}" ]; then
echo "ERREUR: $var n'est pas defini"
exit 1
fi
done
# Verifier que APP_ENV est bien 'prod'
if [ "$APP_ENV" != "prod" ]; then
echo "ATTENTION: APP_ENV=$APP_ENV (devrait etre 'prod')"
exit 1
fi
echo "Variables d'environnement OK"
Deployer PHP : l'outil de reference
Deployer PHP est l'outil de deploiement le plus utilise dans l'ecosysteme Symfony. Il gere les releases atomiques, le zero-downtime et le rollback nativement. Voici une configuration complete :
// deploy.php
namespace Deployer;
require 'recipe/symfony.php';
set('application', 'mon-app-symfony');
set('repository', 'git@github.com:user/mon-app.git');
set('php_version', '8.3');
// Garder 5 releases pour le rollback
set('keep_releases', 5);
// Repertoires partages entre les releases
add('shared_dirs', ['var/log']);
add('shared_files', ['.env.local']);
// Repertoires avec permissions d'ecriture
add('writable_dirs', ['var/cache', 'var/log']);
host('production')
->set('remote_user', 'deploy')
->set('hostname', 'mon-serveur.example.com')
->set('deploy_path', '/var/www/mon-app');
// Taches personnalisees
task('deploy:build_assets', function () {
cd('{{release_path}}');
run('php bin/console asset-map:compile');
});
after('deploy:vendors', 'deploy:build_assets');
// Verifier la sante apres deploiement
task('deploy:healthcheck', function () {
$response = run('curl -s -o /dev/null -w "%{http_code}" http://localhost/health');
if ($response !== '200') {
throw new \RuntimeException("Health check echoue: HTTP $response");
}
writeln('Health check OK');
});
after('deploy:symlink', 'deploy:healthcheck');
Deployer cree une structure de repertoires comme celle-ci :
/var/www/mon-app/
current -> releases/3 # Lien symbolique vers la release active
releases/
1/ # Release precedente
2/ # Release precedente
3/ # Release courante
shared/
var/log/ # Logs partages
.env.local # Configuration locale
Le current est un lien symbolique. Quand Deployer bascule ce lien de releases/2 a releases/3, c'est atomique du point de vue du systeme de fichiers. Les requetes en cours finissent sur l'ancienne release, les nouvelles arrivent sur la nouvelle.
Pipeline CI/CD avec GitHub Actions
Un pipeline complet qui teste, build et deploie automatiquement :
# .github/workflows/deploy.yml
name: Test & Deploy
on:
push:
branches: [main]
jobs:
test:
runs-on: ubuntu-latest
services:
postgres:
image: postgres:16-alpine
env:
POSTGRES_PASSWORD: test
POSTGRES_DB: app_test
ports:
- 5432:5432
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
steps:
- uses: actions/checkout@v4
- uses: shivammathur/setup-php@v2
with:
php-version: '8.3'
extensions: intl, pdo_pgsql
coverage: xdebug
- run: composer install --prefer-dist --no-progress
- run: php bin/phpunit
deploy:
needs: test
runs-on: ubuntu-latest
if: github.ref == 'refs/heads/main'
steps:
- uses: actions/checkout@v4
- uses: shivammathur/setup-php@v2
with:
php-version: '8.3'
- run: composer install --prefer-dist --no-progress
- name: Deploy via Deployer
run: vendor/bin/dep deploy production -v
env:
SSH_PRIVATE_KEY: ${{ secrets.SSH_PRIVATE_KEY }}
Le job test s'execute en premier. Si les tests echouent, le deploiement ne se lance pas. Simple, efficace, pas de mauvaise surprise.
Zero-downtime : les pieges a eviter
Le zero-downtime deploy ne se limite pas a basculer un lien symbolique. Plusieurs elements peuvent casser la continuite :
- Sessions en fichier - si les sessions sont stockees dans
var/sessions, les utilisateurs perdent leur session a chaque deploiement. Utilisez Redis ou la base de donnees - Migrations destructives - un
ALTER TABLE DROP COLUMNcasse l'ancienne release qui tente encore de lire cette colonne. Deployez en deux etapes : d'abord le code qui n'utilise plus la colonne, puis la migration qui la supprime - Cache non partage - si le warmup genere un cache dans le repertoire de la release, l'ancienne release garde son ancien cache - c'est le comportement attendu
- Cron jobs - si un cron tourne sur l'ancienne release pendant le deploiement, il peut echouer. Utilisez des chemins absolus vers
current/
Migrations Doctrine en production
Les migrations meritent une attention particuliere. Voici les regles que j'applique :
# Generer la migration
php bin/console make:migration
# Verifier le SQL genere AVANT de l'executer
php bin/console doctrine:migrations:migrate --dry-run
# Executer en production (non-interactif)
php bin/console doctrine:migrations:migrate --no-interaction
# En cas de probleme : rollback
php bin/console doctrine:migrations:migrate prev
Ecrivez toujours la methode down() de vos migrations, meme si vous pensez ne jamais en avoir besoin. Le jour ou un deploiement echoue et que vous devez rollback, vous serez content de l'avoir fait.
Post-deploiement : les verifications
Apres chaque deploiement, verifiez systematiquement :
- Health check - l'endpoint
/healthretourne 200 - Logs - pas d'erreurs critiques dans
var/log/prod.log - Fonctionnalites cles - testez les parcours critiques (inscription, commande, paiement)
- Performances - le temps de reponse est-il dans les normes ?
- Monitoring - les metriques Sentry, Datadog ou Blackfire ne montrent pas d'anomalies
Strategie de rollback
Le rollback doit etre plus rapide que la correction. Avec Deployer :
# Rollback immediat vers la release precedente
dep rollback production
# Lister les releases disponibles
dep releases production
En moins de 5 secondes, votre application est revenue a l'etat precedent. C'est pourquoi Deployer garde les anciennes releases (keep_releases: 5 par defaut).
Pour les migrations de base de donnees, le rollback est plus complexe. Si la migration est incompatible avec l'ancien code, vous etes bloque. La solution : ne jamais deployer de migrations destructives en meme temps que le code qui en depend.
Monitoring post-deploiement
Un deploiement reussi ne veut pas dire que tout va bien. Mettez en place un monitoring minimum :
- Sentry - capture les exceptions PHP en temps reel via le bundle
sentry/sentry-symfony - Uptime monitoring - un service externe (UptimeRobot, Pingdom) verifie que le site repond
- Log aggregation - centralisez les logs avec Monolog + un handler Graylog ou Elasticsearch
Aller plus loin
Si vous conteneurisez votre application, consultez l'article Symfony dans Docker : Dockerfile production-ready pour la partie build d'image. Pour les commandes Symfony utiles en deploiement, la cheatsheet CLI Symfony est un bon aide-memoire. Et pour optimiser les performances apres deploiement, voyez le guide sur le cache Symfony PSR-6/PSR-16.
Vous planifiez un deploiement Symfony et souhaitez un accompagnement ? Decouvrez mes services et mes tarifs, puis contactez-moi pour discuter de votre projet. Je travaille en tant que freelance entre la France et la Belgique sur des projets Symfony de toutes tailles.
