On this page
Environment variables are a delivery method, not a security rating
Moving a password from code into .env is progress, but the file is not automatically safe. It can enter Git, backups, an image build context, a process environment, or debug logs. Separate information into public configuration, internal but non-sensitive configuration, and secrets that must be rotated promptly if exposed. Only the last group needs secret-handling rules.
Database passwords, session-signing keys, third-party API tokens, SMTP passwords, and private keys are common secrets. Domain names, log levels, and public site URLs generally are not. Hiding every setting can make troubleshooting harder without improving security.
Keep a secret inventory without storing the values
For each secret, record its name, purpose, consuming service, owner, source, creation date, rotation schedule, and revocation method. Do not put the actual value in the inventory. This tells you which processes are affected if one API token leaks and reveals credentials that remain active after their use has ended.
Use separate credentials for development, testing, and production. Avoid making a long-lived key from a personal account into a permanent server asset. Prefer a service account and the least privileges it needs over a full administrator key.
Set explicit file locations and permissions
For systemd, /etc/myapp/myapp.env can be read through EnvironmentFile. Root can manage the file while the application group receives read access only. Keep a Compose env_file outside publicly served or loosely shared locations, or restrict its permissions carefully. Exclude secret files from Git and the image build context.
sudo install -d -m 750 -o root -g myapp /etc/myapp
sudo install -m 640 -o root -g myapp /private/path/myapp.env /etc/myapp/myapp.env
sudo -u myapp test -r /etc/myapp/myapp.envDo not paste values into shared chat, shell history, or screenshots. Use an access-controlled editing method and inspect temporary files and command history afterward. If backups include secrets, encrypt and restrict those backups too.
Check what containers can expose
Do not bake production secrets into a Dockerfile with ARG or ENV; values can remain in image layers or build records. Compose environment variables can carry ordinary configuration. For highly sensitive material, consider a restricted file mount or a platform secrets mechanism. A process with permission inside the container can still read what it is given, so least privilege and isolation remain necessary.
docker compose config may expand variables. Do not upload its output to a public issue. Health checks and error responses must not echo complete connection strings either.
Design rotation so two keys can briefly coexist
Replacing a database password or signing key in one step may disconnect old processes or sign out everyone. If the system supports two valid keys during a transition, add the new one, deploy and verify, then revoke the old one. If it does not, schedule a maintenance window: back up, update the server side, restart consumers in order, and confirm the old key no longer works.
Rotating a session-signing key may invalidate existing sessions; plan for that user impact. For a database, a new account can sometimes be created and connections moved before the old account is removed. Update the inventory when rotation finishes, not just the environment file.
If a leak is suspected, revoke first
Limit exposure, revoke or rotate the credential, check for unusual use, close the leak path, and then review how it happened. Removing a string from Git history is not enough: old commits and clones may retain it. Treat a real exposed credential as compromised.
Keep a timeline of discovery, affected services, revocation, and any suspicious activity. Do not copy the secret into the incident report while investigating. Check public repositories, CI logs, and image registries as possible exposure paths.
What counts as done?
Production secrets are absent from the repository and images; services read restricted files with minimal privilege; development and production credentials differ; logs do not echo values; and every secret has an owner and revocation method. Rehearse at least one rotation. Next, test whether the system is truly recoverable with a database backup and restore.
Sources
Next steps
Continue with the next useful task; you do not need to read everything at once.