Docker TLS & Certificate Commands
Comprehensive guide to Docker TLS configuration, certificate management, and secure registry operations
🔒 Docker Daemon TLS Configuration
Generate CA (Certificate Authority)
# Generate CA private key
openssl genrsa -aes256 -out ca-key.pem 4096
# Generate CA certificate
openssl req -new -x509 -days 365 -key ca-key.pem -sha256 -out ca.pem \
-subj "/C=US/ST=CA/L=San Francisco/O=Example/CN=Docker CA"Creates a Certificate Authority for signing Docker daemon and client certificates.
Generate server key and certificate
# Generate server private key
openssl genrsa -out server-key.pem 4096
# Create certificate signing request
openssl req -subj "/CN=docker-host" -sha256 -new -key server-key.pem -out server.csr
# Add subject alternative names (replace with your IPs/hostnames)
echo "subjectAltName = DNS:docker-host,IP:10.0.0.1,IP:127.0.0.1" > extfile.cnf
echo "extendedKeyUsage = serverAuth" >> extfile.cnf
# Sign the certificate
openssl x509 -req -days 365 -sha256 -in server.csr -CA ca.pem -CAkey ca-key.pem \
-CAcreateserial -out server-cert.pem -extfile extfile.cnfCreates server certificate with multiple hostnames/IPs for Docker daemon.
Generate client key and certificate
# Generate client private key
openssl genrsa -out key.pem 4096
# Create certificate signing request
openssl req -subj '/CN=client' -new -key key.pem -out client.csr
# Sign client certificate
echo "extendedKeyUsage = clientAuth" > extfile-client.cnf
openssl x509 -req -days 365 -sha256 -in client.csr -CA ca.pem -CAkey ca-key.pem \
-CAcreateserial -out cert.pem -extfile extfile-client.cnfConfigure daemon.json for TLS
{
"tlsverify": true,
"tlscacert": "/etc/docker/certs/ca.pem",
"tlscert": "/etc/docker/certs/server-cert.pem",
"tlskey": "/etc/docker/certs/server-key.pem",
"hosts": ["tcp://0.0.0.0:2376", "unix:///var/run/docker.sock"]
}Place in /etc/docker/daemon.json and restart Docker: sudo systemctl restart docker
Connect to Docker daemon with TLS
docker --tlsverify \
--tlscacert=ca.pem \
--tlscert=cert.pem \
--tlskey=key.pem \
-H=docker-host:2376 versionSet environment variables for TLS
export DOCKER_HOST=tcp://docker-host:2376
export DOCKER_TLS_VERIFY=1
export DOCKER_CERT_PATH=/path/to/certs
# Now use docker commands normally
docker ps🏪 Docker Registry TLS Configuration
Run registry with TLS (Let's Encrypt)
docker run -d \
--name registry \
-p 5000:5000 \
-v /path/to/certs:/certs \
-e REGISTRY_HTTP_TLS_CERTIFICATE=/certs/fullchain.pem \
-e REGISTRY_HTTP_TLS_KEY=/certs/privkey.pem \
registry:2Uses Let's Encrypt certificates for secure registry.
Run registry with self-signed certificate
# Generate self-signed certificate
openssl req -newkey rsa:4096 -nodes -sha256 \
-keyout domain.key -x509 -days 365 -out domain.crt \
-subj "/CN=registry.example.com"
# Run registry
docker run -d \
--name registry \
-p 5000:5000 \
-v /path/to/certs:/certs \
-e REGISTRY_HTTP_TLS_CERTIFICATE=/certs/domain.crt \
-e REGISTRY_HTTP_TLS_KEY=/certs/domain.key \
registry:2Add self-signed CA to Docker trust store (Linux)
# Copy CA certificate
sudo mkdir -p /etc/docker/certs.d/registry.example.com:5000
sudo cp ca.crt /etc/docker/certs.d/registry.example.com:5000/ca.crt
# Restart Docker
sudo systemctl restart dockerAdd self-signed CA to system trust store (Ubuntu/Debian)
sudo cp ca.crt /usr/local/share/ca-certificates/docker-registry-ca.crt
sudo update-ca-certificates
sudo systemctl restart dockerAdd self-signed CA to macOS trust store
sudo security add-trusted-cert -d -r trustRoot \
-k /Library/Keychains/System.keychain ca.crtTest registry connectivity
curl https://registry.example.com:5000/v2/Should return: {}
📦 Container Certificate Management
Mount certificates as volumes
docker run -d \
-v /host/certs:/app/certs:ro \
-e SSL_CERT_FILE=/app/certs/cert.pem \
-e SSL_KEY_FILE=/app/certs/key.pem \
myapp:latestMounts certificates as read-only volume for application use.
Add CA certificates to container
# In Dockerfile
FROM alpine:latest
COPY ca-cert.crt /usr/local/share/ca-certificates/
RUN update-ca-certificatesAdd CA certificates to running container
docker cp ca-cert.crt container_name:/usr/local/share/ca-certificates/
docker exec container_name update-ca-certificatesCopy certificates into image (not recommended for production)
# In Dockerfile
FROM node:18
COPY certs/ /app/certs/
RUN chmod 600 /app/certs/key.pem⚠️ Warning: Certificates will be in image layers. Use secrets or volumes instead.
🔐 Docker Secrets (Swarm)
Create secret from file
docker secret create ssl_cert cert.pemCreate secret from stdin
cat cert.pem | docker secret create ssl_cert -List secrets
docker secret lsUse secrets in service
docker service create \
--name myapp \
--secret source=ssl_cert,target=/run/secrets/cert.pem \
--secret source=ssl_key,target=/run/secrets/key.pem \
myapp:latestSecrets are mounted at /run/secrets/ by default.
Use secrets in docker-compose.yml
version: '3.8'
services:
app:
image: myapp:latest
secrets:
- ssl_cert
- ssl_key
environment:
- SSL_CERT_FILE=/run/secrets/ssl_cert
- SSL_KEY_FILE=/run/secrets/ssl_key
secrets:
ssl_cert:
file: ./certs/cert.pem
ssl_key:
file: ./certs/key.pemRemove secret
docker secret rm ssl_cert🔑 Registry Authentication with Certificates
Login to private registry
docker login registry.example.com:5000Login with credentials from file
docker login --username myuser --password-stdin registry.example.com < password.txtConfigure registry authentication in config.json
{
"auths": {
"registry.example.com:5000": {
"auth": "base64(username:password)"
}
}
}Located at ~/.docker/config.json
Pull from private registry
docker pull registry.example.com:5000/myapp:latestPush to private registry
docker tag myapp:latest registry.example.com:5000/myapp:latest
docker push registry.example.com:5000/myapp:latest📦 Docker Compose TLS Configuration
Nginx reverse proxy with TLS (docker-compose.yml)
services:
nginx:
image: nginx:alpine
ports:
- "443:443"
volumes:
- ./certs:/etc/nginx/certs:ro
- ./nginx.conf:/etc/nginx/nginx.conf:ro
restart: unless-stopped
app:
build: .
expose:
- "3000"Traefik with automatic TLS (docker-compose.yml)
services:
traefik:
image: traefik:v2
command:
- "--entrypoints.websecure.address=:443"
- "--certificatesresolvers.myresolver.acme.tlschallenge=true"
- "[email protected]"
- "--certificatesresolvers.myresolver.acme.storage=/letsencrypt/acme.json"
ports:
- "443:443"
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
- ./letsencrypt:/letsencrypt
app:
image: myapp:latest
labels:
- "traefik.http.routers.app.rule=Host(`example.com`)"
- "traefik.http.routers.app.tls.certresolver=myresolver"Traefik automatically obtains and renews certificates via ACME TLS challenge.
🔧 Troubleshooting TLS Issues
Error: "x509: certificate signed by unknown authority"
Docker doesn't trust the CA. Add CA to Docker's trust store:
sudo mkdir -p /etc/docker/certs.d/registry.example.com:5000
sudo cp ca.crt /etc/docker/certs.d/registry.example.com:5000/ca.crt
sudo systemctl restart dockerError: "certificate is valid for ..., not ..."
Certificate's Common Name (CN) or Subject Alternative Names (SAN) don't match. Regenerate certificate with correct hostnames/IPs.
Test TLS connection to registry
openssl s_client -connect registry.example.com:5000 -showcertsTest registry API
# Test catalog
curl https://registry.example.com:5000/v2/_catalog
# Test specific image
curl https://registry.example.com:5000/v2/myapp/tags/listCheck Docker TLS configuration
docker info | grep -i tlsDisable TLS verification (testing only)
# Add to /etc/docker/daemon.json
{
"insecure-registries": ["registry.example.com:5000"]
}⚠️ Warning: Only for testing. Never use in production.
✅ Best Practices
Certificate management
- Use Let's Encrypt for public registries (automatic renewal)
- Use 4096-bit RSA or EC P-256 keys minimum
- Set reasonable expiry dates (90-365 days) and automate renewal
- Never commit certificates or private keys to version control
- Use Docker secrets or external secret management (Vault, AWS Secrets Manager)
Security
- Always enable TLS verification (no insecure registries in production)
- Use Docker secrets instead of environment variables for sensitive data
- Rotate certificates before expiry (automated with Let's Encrypt)
- Use read-only mounts for certificates in containers
- Implement certificate pinning for high-security environments
Production readiness
- Use proper CA-signed certificates (not self-signed) in production
- Monitor certificate expiry with alerting (30/7/1 day warnings)
- Document certificate locations and renewal procedures
- Test certificate rotation procedures regularly
- Keep backup copies of certificates in secure location