SSD Nodes Learn Hosting plans →
Guides Matt ConnorPar Matt Connor · Mis à jour le 2026-08-07

Docker Compose : .env, env_file ou environment ?

Comprenez la différence entre .env, env_file et environment dans Docker Compose, leur ordre de priorité et pourquoi les secrets ne doivent pas rester dans les variables d’environnement.

Les trois mécanismes que l’on appelle « fichier env »

Docker Compose propose trois mécanismes distincts dont les noms se ressemblent beaucoup. Le fichier .env remplace les variables ${VARIABLE} dans compose.yaml lui-même, avant même que Compose n’analyse le fichier. L’attribut env_file: charge un fichier contenant des paires clé-valeur dans l’environnement du conteneur. L’attribut environment: définit directement des variables dans le conteneur, dans le fichier Compose. Ces mécanismes ne sont pas interchangeables. Lorsque deux d’entre eux définissent la même clé, la valeur retenue dépend d’un ordre de priorité documenté.

Ce guide présente chacun de ces mécanismes en fonctionnement. Il vérifie la priorité avec une commande que vous pouvez exécuter. Il aborde ensuite le point le plus important : les variables d’environnement sont lisibles par toute personne pouvant exécuter docker inspect. Les mots de passe ne doivent donc pas y être stockés. Si vous débutez avec les fichiers Compose, commencez par les bases de Docker Compose sur un VPS, puis revenez ici pour la configuration.

Le fichier .env sert au fichier Compose, pas au conteneur

Créez un répertoire et placez-y deux fichiers.

mkdir -p ~/envdemo && cd ~/envdemo
printf 'ALPINE_TAG=3.20\n' > .env
services:
  demo:
    image: alpine:${ALPINE_TAG}
    command: printenv ALPINE_TAG

Demandez maintenant à Compose ce qu’il a réellement analysé.

docker compose config

La sortie affiche image: alpine:3.20. Le paramètre fictif a disparu, car l’interpolation a eu lieu au moment de l’analyse. Compose recherche .env dans le répertoire du projet, c’est-à-dire le répertoire qui contient le fichier Compose, puis remplace chaque occurrence de ${NAME}.

Lancez ensuite le service.

docker compose run --rm demo

printenv ALPINE_TAG se termine avec le code d’état 1 et n’affiche rien. La variable n’existe pas dans le conteneur. C’est le malentendu le plus fréquent : .env a configuré le fichier Compose, pas le processus. Un fichier .env contenant POSTGRES_PASSWORD=hunter2 ne fait absolument rien pour votre base de données, sauf si une partie du fichier Compose le référence.

${NAME:-default} fournit une valeur de repli lorsque la variable n’est pas définie ou est vide. ${NAME:?message} demande à Compose de refuser le démarrage et d’afficher votre message, ce qui convient lorsqu’une valeur n’a pas de valeur par défaut sûre.

env_file charge des variables dans le conteneur

L’attribut env_file: indique un ou plusieurs fichiers dont le contenu devient celui des variables d’environnement du conteneur.

printf 'GREETING=from_env_file\nAPP_MODE=production\n' > app.env
services:
  demo:
    image: alpine:3.20
    command: printenv GREETING
    env_file:
      - ./app.env
docker compose run --rm demo

Cette commande affiche from_env_file. Le format du fichier consiste en lignes KEY=value simples, une par ligne, avec # au début pour introduire un commentaire. Ce n’est pas du shell. Dans la plupart des cas, les guillemets sont conservés dans la valeur, et les préfixes export ne sont pas nécessaires. N’ajoutez pas d’espaces autour du signe =, car KEY = value crée une variable nommée littéralement KEY , avec une espace au début de sa valeur.

Un chemin env_file manquant provoque une erreur et Compose s’arrête. Indiquez-le comme facultatif si le fichier peut légitimement être absent :

    env_file:
      - path: ./app.env
        required: false

environment définit des variables inline

services:
  demo:
    image: alpine:3.20
    command: printenv GREETING
    environment:
      GREETING: from_environment

Deux syntaxes sont acceptées : la forme de mappage ci-dessus et une forme de liste utilisant - GREETING=from_environment. Elles se comportent de la même manière. La forme de liste offre une possibilité supplémentaire : une clé seule, sans valeur, transmet la variable depuis le shell dans lequel vous avez exécuté docker compose.

    environment:
      - GREETING
