Inject Docker runtime configuration without baking secrets
Choose explicit container environment inputs, secret mounts, verification, rotation, and rollback without embedding credentials in an image.
A database endpoint belongs to deployment configuration, not to a reusable container image. A database password belongs in a secret-delivery system, not a Dockerfile, shell history, repository, or diagnostic dump. Docker can inject runtime environment values with --env or --env-file, but the transport you choose must match the sensitivity and operational lifecycle of each value.
Classify inputs before choosing a flag
- Non-secret configuration: log level, feature mode, public service hostname, or timeout. Environment variables are usually appropriate.
- Secrets: passwords, API tokens, private keys, and signing material. Prefer an orchestrator or platform secret mounted as a file, with narrow access and an auditable rotation path.
- Image defaults: harmless values that should apply everywhere. Dockerfile
ENVcan provide defaults, but runtime configuration can override them and the values persist in image metadata and derived containers.
Do not hard-code DATABASE_URL with credentials in a Dockerfile. Removing the line in a later layer does not reliably erase it from previous layers or build history.
Single-container runtime configuration
docker run --rm \
--env APP_MODE=production \
--env DB_HOST=db.internal.example \
--env DB_USER \
example/web:sha-256
When --env NAME has no equals sign, the Docker CLI copies that variable from the client environment. If it is absent, Docker leaves it unset. Validate required configuration at process startup and exit with a clear variable name, never its value.
For a larger non-secret set:
# runtime.env — mode 0600, excluded from version control
APP_MODE=production
DB_HOST=db.internal.example
LOG_LEVEL=info
docker run --env-file ./runtime.env example/web:sha-256
Docker’s run-time env-file syntax supports VAR=value, a bare VAR to copy from the client environment, and full-line comments beginning with #. Do not assume Compose interpolation syntax works in docker run --env-file; Docker explicitly documents that interpolation as a Compose CLI feature.
Compose: separate interpolation from container environment
services:
web:
image: example/web@sha256:verified-digest
environment:
APP_MODE: production
DB_HOST: ${DB_HOST:?DB_HOST must be set}
secrets:
- db_password
secrets:
db_password:
file: ./secrets/db_password
A project .env file feeds Compose interpolation; it does not automatically place every variable inside the container. The service’s environment or env_file attribute controls container environment. Render and inspect the resolved model with:
docker compose config
docker compose config --environment
Treat that output as sensitive if configuration includes secrets. Compose’s official guidance warns against passing sensitive values as ordinary environment variables and recommends secrets instead.
Consume secrets as files
With a Compose secret granted to a service, the application normally reads it from /run/secrets/db_password. Make the path configurable, trim only the delimiter your secret format defines, and never log the content. File-based delivery reduces accidental exposure through environment dumps, but it does not protect against a process or administrator already able to read the container’s memory or mounted secret.
For image builds, runtime flags are not available. Use BuildKit secret mounts for credentials needed temporarily during a build:
docker build --secret id=package_token,env=PACKAGE_TOKEN .
In the Dockerfile, consume the secret in a BuildKit secret mount for the one build step that needs it. Do not replace this with ARG or ENV; build arguments and environment metadata are not secret stores.
Networking is a separate problem
Passing a hostname does not make an external database reachable. Verify DNS resolution, route and firewall policy, TLS trust, database listener address, and server-side authorization from the container’s network context. Avoid the accepted answer’s historical --link example: user-defined Docker networks and service discovery are the current approach, while an external managed database should have an explicit DNS name and tightly scoped network access.
Use a dedicated database identity with minimum privileges. Require TLS and verify the server name. A container reaching TCP port 5432 proves only transport connectivity, not authentication, schema readiness, or safe failover behavior.
Verify without leaking values
docker inspect --format '{{json .Config.Env}}' container_name
docker exec container_name sh -c 'test -n "$DB_HOST"'
docker exec container_name sh -c 'test -r /run/secrets/db_password'
The first command can reveal environment values; run it only in an authorized diagnostic context and do not paste its output into tickets. Prefer application health endpoints that report configuration presence, dependency status, and the non-sensitive destination identity without echoing credentials.
Test four paths before production: correct configuration, missing required value, invalid credential, and unreachable dependency. The process should fail predictably, remain restart-safe, and avoid retry storms. Put bounded backoff around transient connections and distinguish authentication failure from network timeout in metrics.
Rotation, rollback, and incident recovery
Changing a container’s configured environment normally requires replacing the container; restarting the same container does not recreate its configuration. Plan a rollout that supports overlapping old and new credentials: issue a new credential, deploy consumers, verify adoption, revoke the old credential, and audit for remaining use. Whether a mounted secret updates in place depends on the platform; design the application to reload safely or recreate it explicitly.
Keep the previous non-secret configuration and image digest as a deployable release. If a rollout fails, restore the prior release while preserving database compatibility. Do not roll back to a credential that was exposed or revoked. In a leak, rotate first, invalidate sessions or tokens where applicable, search image registries and CI logs for the value, and rebuild affected images from a clean boundary. Deleting a tag does not prove that cached layers disappeared.
Attribution and current verification
This guide was prompted by AJcodez’s Stack Overflow question and errata’s accepted answer, used under CC BY-SA. Its --env and --env-file core remains valid, while the obsolete linking example and secret handling were corrected. Current behavior was independently verified against Docker’s official documentation for container run environment flags, Compose container environments, Compose secrets, and BuildKit build secrets.
Primary source: Review the official reference ↗