SSD Nodes Learn 8GB RAM — $66/jaar
Gidsen Matt ConnorDoor Matt Connor · Bijgewerkt 2026-08-02

Docker Compose: .env, env_file en environment

Leer het verschil tussen .env, env_file en environment in Docker Compose, ontdek welke waarde wint en waarom wachtwoorden in secrets horen, niet in variabelen.

De drie dingen die mensen een env-bestand noemen

Docker Compose heeft drie afzonderlijke mechanismen met namen die sterk op elkaar lijken. Het bestand .env vult ${VARIABLE}-placeholders in compose.yaml zelf in, voordat Compose het bestand parseert. Het attribuut env_file: laadt een bestand met key/value-paren in de omgeving van de container. Het attribuut environment: stelt variabelen rechtstreeks in op de container, vanuit het compose-bestand. Deze mechanismen zijn niet uitwisselbaar. Als twee ervan dezelfde key instellen, wordt de winnaar bepaald door een gedocumenteerde prioriteitsvolgorde.

In deze handleiding ziet u elk mechanisme in werking. U controleert de prioriteit met een opdracht die u zelf kunt uitvoeren. Daarna behandelen we het belangrijkere punt: omgevingsvariabelen zijn leesbaar voor iedereen die docker inspect kan uitvoeren. Wachtwoorden horen daarom niet in omgevingsvariabelen te staan. Als u nog niet bekend bent met compose-bestanden, begint u met de basisbeginselen van Docker Compose op een VPS en gaat u daarna hier verder voor configuratie.

Het .env-bestand is bedoeld voor het compose-bestand, niet voor de container

Maak een map en plaats er twee bestanden in.

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

Vraag Compose nu wat het daadwerkelijk heeft geparseerd.

docker compose config

De uitvoer toont image: alpine:3.20. De placeholder is verdwenen, omdat interpolatie tijdens het parsen plaatsvond. Compose zoekt naar .env in de projectmap, dus de map waarin het compose-bestand staat, en vervangt elke gevonden ${NAME}.

Start de service vervolgens.

docker compose run --rm demo

printenv ALPINE_TAG wordt afgesloten met status 1 en geeft niets weer. De variabele bestaat niet in de container. Dit is het meest voorkomende misverstand: .env configureerde het compose-bestand, niet het proces. Een .env-bestand met POSTGRES_PASSWORD=hunter2 erin doet helemaal niets voor uw database, tenzij een deel van het compose-bestand ernaar verwijst.

${NAME:-default} levert een fallbackwaarde wanneer de variabele niet is ingesteld of leeg is. ${NAME:?message} zorgt ervoor dat Compose niet start en uw bericht weergeeft. Dat is de juiste keuze voor een waarde waarvoor geen veilige standaardwaarde bestaat.

env_file laadt variabelen in de container

Het attribuut env_file: verwijst naar een of meer bestanden waarvan de inhoud containeromgevingsvariabelen wordt.

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

Hiermee wordt from_env_file afgedrukt. De bestandsindeling bestaat uit eenvoudige KEY=value-regels, één per regel, waarbij # het begin van een opmerking aangeeft. Het bestand gebruikt geen shell-syntaxis. Aanhalingstekens blijven in de meeste gevallen onderdeel van de waarde en voorvoegsels van export zijn niet nodig. Plaats geen spaties rond het teken =, omdat KEY = value dan een variabele met de naam KEY oplevert, met een voorloopspatie in de waarde.

Een ontbrekend pad env_file is een fout en Compose stopt. Markeer het bestand als optioneel als het legitiem kan ontbreken:

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

environment stelt variabelen inline in

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

Er worden twee syntaxisvormen geaccepteerd: de bovenstaande toewijzingsvorm en een lijstvorm met - GREETING=from_environment. Ze werken identiek. De lijstvorm heeft één extra mogelijkheid: met een sleutel zonder waarde wordt de variabele doorgegeven vanuit de shell waarin u docker compose hebt uitgevoerd.

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