GREETING=from_my_shell docker compose run --rm demo

Cette commande affiche from_my_shell. Si vous l’exécutez sans définir GREETING dans le shell, Compose ne définit rien et n’affiche aucun avertissement. Ces échecs de transmission silencieux sont importants à connaître : un service qui démarre avec une variable de mot de passe vide démarre souvent correctement, mais reste simplement totalement ouvert.

Quel paramètre prend le dessus

Docker documente l’ordre de priorité, du plus élevé au plus faible : docker compose run -e sur la ligne de commande, puis environment ou env_file, dont la valeur est interpolée depuis votre shell ou depuis un fichier d’environnement, puis environment simple dans le fichier Compose, puis env_file, puis la directive ENV intégrée à l’image.

En pratique : environment: prend le dessus sur env_file:, et -e sur la ligne de commande prend le dessus sur les deux. Vérifiez-le dans un seul fichier.

services:
  demo:
    image: alpine:3.20
    command: printenv GREETING
    env_file:
      - ./app.env
    environment:
      GREETING: from_environment
docker compose run --rm demo
docker compose run --rm -e GREETING=from_cli demo printenv GREETING

La première commande affiche from_environment : environment: a donc remplacé la valeur de app.env. La seconde affiche from_cli. Rien dans le fichier Compose ne remplace la valeur définie sur la ligne de commande.

Lorsqu’un conteneur se comporte comme si votre configuration n’avait pas été appliquée, ne faites pas de suppositions. docker compose config affiche le fichier entièrement résolu, et docker compose config --environment affiche les variables d’interpolation utilisées par Compose. Dans la plupart des signalements indiquant que « mon fichier d’environnement est ignoré », une même valeur a été définie à deux niveaux différents.

Pourquoi les variables d’environnement fuient

Définissez un mot de passe dans environment: : il est alors stocké sur disque dans la configuration du conteneur et visible par tout utilisateur appartenant au groupe docker.

docker compose run -d --name leaky -e DB_PASSWORD=hunter2 demo sleep 300
docker inspect leaky --format '{{json .Config.Env}}'

La sortie contient "DB_PASSWORD=hunter2" en clair. Trois autres chemins exposent la même valeur. docker compose config l’affiche dans le terminal, ce qui explique comment elle finit copiée-collée dans un forum d’assistance. Tout processus exécuté dans le conteneur peut lire /proc/1/environ, et chaque processus fils hérite de cette variable. Les gestionnaires de crash des applications enregistrent aussi régulièrement l’ensemble de l’environnement dans un journal ou un rapport d’erreur.

L’appartenance au groupe docker équivaut en pratique à disposer des privilèges root sur l’hôte. Il ne s’agit donc pas d’une limite de privilèges sur laquelle vous pouvez compter. Le guide consacré aux comptes utilisateur avec le principe du moindre privilège sur un VPS explique pourquoi il est préférable de restreindre ce groupe sur tout serveur partagé.

Les secrets Compose conservent la valeur dans un fichier

Compose prend en charge les secrets stockés dans des fichiers. La valeur est montée dans le conteneur sous forme de fichier, au lieu d’être injectée dans l’environnement.

services:
  db:
    image: postgres:16
    environment:
      POSTGRES_PASSWORD_FILE: /run/secrets/db_password
    secrets:
      - db_password
secrets:
  db_password:
    file: ./db_password.txt

Le secret est monté à l’emplacement /run/secrets/db_password dans le conteneur. Le nom qui suit la barre oblique est le nom du secret défini dans le bloc secrets: de niveau supérieur.

Le suffixe _FILE est une convention utilisée par les Docker Official Images, notamment postgres, mysql et mariadb. Leurs scripts d’entrypoint recherchent VARNAME_FILE, lisent le fichier et utilisent son contenu. Il ne s’agit pas d’une fonctionnalité Docker. Cette convention ne fonctionne donc que si l’image l’implémente. Consultez la documentation de l’image avant de supposer que SOMETHING_FILE sera pris en charge. Les applications qui ne prennent pas cette convention en charge peuvent souvent lire elles-mêmes le fichier au démarrage. Vous pouvez aussi transmettre le chemin et laisser votre propre entrypoint s’en charger.

Vérifiez le résultat depuis le conteneur en cours d’exécution :

docker compose exec db cat /run/secrets/db_password
docker compose exec db printenv POSTGRES_PASSWORD

