SSD Nodes Learn Hosting plans →
Guias Matt ConnorPor Matt Connor · Atualizado 2026-08-07

Docker Compose: .env, env_file e environment

Entenda a diferença entre .env, env_file e environment no Docker Compose, a precedência entre valores e por que senhas não devem ficar em variáveis do contentor.

As três coisas que as pessoas chamam de ficheiro env

O Docker Compose tem três mecanismos distintos com nomes muito semelhantes, o que pode causar confusão. O ficheiro .env preenche os marcadores ${VARIABLE} no próprio compose.yaml, antes de o Compose analisar o ficheiro. O atributo env_file: carrega um ficheiro com pares chave/valor para o ambiente do contentor. O atributo environment: define diretamente variáveis no contentor, escritas no ficheiro Compose. Estes mecanismos não são intercambiáveis. Quando dois deles definem a mesma chave, o resultado é determinado por uma ordem de precedência documentada.

Este guia mostra cada mecanismo em funcionamento e comprova a precedência com um comando que pode executar. Em seguida, aborda o ponto mais importante: qualquer pessoa que possa executar docker inspect consegue ler as variáveis de ambiente. Por isso, as palavras-passe não devem ser guardadas nelas. Se ainda não conhece os ficheiros Compose em geral, comece por conceitos básicos do Docker Compose numa VPS e volte aqui para tratar da configuração.

O ficheiro .env é usado pelo ficheiro Compose, não pelo contentor

Crie um diretório e coloque nele dois ficheiros.

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

Agora peça ao Compose para mostrar o que efetivamente analisou.

docker compose config

O resultado mostra image: alpine:3.20. O marcador de posição desapareceu porque a interpolação ocorreu durante a análise. O Compose procura .env no diretório do projeto, que é o diretório que contém o ficheiro Compose, e substitui todos os ${NAME} que encontrar.

Em seguida, inicie o serviço.

docker compose run --rm demo

printenv ALPINE_TAG termina com o estado 1 e não apresenta qualquer saída. A variável não existe dentro do contentor. Este é o erro de interpretação mais comum: .env configurou o ficheiro Compose, não o processo. Um ficheiro .env com POSTGRES_PASSWORD=hunter2 não produz qualquer efeito na base de dados, a menos que alguma parte do ficheiro Compose faça referência a ele.

${NAME:-default} fornece um valor alternativo quando a variável não está definida ou está vazia. ${NAME:?message} faz o Compose recusar o arranque e apresentar a sua mensagem. Esta é a opção correta para um valor que não tem um valor predefinido seguro.

env_file carrega variáveis para o container

O atributo env_file: especifica um ou mais ficheiros cujo conteúdo se torna variáveis de ambiente do container.

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

Isto imprime from_env_file. O formato do ficheiro usa linhas simples de KEY=value, uma por linha, e # no início indica um comentário. Não é shell. Na maioria dos casos, as aspas permanecem como parte do valor, e não é necessário usar prefixos export. Não coloque espaços em redor do sinal =, porque KEY = value cria uma variável literalmente chamada KEY , com um espaço inicial no valor.

Um caminho env_file em falta é um erro e o Compose é interrompido. Marque-o como opcional se o ficheiro puder legitimamente não existir:

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

define variáveis no ambiente na mesma linha

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

São aceites duas sintaxes: o formato de mapeamento acima e um formato de lista que usa - GREETING=from_environment. O comportamento é idêntico. O formato de lista tem um recurso adicional: uma chave isolada, sem valor, transmite a variável a partir da shell onde executou docker compose.

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

Isto imprime from_my_shell. Se o executar sem definir GREETING na shell, o Compose não define nada e não apresenta qualquer aviso. É importante conhecer estas falhas silenciosas de transmissão, porque um serviço que arranca com uma variável de palavra-passe vazia normalmente inicia sem problemas e fica simplesmente desprotegido.

Qual valor prevalece

O Docker documenta a ordem de precedência, da mais alta para a mais baixa: docker compose run -e na linha de comandos, depois environment ou env_file, cujo valor é interpolado a partir da shell ou de um ficheiro de ambiente, depois environment simples no ficheiro Compose, depois env_file e, por fim, a diretiva ENV incorporada na imagem.

A versão curta para o trabalho diário: environment: prevalece sobre env_file:, e -e na linha de comandos prevalece sobre ambos. Comprove isso num único ficheiro.

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

O primeiro comando imprime from_environment, porque environment: substituiu o valor em app.env. O segundo imprime from_cli. Nada no ficheiro Compose substitui a linha de comandos.

Quando um contentor se comporta como se a sua configuração nunca tivesse sido aplicada, não tente adivinhar. docker compose config imprime o ficheiro totalmente resolvido, e docker compose config --environment imprime as variáveis de interpolação que o Compose está a utilizar. A maioria dos relatos de que “o meu ficheiro de ambiente é ignorado” resulta de um valor definido duas vezes, em níveis diferentes.

Por que as variáveis de ambiente vazam

Defina uma palavra-passe em environment: e ela será armazenada no ficheiro de configuração do contentor, visível para qualquer utilizador do grupo docker.

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