Dit geeft from_my_shell weer. Als u het uitvoert zonder GREETING in de shell in te stellen, stelt Compose niets in en wordt er geen waarschuwing weergegeven. Het is belangrijk om te weten dat het stil doorgeven van variabelen kan mislukken. Een service die met een lege wachtwoordvariabele start, wordt vaak zonder problemen gestart en staat vervolgens volledig open.

Welke heeft voorrang

Docker documenteert de volgorde van voorrang, van hoog naar laag: docker compose run -e op de opdrachtregel, vervolgens environment of env_file waarvan de waarde wordt geïnterpoleerd vanuit uw shell of vanuit een env-bestand, daarna gewone environment in het compose-bestand, vervolgens env_file en ten slotte de ENV-directive die in de image is opgenomen.

De korte versie voor dagelijks gebruik: environment: heeft voorrang op env_file:, en -e op de opdrachtregel heeft voorrang op beide. Toon dit aan in één bestand.

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

De eerste opdracht geeft from_environment weer. environment: heeft dus de waarde in app.env overschreven. De tweede opdracht geeft from_cli weer. Niets in het compose-bestand overschrijft de opdrachtregel.

Wanneer een container zich gedraagt alsof uw configuratie nooit is toegepast, moet u niet raden. Met docker compose config geeft u het volledig opgeloste bestand weer. Met docker compose config --environment geeft u de interpolatievariabelen weer die Compose gebruikt. De meeste meldingen dat "mijn env-bestand wordt genegeerd" blijken te worden veroorzaakt doordat een waarde op twee verschillende niveaus is ingesteld.

Waarom omgevingsvariabelen uitlekken

Stel een wachtwoord in environment: in. Het wordt dan opgeslagen in de configuratie van de container op schijf. Elke gebruiker in de groep docker kan het wachtwoord zien.

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

De uitvoer bevat "DB_PASSWORD=hunter2" als platte tekst. Drie andere paden geven dezelfde waarde vrij. docker compose config schrijft de waarde naar de terminal. Daardoor kan deze in een supportforum worden geplakt. Elk proces in de container kan /proc/1/environ lezen. Elk onderliggend proces neemt de variabele over. Crashafhandeling van applicaties schrijft bovendien vaak de volledige omgeving naar een logbestand of foutrapport.

Lidmaatschap van de groep docker geeft op de host in de praktijk root-rechten. U kunt deze groep dus niet als beveiligingsgrens gebruiken. De handleiding gebruikersaccounts met minimale rechten op een VPS legt uit waarom u deze groep op elke gedeelde server moet beperken.

Compose-secrets houden de waarde in een bestand

Compose ondersteunt secrets op basis van bestanden. De waarde wordt als bestand in de container gemount in plaats van in de omgeving te worden geïnjecteerd.

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

Het secret wordt in de container gemount op /run/secrets/db_password. De naam na de slash is de naam van het secret uit het blok secrets: op het hoogste niveau.

Het achtervoegsel _FILE is een conventie die door de Docker Official Images wordt gebruikt, waaronder postgres, mysql en mariadb. Deze entrypoint-scripts controleren op VARNAME_FILE, lezen het bestand en gebruiken de inhoud ervan. Dit is geen functie van Docker. Het werkt dus alleen als de image dit implementeert. Controleer de documentatie van de image voordat u ervan uitgaat dat SOMETHING_FILE wordt verwerkt. Applicaties die dit niet ondersteunen, kunnen het bestand vaak zelf bij het starten lezen. U kunt ook het pad doorgeven en dit door uw eigen entrypoint laten verwerken.

Controleer dit vanuit de actieve container:

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

De eerste opdracht geeft het wachtwoord weer. De tweede geeft niets weer, omdat de waarde nooit in de omgeving is terechtgekomen. Dat is precies het doel: docker inspect in deze container toont alleen het onschadelijke pad.