La première commande affiche le mot de passe. La seconde n’affiche rien, car la valeur n’a jamais été ajoutée à l’environnement. C’est précisément l’objectif : docker inspect dans ce conteneur affiche uniquement le chemin sans caractère sensible.

Protégez le fichier source sur l’hôte, car le secret n’est pas plus privé que le fichier qui le contient :

chmod 600 db_password.txt

Le compromis pragmatique sur un VPS

De nombreuses images self-hosted ne prennent pas en charge les variables _FILE. Les variables d’environnement sont donc le seul moyen de les transmettre. Sur un VPS administré par une seule personne, l’objectif réaliste consiste à éviter que ces valeurs restent dans un fichier lisible par tous dans le répertoire de votre projet, et à les exclure de git.

sudo install -o root -g root -m 600 /dev/null /etc/myapp/app.env
sudo nano /etc/myapp/app.env
    env_file:
      - /etc/myapp/app.env

install -m 600 crée le fichier avec les permissions déjà définies. Il n’existe donc aucune période pendant laquelle il est lisible par tous. root en est propriétaire. Un utilisateur qui n’a pas les privilèges root sur la machine ne peut donc pas le lire. En revanche, toute personne pouvant exécuter docker peut toujours lire la valeur depuis le conteneur. Ajoutez *.env et .env à .gitignore, puis validez un fichier app.env.example contenant les noms des clés avec des valeurs vides. Un mot de passe validé dans git doit être changé.

La rotation d’une valeur nécessite de redémarrer le service. Les variables d’environnement sont lues une seule fois, au démarrage du processus du conteneur. Modifier le fichier ne change donc rien tant que vous n’exécutez pas docker compose up -d --force-recreate db. C’est le même principe que dans le guide n8n derrière HTTPS sur un VPS, où la clé de chiffrement se trouve en dehors du fichier Compose.

Fractionner la configuration par environnement

Compose lit .env dans le répertoire du projet par défaut. Indiquez un autre emplacement avec --env-file.

docker compose --env-file .env.staging config

Les fichiers sont lus dans l’ordre et les fichiers suivants remplacent les valeurs définies précédemment. Conservez les valeurs par défaut non secrètes dans un fichier versionné, et les secrets dans un fichier qui ne quitte jamais le serveur. La même règle s’applique à env_file: : en cas de clé dupliquée, la valeur du dernier fichier indiqué est retenue.

FAQ

Pourquoi mon fichier .env est-il ignoré dans le conteneur ?

Il n’est pas ignoré. Le fichier .env ne remplace que les espaces réservés ${NAME} dans le fichier Compose. Il ne définit jamais de variables dans un conteneur. Pour transmettre la valeur au conteneur, référencez-la avec environment: { KEY: "${NAME}" } ou utilisez plutôt env_file: ./that-file.env.

Est-ce que environment remplace env_file, ou est-ce l’inverse ?

environment: est prioritaire. L’ordre documenté par Docker place l’attribut environment au-dessus de l’attribut env_file, et les deux sont prioritaires par rapport à docker compose run -e sur la ligne de commande. Si une clé est définie aux deux endroits, la valeur de env_file est ignorée silencieusement.

Comment voir la valeur finale utilisée par Compose ?

Exécutez docker compose config pour afficher le fichier Compose entièrement résolu, après application de toutes les interpolations. Pour un conteneur déjà en cours d’exécution, docker inspect <container> --format '{{json .Config.Env}}' affiche exactement ce que son processus a reçu.

Les secrets Compose sont-ils chiffrés ?

Non. Un secret basé sur un fichier est monté dans le conteneur comme un fichier en clair à l’emplacement /run/secrets/<name>, et le fichier source reste stocké sans chiffrement sur le disque de l’hôte. L’intérêt concerne la portée, pas le chiffrement : la valeur reste absente de l’environnement du conteneur, de la sortie de docker inspect et des crash dumps qui affichent l’environnement.

Puis-je utiliser des guillemets et des espaces dans un fichier env ?

Utilisez KEY=value with spaces et omettez les guillemets. Compose traite tout le reste de la ligne comme la valeur ; les guillemets deviennent donc généralement des caractères littéraux dans cette valeur. Ne mettez jamais d’espaces autour de =, car la clé contient alors un espace final et aucune correspondance ne peut être établie.