Mise en Production Symfony (MEP). Déjouez les 6 pièges : gestion des secrets, Document Root sécurisé, cache prod et séquentiel des migrations. Guide de déploiement et commandes bash.
Développement Back-end Développement Web

Mise en Production de Symfony : Le Guide Anti-Pièges

💡 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 WebConfiguration à appliquer
NginxModifier la directive root du Virtual Host. Exemple : root /chemin/vers/votre/projet/**public**;
ApacheModifier le DocumentRoot dans la configuration du Virtual Host (méthode préférée) ou, à défaut, compter sur le .htaccess par défaut de Symfony dans le dossier public/.

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.

FichierContenu TypiqueStatut Versionnement GitRôle Principal
.envVariables par défaut (ex: APP_ENV=dev, APP_SECRET=changeme).OUIFichier de référence : indique les clés attendues par le projet.
.env.prodSurcharge des configurations non sensibles pour prod (ex: CACHE_POOL_NAME=redis).OUIConfigurations de production non sensibles.
*.local (y compris .env.local et .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 .gitignore doit contenir la ligne *.local pour 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.php sur 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 Encore ou l’option version dans config/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 :

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 :

  1. Déploiement du nouveau code.
  2. Mise à jour des dépendances.
  3. Exécution de la migration : bin/console doctrine:migrations:migrate --no-interaction.
  4. 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-nothing si 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 environnement prod pour 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
    

Laisser un commentaire

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