The 'secret is not defined' error in Docker Compose occurs when a service references a secret that hasn't been declared in the top-level secrets section of your compose file. Fix it by defining the secret at the top level with either a file source or external reference.
The "secret is not defined" error indicates that Docker Compose found a reference to a secret in a service definition, but that secret hasn't been declared in the top-level `secrets:` section of your compose file. Docker Compose secrets work in two parts: 1. **Top-level declaration**: You must define all secrets at the root level of your compose file, specifying where the secret value comes from (a file, environment variable, or external source) 2. **Service-level reference**: Services then reference which secrets they need access to When you reference a secret in a service (like `secrets: [my_secret]`) without first declaring it at the top level, Docker Compose cannot resolve where that secret value should come from, resulting in this error. This error commonly occurs when: - Copying service definitions without their corresponding secret declarations - Migrating from Docker Swarm where secrets were created externally - Forgetting to add the top-level secrets block after adding secrets to a service - Typos in secret names between the top-level declaration and service reference
The most common fix is adding the missing top-level secrets: block. Docker Compose requires secrets to be defined at both the service level AND the top level:
services:
myapp:
image: myapp:latest
secrets:
- my_secret # Service-level: which secrets to use
secrets: # Top-level: where secrets come from
my_secret:
file: ./my_secret.txt # Path to file containing the secretThe secret file should contain the raw secret value (no quotes needed):
# Create the secret file
echo "my-super-secret-value" > ./my_secret.txt
# Verify Docker Compose config is valid
docker-compose configInside your container, the secret will be available at /run/secrets/my_secret.
Ensure the secret name matches exactly between the service reference and top-level declaration:
Incorrect (names don't match):
services:
web:
secrets:
- db_password # Using underscores
secrets:
db-password: # Using hyphens - MISMATCH!
file: ./db_password.txtCorrect:
services:
web:
secrets:
- db_password # Matches exactly
secrets:
db_password: # Same name
file: ./db_password.txtCommon naming issues:
- db_password vs db-password (underscore vs hyphen)
- mySecret vs mysecret (case sensitivity)
- db_pass vs db_password (abbreviation differences)
For local development with Docker Compose, file-based secrets are the simplest approach:
services:
db:
image: postgres:15
environment:
POSTGRES_PASSWORD_FILE: /run/secrets/db_password
secrets:
- db_password
- db_user
app:
image: myapp
secrets:
- db_password
- api_key
depends_on:
- db
secrets:
db_password:
file: ./secrets/db_password.txt
db_user:
file: ./secrets/db_user.txt
api_key:
file: ./secrets/api_key.txtCreate the secrets directory and files:
mkdir -p ./secrets
echo "postgres-password-123" > ./secrets/db_password.txt
echo "postgres" > ./secrets/db_user.txt
echo "api-key-abc123" > ./secrets/api_key.txt
# Don't commit secrets to git
echo "secrets/" >> .gitignoreDocker Compose can also read secrets from environment variables (available in Compose V2):
services:
app:
image: myapp
secrets:
- db_password
secrets:
db_password:
environment: DB_PASSWORD # Read from host environment variableThen set the environment variable before running:
export DB_PASSWORD="my-secret-password"
docker-compose upOr in a .env file:
# .env
DB_PASSWORD=my-secret-passwordThis approach is useful for:
- CI/CD pipelines where secrets are injected as environment variables
- Avoiding secret files on disk
- Dynamic secret values
If you're using Docker Swarm, secrets can be created externally and referenced in your compose file:
# First, create the secret in Docker Swarm
docker swarm init # If not already in swarm mode
echo "my-secret-value" | docker secret create my_secret -Then reference it as external in your compose file:
services:
app:
image: myapp
secrets:
- my_secret
secrets:
my_secret:
external: true # Secret must already exist in SwarmImportant: External secrets ONLY work in Docker Swarm mode. If you see this error with external: true:
- Ensure you've initialized Swarm: docker swarm init
- Verify the secret exists: docker secret ls
- For local development, use file-based secrets instead
Build-time secrets (used during docker-compose build) require a different setup than runtime secrets:
For runtime secrets (used when container runs):
services:
app:
image: myapp
secrets:
- api_key
secrets:
api_key:
file: ./api_key.txtFor build-time secrets (used during image build):
services:
app:
build:
context: .
secrets:
- npm_token # Build-time secret
secrets:
npm_token:
file: ./npm_token.txtIn your Dockerfile, mount the build secret:
# syntax=docker/dockerfile:1
FROM node:18
# Mount and use the secret during build
RUN --mount=type=secret,id=npm_token \
NPM_TOKEN=$(cat /run/secrets/npm_token) npm install
COPY . .Build with BuildKit enabled:
DOCKER_BUILDKIT=1 docker-compose buildUse docker-compose config to validate your compose file and see the resolved configuration:
# Validate the compose file
docker-compose config
# If you see the error, the config is invalid
# ERROR: secret "mysecret" is not defined
# After fixing, you should see the full resolved config
docker-compose configThe output should show your secrets properly defined:
services:
app:
image: myapp
secrets:
- source: my_secret
target: /run/secrets/my_secret
secrets:
my_secret:
file: /full/path/to/my_secret.txtThis command helps catch configuration errors before attempting to start containers.
### Understanding Docker Secrets Architecture
Docker secrets are designed to securely pass sensitive data to containers. Here's how they work:
File-based secrets (Compose standalone)
- Secret content is stored in a file on your host
- Docker mounts the file into the container at /run/secrets/<secret_name>
- The mount is read-only with restrictive permissions
- Works without Docker Swarm
External secrets (Swarm mode)
- Secrets are stored encrypted in the Swarm raft log
- Distributed automatically to nodes that need them
- More secure for production multi-node deployments
- Requires docker swarm init
### Secret Syntax Variations
Docker Compose supports both short and long syntax for secrets:
Short syntax:
services:
app:
secrets:
- my_secretLong syntax (more control):
services:
app:
secrets:
- source: my_secret
target: /custom/path/secret # Custom path in container
uid: '103' # Owner UID
gid: '103' # Owner GID
mode: 0440 # File permissions### Reading Secrets in Applications
Applications need to read from /run/secrets/<name> instead of environment variables:
Node.js:
const fs = require('fs');
const dbPassword = fs.readFileSync('/run/secrets/db_password', 'utf8').trim();Python:
with open('/run/secrets/db_password') as f:
db_password = f.read().strip()Bash:
DB_PASSWORD=$(cat /run/secrets/db_password)### Many Images Support *_FILE Environment Variables
Official images like PostgreSQL, MySQL, and MariaDB support a *_FILE convention:
services:
db:
image: postgres:15
environment:
# Instead of POSTGRES_PASSWORD directly
POSTGRES_PASSWORD_FILE: /run/secrets/db_password
secrets:
- db_passwordThis pattern is more secure than passing secrets as environment variables.
### Secrets vs Environment Variables
| Aspect | Secrets | Environment Variables |
|--------|---------|----------------------|
| Storage | File at /run/secrets | Process memory |
| Visibility | Not in docker inspect | Visible in docker inspect |
| Logging | Not logged | May appear in logs |
| Best for | Passwords, API keys | Non-sensitive config |
### Troubleshooting Common Issues
1. Secret file not found:
# Check file exists and path is correct
ls -la ./secrets/
# Use absolute path if relative doesn't work
secrets:
my_secret:
file: /home/user/project/secrets/my_secret.txt2. Secret empty in container:
# Check file isn't empty
cat ./secrets/my_secret.txt
# Ensure no trailing newlines if app is sensitive to them
echo -n "secret-value" > ./secrets/my_secret.txt3. Permission denied reading secret:
# Check container user can read /run/secrets
docker-compose exec app ls -la /run/secrets/
# Use long syntax to set permissions
secrets:
- source: my_secret
mode: 0444 # World-readable### Security Best Practices
1. Never commit secrets to git - Add to .gitignore
2. Use .env.example - Document required secrets without values
3. Rotate secrets regularly - Recreate secret files periodically
4. Limit access - Only mount secrets to services that need them
5. Use external secrets in production - Swarm secrets or HashiCorp Vault
image operating system "linux" cannot be used on this platform
How to fix 'image operating system linux cannot be used on this platform' in Docker
manifest unknown: manifest unknown
How to fix 'manifest unknown' in Docker
cannot open '/etc/passwd': Permission denied
How to fix 'cannot open: Permission denied' in Docker
Error response from daemon: failed to create the ipvlan port
How to fix 'failed to create the ipvlan port' in Docker
toomanyrequests: Rate exceeded for anonymous users
How to fix 'Rate exceeded for anonymous users' in Docker Hub