A saída contém "DB_PASSWORD=hunter2" em texto simples. Mais três caminhos expõem o mesmo valor. docker compose config imprime-o no terminal, fazendo com que acabe colado num fórum de suporte. Qualquer processo dentro do contentor pode ler /proc/1/environ, e todos os processos filho herdam a variável. Além disso, os gestores de falhas das aplicações costumam despejar todo o ambiente num log ou num relatório de erro.

A pertença ao grupo docker equivale efetivamente a root no host. Por isso, não deve ser considerada uma fronteira de privilégios. O guia sobre contas de utilizador com privilégios mínimos num VPS explica por que razão deve restringir esse grupo em qualquer servidor partilhado.

Os secrets do Compose mantêm o valor num ficheiro

O Compose suporta secrets baseados em ficheiros. O valor é montado no contentor como um ficheiro, em vez de ser injetado no ambiente.

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

O secret é montado em /run/secrets/db_password dentro do contentor. O nome depois da barra é o nome do secret definido no bloco de nível superior secrets:.

O sufixo _FILE é uma convenção usada pelas Docker Official Images, incluindo postgres, mysql e mariadb. Esses scripts de entrypoint verificam a existência de VARNAME_FILE, leem o ficheiro e usam o seu conteúdo. Isto não é uma funcionalidade do Docker. Só funciona quando a imagem a implementa. Consulte a documentação da imagem antes de assumir que SOMETHING_FILE será respeitado. As aplicações que não suportam esta convenção podem muitas vezes ler o ficheiro durante o arranque. Em alternativa, pode passar o caminho e deixar que o seu próprio entrypoint faça essa leitura.

Verifique a partir do contentor em execução:

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

O primeiro comando imprime a palavra-passe. O segundo não imprime nada, porque o valor nunca entrou no ambiente. Esse é o objetivo: docker inspect neste contentor mostra apenas o caminho inofensivo.

Proteja o ficheiro de origem no host, porque o secret só é privado enquanto o ficheiro que o contém também o for:

chmod 600 db_password.txt

O meio-termo pragmático numa VPS

Muitas imagens self-hosted não suportam variáveis _FILE, por isso as variáveis de ambiente são a única forma de fornecer estes valores. Numa VPS administrada por uma única pessoa, o objetivo realista é impedir que os valores fiquem num ficheiro legível por todos no diretório do projeto e mantê-los fora do 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 cria o ficheiro com as permissões já definidas, por isso não existe um intervalo em que fique legível por todos. O root é o proprietário, portanto um utilizador que não seja root no servidor não o consegue ler, embora qualquer pessoa que consiga executar docker ainda possa obter o valor a partir do contentor. Adicione *.env e .env a .gitignore e faça commit de um app.env.example que contenha os nomes das chaves com valores vazios. Uma palavra-passe incluída num commit é uma palavra-passe que deve ser substituída.

A rotação de um valor implica reiniciar o serviço. As variáveis de ambiente são lidas uma vez, quando o processo do contentor arranca, por isso editar o ficheiro não altera nada até executar docker compose up -d --force-recreate db. Este é o mesmo padrão utilizado no guia n8n atrás de HTTPS numa VPS, em que a chave de encriptação fica fora do ficheiro compose.

Dividir a configuração por ambiente

O Compose lê .env do diretório do projeto por padrão. Aponte-o para outro local com --env-file.

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

Vários ficheiros são lidos pela ordem indicada, e os ficheiros posteriores substituem os anteriores. Mantenha os valores predefinidos não secretos num ficheiro versionado e os segredos num ficheiro que nunca saia do servidor. O mesmo se aplica a env_file:: para uma chave duplicada, prevalece o último ficheiro listado.

FAQ

Por que o meu arquivo .env é ignorado dentro do container?

Ele não é ignorado. O arquivo .env apenas substitui os marcadores ${NAME} no arquivo Compose. Ele nunca define variáveis dentro de um container. Para passar o valor para o container, faça referência a ele: environment: { KEY: "${NAME}" }, ou use env_file: ./that-file.env.

environment substitui env_file ou o contrário?

environment: tem precedência. A ordem documentada pelo Docker coloca o atributo environment acima do atributo env_file, e ambos ficam abaixo de docker compose run -e na linha de comando. Se uma chave for definida nos dois locais, o valor em env_file será silenciosamente ignorado.

Como vejo o valor final que o Compose usará?

Execute docker compose config para exibir o arquivo Compose totalmente resolvido, com toda a interpolação aplicada. Para um container que já está em execução, docker inspect <container> --format '{{json .Config.Env}}' mostra exatamente o que o processo recebeu.

Os secrets do Compose são criptografados?

Não. Um secret baseado em arquivo é montado no container como um arquivo sem criptografia em /run/secrets/<name>, e o arquivo de origem fica armazenado no disco do host sem criptografia. O benefício é o escopo, não a criptografia: o valor não aparece no ambiente do container, na saída de docker inspect nem em dumps de falha que imprimem o ambiente.

Posso usar aspas e espaços em um arquivo de ambiente?

Use KEY=value with spaces e não coloque as aspas. O Compose trata todo o restante da linha como o valor, portanto as aspas normalmente acabam como caracteres literais no valor. Nunca coloque espaços ao redor de =, pois a chave passa a conter um espaço no final e nada corresponde a ela.