Beveilig het bronbestand op de host, omdat het secret slechts zo privé is als het bestand waarnaar het verwijst:

chmod 600 db_password.txt

De praktische middenweg op een VPS

Veel zelf gehoste images ondersteunen geen _FILE-variabelen. Omgevingsvariabelen zijn dan de enige manier om deze waarden door te geven. Op een VPS met één beheerder is het realistische doel om te voorkomen dat de waarden in een bestand staan dat iedereen kan lezen in uw projectmap, en om ze buiten git te houden.

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 maakt het bestand aan met de juiste modus. Daardoor is er geen moment waarop iedereen het kan lezen. Root is de eigenaar. Een gebruiker zonder rootrechten op de server kan het bestand daarom niet lezen. Iedereen die docker kan uitvoeren, kan de waarde echter nog steeds uit de container lezen. Voeg *.env en .env toe aan .gitignore en commit in plaats daarvan een app.env.example met de sleutelnamen en lege waarden. Een gecommit wachtwoord moet worden vervangen.

Een waarde vervangen betekent dat u de service opnieuw moet starten. Omgevingsvariabelen worden één keer gelezen wanneer het containerproces start. Als u het bestand bewerkt, verandert er dus niets totdat u docker compose up -d --force-recreate db uitvoert. Dit is hetzelfde patroon als in de handleiding n8n achter HTTPS op een VPS, waarin de encryptiesleutel buiten het compose-bestand staat.

Configuratie per omgeving opsplitsen

Compose leest standaard .env uit de projectdirectory. Wijs met --env-file naar een andere locatie.

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

Meerdere bestanden worden in de opgegeven volgorde gelezen. Latere bestanden overschrijven eerdere bestanden. Bewaar de niet-geheime standaardwaarden in een bestand dat u commit. Bewaar de geheimen in een bestand dat de server nooit verlaat. Hetzelfde geldt voor env_file:. Daar wint het laatst vermelde bestand bij een dubbele sleutel.

FAQ

Waarom wordt mijn .env-bestand in de container genegeerd?

Het wordt niet genegeerd. Het bestand .env vervangt alleen ${NAME}-placeholders in het compose-bestand. Het stelt nooit variabelen in een container in. Als u de waarde in de container wilt gebruiken, verwijst u ernaar met environment: { KEY: "${NAME}" } of gebruikt u in plaats daarvan env_file: ./that-file.env.

Heeft environment voorrang op env_file, of andersom?

environment: heeft voorrang. Volgens de gedocumenteerde volgorde van Docker staat het attribuut environment boven het attribuut env_file. Beide staan onder docker compose run -e op de opdrachtregel. Als een sleutel op beide plaatsen is ingesteld, wordt de waarde in env_file stilzwijgend niet gebruikt.

Hoe zie ik de uiteindelijke waarde die Compose gebruikt?

Voer docker compose config uit om het volledig opgeloste compose-bestand met alle toegepaste interpolaties weer te geven. Voor een container die al actief is, toont docker inspect <container> --format '{{json .Config.Env}}' precies wat het proces heeft ontvangen.

Zijn Compose-secrets versleuteld?

Nee. Een op een bestand gebaseerde secret wordt als een normaal bestand in de container gekoppeld op /run/secrets/<name>. Het bronbestand staat onversleuteld op de schijf van de host. Het voordeel is de beperkte beschikbaarheid, niet de versleuteling: de waarde blijft buiten de containeromgeving, buiten de uitvoer van docker inspect en buiten crashdumps die de omgeving afdrukken.

Kan ik aanhalingstekens en spaties in een env-bestand gebruiken?

Gebruik KEY=value with spaces en laat de aanhalingstekens weg. Compose behandelt de volledige rest van de regel als de waarde. Daardoor worden aanhalingstekens meestal als letterlijke tekens in de waarde opgenomen. Plaats nooit spaties rond =, omdat de sleutel dan een afsluitende spatie bevat en niets ermee overeenkomt.