Never store real secrets in .env files in the repo. Keep .env.example as documentation with placeholders only.
Use sops + age (or GPG) to encrypt per-environment secrets that can be safely committed.
# writes to ~/.config/sops/age/keys.txt
age-keygen -o ~/.config/sops/age/keys.txtAdd the public recipient from that file (starts with age1...) to your repository SOPS config.
Create .sops.yaml at repo root:
# Encrypt files matching these globs with the recipient below
creation_rules:
- path_regex: secrets/.*\.(env|yaml|yml)$
age: ["AGE1_PUBLIC_KEY_HERE"]
encrypted_regex: '^(?!#)'Replace AGE1_PUBLIC_KEY_HERE with your public age key.
Place per-environment secrets under secrets/ and encrypt with sops:
mkdir -p secrets
printf "TRAEFIK_ENABLE=true\nSSO_CREDENTIALS=admin:$apr1$...\n" > secrets/traefik.dev.env
sops -e -i secrets/traefik.dev.envThe file is now encrypted at rest and safe to commit.
# Produces a plaintext file for docker usage (do not commit this)
sops -d secrets/traefik.dev.env > traefik/.envYou can add a simple make/script target to automate decrypt -> deploy -> clean.
On a deployment host, provision the age private key (read-only, secured). Decrypt secrets just-in-time before docker stack deploy.
Docker Swarm supports native secrets. You can combine sops+age with docker secret create:
- Decrypt locally in memory and pipe to secret create:
sops -d secrets/traefik.dev.env | docker secret create traefik_env -- Reference the secret in your stack file using
secrets:andenv_filealternatives where appropriate.
This is more granular and keeps values out of env vars in the container filesystem, but requires adjusting service configs to read from files or environment sourced from secrets.
- Commit only
.env.examplefiles and encrypted files undersecrets/. - Never commit plaintext
.env. - Add a
.gitignorerule for**/.envand**/*.env.decryptedas needed.
- If
sopscan’t decrypt: ensure the age private key is in~/.config/sops/age/keys.txt. - For team usage: include multiple recipients in
.sops.yamlso each developer can decrypt.