Certificate Depot

Guides

Home › Guides › Docker

Self-Signed SSL Certificates in Docker

Mount certs, build them into images, or trust them inside a container — all the patterns for self-signed certs in Docker.

Running a self-signed cert in a container is the same as on bare metal — you just need the files where the process can read them. A few patterns cover 99% of use cases.

Pattern 1: Mount certs as a volume (recommended)

Keeps certs out of the image. Rotate them without rebuilding.

# docker-compose.yml
services:
  nginx:
    image: nginx:alpine
    ports:
      - "443:443"
    volumes:
      - ./certs:/etc/nginx/ssl:ro
      - ./nginx.conf:/etc/nginx/nginx.conf:ro

Then in nginx.conf:

ssl_certificate     /etc/nginx/ssl/certificate.pem;
ssl_certificate_key /etc/nginx/ssl/private-key.pem;

Pattern 2: Docker secrets

For Docker Swarm, put certs in secrets. They're mounted at /run/secrets/ read-only inside the container.

# docker-compose.yml
secrets:
  cert:
    file: ./certificate.pem
  key:
    file: ./private-key.pem

services:
  nginx:
    image: nginx:alpine
    secrets: [cert, key]
    # reference as /run/secrets/cert and /run/secrets/key

Pattern 3: Build certs into the image (dev only)

FROM nginx:alpine
COPY certificate.pem /etc/nginx/ssl/
COPY private-key.pem /etc/nginx/ssl/
COPY nginx.conf /etc/nginx/nginx.conf
Never ship a container image to a registry with the private key baked in. Anyone who pulls the image can extract the key. Use mount or secrets for anything that leaves your laptop.

Trust a self-signed cert inside the container

If your app runs in a container and needs to call an HTTPS service with a self-signed cert:

# Dockerfile — Debian/Ubuntu-based
COPY ca.pem /usr/local/share/ca-certificates/my-ca.crt
RUN update-ca-certificates

Alpine:

COPY ca.pem /usr/local/share/ca-certificates/my-ca.crt
RUN apk add --no-cache ca-certificates && update-ca-certificates

Pattern 4: Caddy (auto-HTTPS in a container)

For pure local dev, Caddy will generate a self-signed cert on the fly:

# Caddyfile
localhost {
    reverse_proxy app:3000
    tls internal
}

tls internal tells Caddy to mint a cert from its internal CA. Trust Caddy's CA in your OS once, and everything it serves is trusted for the duration of the cert.

Troubleshooting

"SSL_CTX_use_PrivateKey_file failed"

The container can't read the key file. Check volume mount permissions, and make sure the file isn't empty (a common silent failure when a volume path is wrong — it creates an empty directory instead of mounting the file).

Client inside container can't verify a self-signed server

You need to trust the cert inside the container — see the update-ca-certificates pattern above. For Node.js containers, mount the cert and set NODE_EXTRA_CA_CERTS.

Need a self-signed certificate? Use our free generator — browser-compatible SANs, RSA or ECDSA, ZIP or PFX. No signup, no ads, keys never stored.

Further Reading