← Tous les articles
June 30, 2026

Docker Volumes : Bien choisir entre Volumes Managés et Bind Mounts (Retour d’expérience Laravel + Nginx)

Développement Web PHP IT Laravel #Docker #docker-compose #Devops

Quand on déploie une application web avec Docker, surtout une stack Laravel + PHP-FPM + Nginx, la gestion du stockage persistant devient rapidement un sujet critique.

Entre volumes managés et bind mounts, le mauvais choix peut provoquer :

  • des problèmes de permissions,
  • des conflits entre utilisateurs Docker et système,
  • des fichiers invisibles pour Nginx,
  • ou encore des performances dégradées.

Après plusieurs architectures testées en production, voici le meilleur compromis que j’ai trouvé.

Comprendre les deux types de volumes Docker

1. Bind Mounts

Le bind mount lie directement un dossier de la machine hôte au container.


volumes:
    - ./project:/var/www

Avantages :

  • Parfait pour le développement
  • Accès direct aux fichiers depuis l’hôte
  • Hot reload immédiat
  • Facile pour Git

Inconvénients :

  • Permissions souvent compliquées entre les utilisateurs du container docker et l’hôte
  • Conflits UID/GID
  • Performances parfois moins bonnes
  • Dépendance à la structure de l’hôte

2. Volumes managés Docker

Docker gère lui-même le stockage.


volumes:
    laravel_storage:

services:
    app:
        volumes:
            - laravel_storage:/var/www/storage

Avantages :

  • Permissions plus propres et géré par docker
  • Isolation parfaite
  • Plus fiable en production
  • Meilleures performances Linux

Inconvénients :

  • Moins accessible directement
  • Toujours penser à mettre à jour pendant le déploiement
  • Debug moins pratique

Le piège classique avec Laravel

Laravel écrit énormément dans :


storage/
bootstrap/cache/

Exemples :

  • logs
  • cache
  • sessions
  • uploads
  • images générées dynamiquement

Si ces dossiers sont en bind mount :


./storage:/var/www/storage

alors PHP écrit avec son user Docker (souvent www-data), mais l’hôte possède souvent un autre UID.

Résultat :

  • fichiers root:root
  • fichiers www-data:33
  • fichiers user local:1000

Et là commencent les problèmes :


Permission denied
Failed to open stream
Unable to write file
Nginx 403 forbidden

Le gros problème : Nginx doit voir les fichiers statiques

Prenons ce cas réel :

  • Laravel génère une image :

storage/app/public/generated/image.png
  • Le symlink public existe :

public/storage -> ../storage/app/public
  • Nginx sert :

/var/www/public/storage/generated/image.png

Si Nginx et PHP n’utilisent pas exactement le même volume :

  • PHP voit le fichier
  • Nginx ne le voit pas

Résultat :


404 Not Found

L’architecture recommandée

Après plusieurs essais, voici l’architecture la plus stable.

Le code source → Bind Mount


./src:/var/www

Pourquoi ?

  • Git fonctionne normalement
  • déploiement simple
  • édition facile

Les dossiers dynamiques → Volumes managés


volumes:
    laravel_storage:
    laravel_cache:

services:
    app:
        volumes:
            - ./src:/var/www
            - laravel_storage:/var/www/storage
            - laravel_cache:/var/www/bootstrap/cache

Pourquoi ?

  • Laravel écrit librement
  • pas de conflit de permissions
  • plus sécurisé

Nginx monte aussi storage


services:
    nginx:
        volumes:
            - ./src/public:/var/www/public
            - laravel_storage:/var/www/storage:ro

Ainsi :

  • PHP écrit
  • Nginx lit
  • les fichiers générés sont visibles immédiatement

Pourquoi ne pas bind mount "storage" ?



Critère Bind Mount Managed Volume
Facilité debug
Permissions propres
Production stable
Compatibilité multi-user
Nginx lecture facile Moyen

Exemple docker-compose recommandé


services:
    app:
        build: .
        volumes:
            - ./src:/var/www
            - laravel_storage:/var/www/storage
            - laravel_cache:/var/www/bootstrap/cache

    nginx:
        image: nginx:alpine
        volumes:
            - ./src/public:/var/www/public:ro
            - laravel_storage:/var/www/storage:ro

volumes:
    laravel_storage:
    laravel_cache:

Règle simple à retenir

  • Code source : bind mount
  • Uploads utilisateurs : volume managé
  • Cache : volume managé
  • Logs : volume managé
  • Images générées : volume managé partagé avec Nginx
  • Configs : bind mount

Conclusion

Si tu développes en Laravel avec Docker :

Le meilleur compromis est hybride.

Utilise les bind mounts pour tout ce qui est source code et configuration, et des volumes managés pour tout ce que Laravel écrit lui-même.

Et surtout :

si Nginx doit servir un fichier généré par Laravel, ce dossier doit être monté dans les deux containers.

C’est ce point qui évite 80% des problèmes de fichiers statiques en production.

Thiébault Michaël ©