SSD Nodes Learn 8GB de RAM — $66/ano
Guias Matt ConnorPor Matt Connor · Atualizado 2026-08-02

Docker Compose: .env, env_file, environment e secrets

Entenda a diferença entre .env, env_file e environment no Docker Compose, veja a precedência entre valores e saiba por que senhas devem usar secrets.

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

O Docker Compose tem três mecanismos separados, com nomes muito semelhantes e que causam confusão. O arquivo .env substitui os marcadores ${VARIABLE} dentro do próprio compose.yaml, antes mesmo de o Compose analisar o arquivo. O atributo env_file: carrega um arquivo de pares chave/valor no ambiente do contêiner. O atributo environment: define variáveis diretamente no contêiner, gravadas no arquivo Compose. Eles não são intercambiáveis. Quando dois deles definem a mesma chave, o vencedor é determinado por uma ordem de precedência documentada.

Este guia mostra cada mecanismo em funcionamento e comprova a precedência com um comando que você pode executar. Depois, aborda o ponto mais importante: as variáveis de ambiente podem ser lidas por qualquer pessoa que possa executar docker inspect. Portanto, senhas não devem ser armazenadas nelas. Se você ainda não conhece os arquivos Compose em geral, comece por conceitos básicos do Docker Compose em um VPS e volte aqui para tratar da configuração.

O arquivo .env é usado pelo arquivo compose, não pelo contêiner

Crie um diretório e coloque dois arquivos nele.

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 ele realmente analisou.

docker compose config

A saída mostra image: alpine:3.20. O marcador foi substituído porque a interpolação ocorreu no momento da análise. O Compose procura .env no diretório do projeto, que é o diretório que contém o arquivo compose, e substitui cada ocorrência de ${NAME}.

Em seguida, inicie o serviço.

docker compose run --rm demo

printenv ALPINE_TAG encerra com o status 1 e não imprime nada. A variável não existe dentro do contêiner. Esse é o erro de interpretação mais comum: .env configurou o arquivo compose, não o processo. Um arquivo .env que contenha POSTGRES_PASSWORD=hunter2 não produz efeito algum no banco de dados, a menos que alguma parte do arquivo 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 a inicialização e imprimir a mensagem especificada. Essa é a escolha correta para um valor que não tem um padrão seguro.

env_file carrega variáveis no container

O atributo env_file: indica um ou mais arquivos 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

Isso imprime from_env_file. O formato do arquivo consiste em linhas simples de KEY=value, uma por linha, com # iniciando um comentário. Ele não usa a sintaxe do shell. Na maioria dos casos, as aspas são mantidas como parte do valor, e os prefixos export não são necessários. Não coloque espaços ao redor do sinal =, pois KEY = value cria uma variável literalmente chamada KEY , com um espaço inicial em seu valor.

Um caminho env_file ausente gera um erro, e o Compose é interrompido. Marque-o como opcional se o arquivo puder legitimamente não existir:

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

o ambiente define variáveis em linha

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

Duas sintaxes são aceitas: o formato de mapeamento acima e o formato de lista usando - GREETING=from_environment. Elas se comportam de forma idêntica. O formato de lista tem um recurso adicional: uma chave sem valor repassa a variável do shell em que você executou docker compose.

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

Isso imprime from_my_shell. Execute sem definir GREETING no shell, e o Compose não define nada nem exibe um aviso. Vale conhecer as falhas silenciosas de repasse, porque um serviço que é iniciado com uma variável de senha vazia geralmente inicia com sucesso e fica totalmente aberto.

Qual deles prevalece

O Docker documenta a ordem de precedência, da maior para a menor: docker compose run -e na linha de comando, depois environment ou env_file, cujo valor é interpolado do seu shell ou de um arquivo de ambiente, depois environment simples no arquivo Compose, depois env_file e, por fim, a diretiva ENV incorporada à imagem.

A versão curta para o trabalho diário: environment: prevalece sobre env_file:, e -e na linha de comando prevalece sobre ambos. Comprove isso em um único arquivo.

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, portanto environment: substituiu o valor em app.env. O segundo imprime from_cli. Nada no arquivo Compose substitui o valor definido na linha de comando.

