CRITICAL

Solved: Docker SSL Handshake Failed Error with Private Registry

Quick Fix Summary

TL;DR

Add your registry's CA certificate to Docker's trusted certificates at /etc/docker/certs.d/<registry_host>/ca.crt and restart Docker.

Docker cannot establish a secure TLS connection to your private registry because it doesn't trust the registry's SSL/TLS certificate. This typically occurs when using self-signed certificates or certificates from a private Certificate Authority.

Diagnosis & Causes

  • Self-signed certificate not trusted by Docker daemon.
  • Registry certificate signed by private CA not in Docker's trust store.
  • Certificate Common Name (CN) doesn't match registry hostname.
  • Certificate has expired or is not yet valid.
  • Docker daemon not configured to trust custom certificates.
  • Recovery Steps

    1

    Step 1: Verify the SSL Connection Manually

    First, confirm the SSL issue exists and examine the certificate details using OpenSSL.

    bash
    openssl s_client -connect your.registry.com:443 -showcerts
    openssl s_client -connect your.registry.com:443 2>&1 | openssl x509 -noout -dates -subject -issuer
    2

    Step 2: Place the CA Certificate in Docker's Trust Directory

    Copy the registry's CA certificate (or the self-signed certificate itself) to the correct Docker directory. Create the directory if it doesn't exist.

    bash
    sudo mkdir -p /etc/docker/certs.d/your.registry.com
    sudo cp your-ca-certificate.crt /etc/docker/certs.d/your.registry.com/ca.crt
    3

    Step 3: Restart the Docker Daemon

    Restart Docker to pick up the new trusted certificates. Use the appropriate command for your init system.

    bash
    sudo systemctl restart docker
    sudo service docker restart
    4

    Step 4: Test the Fix

    Verify the SSL handshake now succeeds by attempting to log in or pull an image.

    bash
    docker login your.registry.com
    docker pull your.registry.com/myimage:latest
    5

    Step 5: Alternative - Insecure Registry (TEMPORARY FIX ONLY)

    For emergency recovery only, configure Docker to treat the registry as insecure. WARNING: This disables SSL verification.

    bash
    sudo nano /etc/docker/daemon.json
    6

    Step 5 (continued): Add Insecure Registry Configuration

    Add the 'insecure-registries' key to the daemon.json file, then restart Docker.

    json
    {
      "insecure-registries": ["your.registry.com"]
    }

    Architect's Pro Tip

    "For Kubernetes clusters pulling from private registries, you must also add the CA certificate to the nodes at the OS level (/etc/ssl/certs/) and update the containerd or Docker configuration there."

    Frequently Asked Questions

    Do I need to restart Docker after adding a certificate?

    Yes, the Docker daemon only reads the certificate trust store on startup. A restart is required for it to recognize new certificates.

    What if my registry uses a different port, like 5000?

    Include the port in the directory name: /etc/docker/certs.d/your.registry.com:5000/ca.crt.

    How do I get the CA certificate from my registry?

    If you control the registry, use the certificate file from its TLS configuration. Otherwise, extract it using `openssl s_client -connect host:port 2>&1 < /dev/null | sed -n '/-----BEGIN/,/-----END/p' > cert.crt`.

    Related Docker Guides