docker-mailserver no Git: o que versionar e o que nunca sai do servidor
Separe no docker-mailserver o que é configuração pública do que é segredo, tire senha, hash e chave DKIM do repositório e saiba o que trocar se já vazou.
O repositório da infraestrutura tem um commit chamado "subindo o mailserver igual pra todo mundo". Dentro dele, o mailserver.env com a senha do relay, a pasta docker-data/dms/config com o arquivo de contas e a chave DKIM privada do domínio. O repositório é privado, mas já foi clonado em quatro notebooks e numa ferramenta de CI.
A resposta curta: versione a forma, não o conteúdo secreto. O compose.yaml e as opções que ligam e desligam recursos podem ir para o Git. Senhas de relay e de LDAP, o arquivo de contas, as chaves DKIM e os certificados TLS ficam só no servidor, com permissão restrita. Se algum deles já foi commitado, troque o segredo primeiro e limpe o histórico depois.
Por que o compose de exemplo vira vazamento
A documentação do docker-mailserver lista dezenas de variáveis de ambiente, e quase todas são inofensivas: ligar antispam, escolher o tipo de certificado, definir o endereço do postmaster. Por isso dá vontade de tratar o arquivo inteiro como configuração pública. Só que algumas variáveis carregam credencial, como as de usuário e senha do relay e a senha de bind do LDAP. Confira os nomes exatos na página de ambiente da versão que você roda, porque eles mudam entre versões.
O maior risco, porém, não é o .env. É a pasta de configuração montada no container. Ali o comando setup grava o arquivo de contas, com o hash das senhas das caixas, e as chaves DKIM privadas. Quem tem a chave DKIM assina mensagem como se fosse o seu domínio, e ela passa na verificação. Quem tem o hash pode tentar quebrar as senhas fora do seu servidor, no tempo dele.
Repositório privado não é cofre. Ele é copiado para cada máquina que clona, para backups, forks e ferramentas de integração. A regra geral está em segredo não entra na imagem do container; aqui ela é aplicada ao servidor de e-mail.
O que versionar e o que não versionar
O exemplo: o servidor mail.lojaexemplo.com.br, em docker-mailserver, com envio de saída por relay.
- Vai para o Git:
compose.yaml,mailserver.envsó com opções sem segredo, ummailserver.secrets.env.examplecom os nomes das variáveis e valores vazios, e a documentação de como gerar contas e chaves. - Fica só no servidor:
mailserver.secrets.env, toda a pastadocker-data/(contas, chaves DKIM, caixas, estado, logs) e os certificados TLS.
Como organizar o repositório, passo a passo
- Divida o ambiente em dois arquivos: um público e um secreto.
- Carregue os dois no compose com
env_fileem lista. - Ignore no Git o arquivo secreto e a pasta de dados antes do primeiro commit.
- Crie o arquivo secreto no servidor, com permissão 600 e dono restrito.
- Crie as contas e as chaves no servidor, com o
setupdo próprio container, e faça backup dessa pasta por um canal separado. - Use uma conta própria para o aplicativo, como
noreply@, nunca a conta do administrador ou do postmaster.
O compose com dois arquivos de ambiente
# compose.yaml
services:
mailserver:
image: ghcr.io/docker-mailserver/docker-mailserver:14.0.0
container_name: mailserver
hostname: mail.lojaexemplo.com.br
env_file:
- mailserver.env
- mailserver.secrets.env
ports:
- "25:25"
- "465:465"
- "587:587"
- "993:993"
volumes:
- ./docker-data/dms/mail-data/:/var/mail/
- ./docker-data/dms/mail-state/:/var/mail-state/
- ./docker-data/dms/mail-logs/:/var/log/mail/
- ./docker-data/dms/config/:/tmp/docker-mailserver/
- /etc/letsencrypt:/etc/letsencrypt:ro
- /etc/localtime:/etc/localtime:ro
restart: always
Fixe a versão da imagem que você testou, em vez de latest; o motivo está em a tag latest mente. Os certificados vêm do host, somente leitura, e nunca passam pelo repositório.
O .gitignore e o arquivo de exemplo
# .gitignore
docker-data/
mailserver.secrets.env
# mailserver.secrets.env.example (este vai para o Git, sem valores)
# Copie para mailserver.secrets.env no servidor e preencha.
# Confira os nomes na documentação da versão em uso.
RELAY_USER=
RELAY_PASSWORD=
# no servidor
cp mailserver.secrets.env.example mailserver.secrets.env
chmod 600 mailserver.secrets.env
docker compose up -d
docker exec -it mailserver setup email add noreply@lojaexemplo.com.br
docker exec -it mailserver setup config dkim
Sem a senha na linha de comando, o setup email add pede a senha de forma interativa, e ela não fica no histórico do shell. O comando de DKIM grava a chave privada dentro de docker-data/dms/config e mostra o registro TXT que você publica no DNS. Só a parte pública vai para o DNS; a privada não sai do servidor.
Como descobrir se já vazou
git ls-files | grep -E "docker-data|secrets.env|postfix-accounts|\.private$"
git log --all --oneline -- docker-data mailserver.env mailserver.secrets.env
git log --all -p -S "RELAY_PASSWORD" -- mailserver.env
O primeiro comando mostra o que está rastreado hoje. Os outros dois procuram no histórico inteiro, inclusive em branches. Se algo aparecer, considere o segredo comprometido, mesmo que o arquivo tenha sido apagado num commit posterior. Ferramentas como o gitleaks ajudam a automatizar essa busca no pre-commit e na CI.
O que trocar, e em que ordem
- Senha do relay: gere uma nova credencial no provedor de envio, atualize o arquivo secreto, reinicie o container e só então revogue a antiga.
- Senhas das caixas: troque com
setup email updatepara cada conta exposta e avise os usuários. - Chave DKIM: gere uma chave com seletor novo, publique o TXT do novo seletor, passe a assinar com ele e remova o registro antigo do DNS depois de alguns dias. Removendo antes, mensagens em trânsito falham na verificação.
- Só depois limpe o histórico e tire os arquivos do índice com
git rm -r --cached.
A lógica de aceitar o antigo e o novo por um tempo está em trocar segredo sem derrubar o sistema, e o porquê da ordem está em segredo no Git: troque a chave antes de limpar o histórico.
Erros comuns
- Commitar o
.env"para o time subir igual". A senha do relay passa a existir em todo notebook que clonou, para sempre no histórico. - Versionar a pasta
docker-data. Vão junto o hash das senhas e a chave DKIM, que permite assinar mensagens falsas em nome do domínio. - Limpar o histórico sem trocar o segredo. As cópias já clonadas continuam com o valor válido.
- Usar a conta do administrador como remetente do aplicativo. Um vazamento da credencial do app entrega a caixa mais sensível do domínio.
- Desligar verificações para "entregar de qualquer jeito". Desativar TLS no relay ou relaxar restrições de envio troca um problema de configuração por um servidor inseguro.
- Remover o seletor DKIM antigo no mesmo minuto da troca. Mensagens já assinadas e ainda na fila falham na verificação do destinatário.
Checklist
git ls-filesnão listadocker-data, arquivo secreto, contas ou chave privada.- O histórico não tem senha de relay nem chave DKIM.
- O arquivo secreto no servidor tem permissão 600.
- O repositório tem um arquivo de exemplo com os nomes das variáveis, sem valores.
- A imagem está fixada numa versão testada.
- O aplicativo envia por uma conta própria, não pela do administrador.
- A pasta de configuração tem backup fora do Git.
Rode git log --all -p -S "PASSWORD" no repositório da sua infraestrutura agora: ele mostra alguma senha ou chave privada de e-mail?
Referência: https://docker-mailserver.github.io/docker-mailserver/edge/config/environment/