Quando um container se comporta como se sua configuração nunca tivesse sido aplicada, não tente adivinhar. docker compose config imprime o arquivo totalmente resolvido, e docker compose config --environment imprime as variáveis de interpolação usadas pelo Compose. A maioria dos relatos de que "meu arquivo de ambiente é ignorado" ocorre porque um valor foi definido duas vezes, em níveis diferentes.

Por que as variáveis de ambiente vazam

Defina uma senha em environment: e ela será armazenada na configuração do contêiner em disco, visível para qualquer usuário 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 o exibe no terminal, e é assim que ele acaba sendo colado em um fórum de suporte. Qualquer processo dentro do contêiner pode ler /proc/1/environ, e todo processo filho herda a variável. Além disso, os manipuladores de falhas de aplicativos normalmente despejam todo o ambiente em um log ou relatório de erro.

A associação ao grupo docker equivale efetivamente a root no host, portanto isso não é um limite de privilégios no qual você possa confiar. O guia sobre contas de usuário com privilégio mínimo em um VPS explica por que vale a pena restringir esse grupo em qualquer servidor compartilhado.

Os secrets do Compose mantêm o valor em um arquivo

O Compose oferece suporte a secrets baseados em arquivo. O valor é montado no container como um arquivo, 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 container. O nome após a 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 arquivo e usam o conteúdo. Isso não é um recurso do Docker. Portanto, só funciona quando a imagem implementa essa convenção. Consulte a documentação da imagem antes de presumir que SOMETHING_FILE será respeitado. Aplicações que não oferecem suporte a isso geralmente podem ler o arquivo durante a inicialização, ou você pode passar o caminho e deixar que seu próprio entrypoint faça isso.

Verifique de dentro do container em execução:

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

O primeiro comando exibe a senha. O segundo não exibe nada, porque o valor nunca entrou no ambiente. Esse é o objetivo: docker inspect neste container mostra apenas o caminho sem informações sensíveis.

Proteja o arquivo de origem no host, porque o secret só é privado enquanto o arquivo correspondente permanecer protegido:

chmod 600 db_password.txt

O meio-termo pragmático em um VPS

Muitas imagens auto-hospedadas não oferecem suporte a variáveis _FILE, portanto as variáveis de ambiente são a única forma de fornecê-las. Em um VPS com um único administrador, o objetivo realista é impedir que os valores fiquem armazenados em um arquivo 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 arquivo com as permissões já definidas, portanto não existe um intervalo em que ele fique legível por todos. O root é o proprietário, então um usuário que não seja root no servidor não pode lê-lo, embora qualquer pessoa que possa executar docker ainda consiga ler o valor de dentro do container. Adicione *.env e .env ao .gitignore e faça commit de um app.env.example contendo os nomes das chaves com valores vazios. Uma senha armazenada em um commit deve ser substituída.

A rotação de um valor significa reiniciar o serviço. As variáveis de ambiente são lidas uma vez, quando o processo do container é iniciado, portanto editar o arquivo não altera nada até você executar docker compose up -d --force-recreate db. Esse é o mesmo padrão usado no guia n8n atrás de HTTPS em um VPS, no qual a chave de criptografia fica fora do arquivo compose.

Dividindo 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 arquivos são lidos na ordem, e os arquivos posteriores substituem os anteriores. Mantenha os padrões não secretos em um arquivo versionado e os segredos em um arquivo que nunca saia do servidor. O mesmo se aplica a env_file:: o último arquivo listado prevalece quando uma chave é duplicada.

FAQ

Por que 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 colocar o valor no container, faça referência a ele: environment: { KEY: "${NAME}" }, ou use env_file: ./that-file.env.

environment substitui env_file, ou ocorre 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 permanece sem criptografia no disco do host. 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 exibem o ambiente.

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

Use KEY=value with spaces e não inclua 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 à direita e nada corresponde a ela.