Hi,
I saw a bunch of complicated guides that involved custom scripts and changing the container’s entrypoint, and it all felt like way too much work. Instead of making Caddy read an exposed environment variable, you can just use Docker Secrets to mount your token as a file and tell Caddy to read that file directly.
The Goal
In my case I want to use Docker Secrets for DESEC_TOKEN so it’s not exposed as an environment variable.
1. The Secret File
First, I removed the token from my .env file and put it in a new file on my host named desec_token.txt. The file contains only the token string.
desec_token.txt
YourDeSECTokenHere
2. The docker-compose.yml
In my docker-compose.yml, I told the caddy service to use this file and defined it in the top-level secrets: block.
services:
caddy:
build: .
container_name: caddy
restart: unless-stopped
ports:
- "80:80"
- "443:443"
volumes:
- data:/data
- config:/config
networks:
- proxy
secrets:
- desec_token
volumes:
data:
config:
networks:
proxy:
external: true
secrets:
desec_token:
file: ./desec_token.txt
3. The Caddyfile
This is the most important part. Docker mounts the secret at /run/secrets/desec_token (using the key from the compose file).
I modified my (dns_challenge) snippet to use the {file.} placeholder to read the token directly from that file.
(dns_challenge) {
tls {$ACME_EMAIL} {
propagation_delay 60s
propagation_timeout 300s
dns desec {
token {file./run/secrets/desec_token}
}
}
}
Now, when I run docker inspect caddy, the token is nowhere to be found.
This can also be applied to other services that have sensitive values such as API key, database passwords and so on.