← Back to DevBytes

Docker Compose Secrets: Production Guide

Understanding Docker Compose Secrets

Secrets in Docker Compose provide a secure mechanism for injecting sensitive data — passwords, API keys, certificates, database connection strings — into containers at runtime without baking them into images or exposing them in environment variables. The feature relies on Docker’s native secret management infrastructure, which encrypts secrets in transit, stores them safely on the swarm manager, and delivers them only to services that explicitly request them. This article focuses on production-grade usage: what secrets are, why they matter, how to define and consume them in a Compose file, and best practices to keep your deployments airtight.

What Exactly Are Docker Secrets?

A secret is a named encrypted blob that Docker mounts as a read-only file into the container’s /run/secrets/<secret_name> directory. Unlike environment variables, secrets are not visible in docker inspect output, process lists, or container logs. They are managed by the Docker daemon’s secrets subsystem, which is available in two contexts:

In both cases, the container sees a plaintext file at the designated mount point, but the secret never appears in the image layers, environment variables, or container definition.

Why Secrets Matter in Production

Hardcoding credentials inside images is a severe security anti‑pattern. Images are often pushed to registries, scanned, and shared across teams — leaking a database password there compromises the entire stack. Environment variables are slightly better but still appear in docker inspect, docker compose config, and process‑table dumps. Secrets solve these issues:

How to Use Docker Compose Secrets

The following walk‑through covers both swarm‑mode secrets (recommended for true production clusters) and file‑based secrets for simpler Compose deployments. All examples assume Compose file version 3.8 or newer, which is the minimum required for secrets support.

1. Swarm Mode Secrets

First, ensure your Docker Engine is in swarm mode. On the manager node, run:

docker swarm init

Create a secret from a file or standard input. For example, a database password:

echo "SuperSecret!Pass123" | docker secret create db_password -

Alternatively, read from a file:

docker secret create db_password ./secrets/db_password.txt

Secrets are immutable; to update, you must remove and re‑create (or use external secret management with a driver). List existing secrets:

docker secret ls

Next, define a Compose file (e.g., docker-compose.yml) that references the secret. The top‑level secrets block declares which secrets are available, and each service lists the secrets it needs.

version: "3.8"

secrets:
  db_password:
    external: true   # tells Compose the secret was already created via `docker secret create`

services:
  app:
    image: myapp:latest
    secrets:
      - db_password
    environment:
      - DB_PASSWORD_FILE=/run/secrets/db_password
    deploy:
      replicas: 2
      restart_policy:
        condition: any

  db:
    image: postgres:15
    secrets:
      - db_password
    environment:
      - POSTGRES_PASSWORD_FILE=/run/secrets/db_password

In this example, external: true tells Compose not to try to create the secret itself but to rely on the pre‑existing swarm secret named db_password. The app and database services both mount the secret at /run/secrets/db_password. Many official images (like Postgres) support _FILE suffixed environment variables that read the secret from that path instead of requiring plain text.

Deploy the stack:

docker stack deploy -c docker-compose.yml mystack

Now every replica of app and db has the secret available. If you scale the app service up, new containers automatically receive the secret.

2. File‑Based Secrets (Non‑Swarm Compose)

For single‑host production or CI environments where swarm mode is not desired, Compose can mount secrets from local files. The syntax is similar but uses the file key inside the top‑level secrets block. Docker Compose v2.19+ is required; check your version with docker compose version.

Create a secret file on the host (ensure it is not committed to version control):

mkdir -p ./secrets
echo "SuperSecret!Pass123" > ./secrets/db_password.txt
chmod 600 ./secrets/db_password.txt

Compose file:

version: "3.8"

secrets:
  db_password:
    file: ./secrets/db_password.txt

services:
  app:
    image: myapp:latest
    secrets:
      - db_password
    environment:
      - DB_PASSWORD_FILE=/run/secrets/db_password

Launch with docker compose up -d. The file’s content is bind‑mounted into /run/secrets/db_password. The mount is read‑only inside the container. Note: unlike swarm secrets, the content is not encrypted at rest on the host — you are responsible for securing the source file (e.g., restricting filesystem permissions, using encrypted volumes).

3. Consuming Secrets Inside the Container

The secret appears as a regular file. Your application can read it directly:

# Read secret in a shell script
DB_PASSWORD=$(cat /run/secrets/db_password)

Or, in a programming language:

# Python example
with open('/run/secrets/db_password', 'r') as f:
    db_password = f.read().strip()

Many official Docker images support _FILE variables out of the box. For example, the Postgres image checks POSTGRES_PASSWORD_FILE and uses its content if defined, falling back to POSTGRES_PASSWORD. Always prefer the _FILE variant for secrets.

Best Practices for Production Secrets

Conclusion

Docker Compose secrets turn credential management from a risky afterthought into a first‑class, declarative part of your stack definition. Whether you operate a full Docker Swarm cluster or a single‑host Compose deployment, secrets keep sensitive material out of images, environment dumps, and configuration files. By adopting the practices above — external secret management, least‑privilege attachment, immutable rotation, and _FILE‑based consumption — you harden your production environment without sacrificing developer velocity. Start migrating your plain‑text environment variables today, and let Docker handle the secure delivery so your application only sees what it needs, when it needs it.

🚀 Need a reliable AI agent for your project?

Deploy Hermes Agent in 10 minutes. Managed hosting, zero DevOps.

Get Started — $23.99/mo
← Back to all articles