💡 Symfony en Prod : Déjouer les 6 Pièges de la Première Mise en Ligne
C’est un fait : maîtriser Symfony en local est une chose ; le déployer proprement en production en est une autre. Pour certains, c’est une routine. Pour les autres, la Mise en Production (MEP) est souvent semée d’embûches qui n’ont rien à voir avec le code.
Voici la checklist pour déjouer les pièges classiques et garantir le succès immédiat de votre déploiement.
1 – Piège N°1 : Le Document Root Incorrect (/public vs /)
La plus grande erreur de sécurité est de faire pointer le nom de domaine vers la racine du projet, exposant ainsi les dossiers sensibles.
Le Problème
Exposer l’intégralité du code source (e.g., .env, vendor/) en cas de mauvaise configuration.
La Solution
Le serveur web doit pointer exclusivement vers le répertoire public/.
Si vous servez du PHP-FPM : vérifiez que la fastcgi_param SCRIPT_FILENAME pointe bien vers public/index.php (Nginx) pour éviter l’exécution hors public/.”
(Ça évite les VHost mal câblés qui routent vers index.php à la racine.)
| Serveur Web | Configuration à appliquer | 
| Nginx | Modifier la directive rootdu Virtual Host. Exemple :root /chemin/vers/votre/projet/**public**; | 
| Apache | Modifier le DocumentRootdans la configuration du Virtual Host (méthode préférée) ou, à défaut, compter sur le.htaccesspar défaut de Symfony dans le dossierpublic/. | 
2 – Piège N°2 : La Confusion des Variables et des Secrets d’Environnement
C’est la section la plus critique. La gestion des configurations est une discipline d’ingénierie qui repose sur la séparation stricte des valeurs par défaut, des valeurs d’environnement et des secrets.
A. La Règle de Versionnement Stricte des Fichiers .env
Le skeleton moderne de Symfony versionne plusieurs fichiers .env qui définissent des valeurs non sensibles. Les fichiers sensibles (.local) ne doivent jamais être versionnés.
La sécurité passe par le fichier .gitignore. Tout ce qui est sensible ou local doit en être exclu.
| Fichier | Contenu Typique | Statut Versionnement Git | Rôle Principal | 
| .env | Variables par défaut (ex: APP_ENV=dev,APP_SECRET=changeme). | OUI | Fichier de référence : indique les clés attendues par le projet. | 
| .env.prod | Surcharge des configurations non sensibles pour prod(ex:CACHE_POOL_NAME=redis). | OUI | Configurations de production non sensibles. | 
| *.local(y compris.env.localet.env.prod.local) | TOUS les secrets locaux et surcharges sensibles. | NON (doit être dans .gitignore) | Contient les secrets d’un développeur ou d’un serveur spécifique. | 
Règle absolue : Tout fichier qui, par convention (comme .env.dev) ou par suffixe (.local), est destiné à contenir un secret, une clé privée ou un mot de passe en clair, doit être exclu du dépôt Git.
Action : Votre
.gitignoredoit contenir la ligne*.localpour garantir que les vrais secrets (mots de passe, clés d’API) ne sont jamais accidentellement committés.
En prod : privilégiez variables d’environnement +composer dump-env prod(génère.env.local.phpsur le serveur/deploy, non dans le repo).”
B. La Gestion des Secrets Sensibles en Production
Les secrets ne doivent pas être définis dans des fichiers déployés.
Méthode Professionnelle (Préférée)
Définir les clés secrètes directement comme des variables d’environnement système (via le VPS, le panneau d’hébergement ou l’outil de conteneurisation comme Kubernetes). Ces variables ont la plus haute priorité et écrasent toutes les valeurs dans les fichiers .env.*.
Alternative (via Symfony)
Utiliser le système de Secrets natif de Symfony pour chiffrer les clés de manière sécurisée et les déchiffrer seulement en production.
3 – Piège N°3 : Le Cache et le Mode Production
L’application doit impérativement utiliser le mode prod avec un cache construit et optimisé.
Le Problème
L’application tourne en mode débogage ou sans cache optimisé, ce qui impacte la performance et la sécurité.
La Solution
S’assurer que la variable d’environnement APP_ENV=prod est définie avant l’exécution de ces commandes :
# 1. Installer sans les outils de dev et optimiser l'autoloader
composer install --no-dev --optimize-autoloader --classmap-authoritative
# 2. Nettoyer et préchauffer le cache de production
bin/console cache:clear
bin/console cache:warmup   
    
🆘 Solutions d’Urgence et Astuces Avancées
Si, pour une raison obscure (permissions, accès limité, etc.), le cache:clear échoue ou ne résout pas le problème :
Solution de dernier recours (Brute Force)
Si les permissions vous bloquent, vous pouvez supprimer manuellement le contenu du répertoire var/cache/ (sauf le dossier .gitignore qu’il contient).
rm -rf var/cache/*
    
Attention : Cela nécessite de reconstruire le cache (cache:warmup) juste après et de corriger le problème de permissions sous-jacent.
Astuce pour forcer le rechargement des assets (Frontend)
Lors d’une mise à jour de CSS ou JS, le cache navigateur ou CDN peut être trop agressif. Pour forcer les clients à recharger la nouvelle version, utilisez le versioning des URLs d’assets :
- Méthode propre Symfony (Filtrage) : Configurer un Asset Versioning Strategy (via Webpack Encoreou l’optionversiondansconfig/packages/framework.yaml) pour ajouter automatiquement un hash ou un horodatage (timestamp) aux URLs de vos assets (ex:app.css?v=202510261808).
- Méthode Manuelle (Urgence) : Si vous n’utilisez pas de versioning automatique, ajoutez manuellement un paramètre de requête arbitraire (un “cache-buster”) à la fin de l’URL dans votre gabarit (Twig) lors du déploiement :
 
- Méthode propre Symfony (Filtrage) : Configurer un Asset Versioning Strategy (via 
ATTENTION : Évitez le timestamp dynamique en prod si vous avez du CDN : préférez hash de contenu (Encore/AssetMapper) pour profiter d’
immutable.
< link rel="stylesheet" href="/assets/css/app.css?v={{ date('YmdHis') }}">
4 – Piège N°4 : Le Séquençage des Migrations
Les migrations de base de données doivent être exécutées avec soin pour garantir la continuité de service.
Le Problème
Le nouveau code utilise une structure de base de données non encore appliquée, provoquant des erreurs en cascade.
La Solution
L’ordre de déploiement idéal est :
- Déploiement du nouveau code.
- Mise à jour des dépendances.
- Exécution de la migration : bin/console doctrine:migrations:migrate --no-interaction.
- Nettoyage et réchauffage du cache (Piège N°3).
Gérer la compatibilité ascendante
- Déployer du code compatible avec l’ancienne DB avant d’exécuter la migration (zéro-downtime).
- Éviter DROP/renommages destructifs dans la même release ; faire en deux temps (ajout → code lit/écrit les deux → nettoyage).
- Lancer doctrine:migrations:migrate --no-interaction --all-or-nothingsi vous avez activé les transactions globales (sinon préciser pourquoi).”
5 – Piège N°5 : Les Permissions du Cache et des Logs
Un classique de l’hébergement qui génère des erreurs cryptiques 500.
Le Problème
Le serveur web (www-data, nginx) n’a pas les droits d’écriture dans les dossiers var/cache et var/log.
La Solution
Utiliser les commandes de permission standard pour garantir les droits en écriture à l’utilisateur CLI (vous) et à l’utilisateur du serveur web :
# Méthode préférée (si ACL est disponible)
sudo setfacl -R -m u:www-data:rwX -m u:$(whoami):rwX var
sudo setfacl -dR -m u:www-data:rwx -m u:$(whoami):rwx var  
# Sans ACL
sudo chown -R www-data:www-data var
sudo find var -type d -exec chmod 775 {} \;
sudo find var -type f -exec chmod 664 {} \;
    
Systemd/PHP-FPM : Alignez l’utilisateur du service PHP-FPM (
user=) avec celui du serveur web ou utilisez ACL.
6 – Piège N°6 : L’Illusion du CORS en Production
Ceci est crucial pour une architecture découplée (Symfony API + SPA).
La Confusion
“J’ai dû configurer le CORS en local, donc je dois le laisser en production.”
La Réalité
Si votre frontend et votre API sont servis par le même domaine en production (méthode recommandée), le CORS n’est plus nécessaire. Il ne servait qu’à autoriser le port de développement de votre SPA (ex: :5173).
Si vous utilisez cookies HttpOnly et que frontend ≠ domaine API, vous devez soit unifier les domaines, soit basculer vers OAuth2/OIDC/JWT (ou CORS + credentials + cookies cross-site bien réglés, mais surface d’attaque plus large). En même domaine, désactivez CORS.
Action : Désactivez ou supprimez les configurations CORS (e.g., dans
nelmio_cors.yaml) en environnementprodpour réduire la surface d’attaque inutile.
Conclusion : La Checklist du Succès Imminent
En maîtrisant ces six étapes, vous automatisez le processus de mise en production et garantissez que votre code Symfony est déployé de manière sécurisée, performante et stable. C’est le marqueur d’un ingénieur qui travaille pour le monde réel.
# PROD QUICK CHECK (Symfony)
echo "$APP_ENV / $APP_DEBUG" # doivent être prod / 0
test -f public/index.php     # docroot = public/
php bin/console about --env=prod
# Composer & cache
composer install --no-dev --optimize-autoloader
                 --classmap-authoritative
bin/console cache:pool:clear cache.global_clearer 
                       && bin/console cache:warmup
# Migrations
bin/console doctrine:migrations:migrate --no-interaction
                     --all-or-nothing
# Permissions (fallback sans ACL)
sudo chown -R www-data:www-data var && \
sudo find var -type d -exec chmod 775 {} \; && \
sudo find var -type f -exec chmod 664 {} \;
# Sanity
curl -I https://ton.domaine.tld/ | grep -E
     'strict-transport|content-security|referrer-policy' -i
    


 
										