Deploy a Docker Registry Using Self-Signed Certificates and htpasswd
Deploy a Docker Registry using TLS (key/certificate) and htpasswd (authentication)

We’ll start with creating a directory in which we’ll store our configuration and certificates.
# Create a directory and access it
$ mkdir registry && cd "$_"
In this directory, we’ll create two subdirectories: one for our TLS configuration and one for our htpasswd
configuration.
# Create subdirectories
$ mkdir certs
$ mkdir auth
We’ll generate a key and secure it. After that, we’ll use the key to generate our self-signed certificate.
# Generate private key
$ cd certs/
$ openssl genrsa 1024 > domain.key
$ chmod 400 domain.key# Generate certificate
$ openssl req -new -x509 -nodes -sha1 -days 365 -key domain.key -out domain.crt# Verify
$ ls
domain.crt domain.key
We’re ready with our TLS configuration. Now, we access our auth/
directory and start configuring our credentials using htpasswd
.
# Access auth/ directory
$ cd ../auth/# Use the registry container to generate a htpasswd file
$ docker run --rm --entrypoint htpasswd registry:2 -Bbn username password > htpasswd# Verify
$ cat htpasswd
username:$2y$05$mnaMdOsL7RCjyhTwYnGSp.7OUmZyd2EYLYj0WWKGKSpcVCl9
All our configuration is done. We can start the registry container.
# Go back inside your registry/ directory
$ cd ..
$ pwd
/Users/xxx/registry# Start Registry container
docker run -d \
--restart=always \
--name registry \
-v `pwd`/auth:/auth \
-v `pwd`/certs:/certs \
-v `pwd`/certs:/certs \
-e REGISTRY_AUTH=htpasswd \
-e REGISTRY_AUTH_HTPASSWD_REALM="Registry Realm" \
-e REGISTRY_AUTH_HTPASSWD_PATH=/auth/htpasswd \
-e REGISTRY_HTTP_ADDR=0.0.0.0:443 \
-e REGISTRY_HTTP_TLS_CERTIFICATE=/certs/domain.crt \
-e REGISTRY_HTTP_TLS_KEY=/certs/domain.key \
-p 443:443 \
registry:2
Your registry is running on https://localhost/
. Lets push an image to it.
# Pull busybox image
$ docker pull busybox# Tag the image
$ docker tag busybox localhost:443/busybox# Try to push the image
docker push localhost:443/busybox
The push refers to repository [localhost:443/busybox]
0314be9edf00: Preparing
no basic auth credentials# Perform a docker login
$ docker login -u username https://localhost:443
Password:
Login Succeeded# Push again
$ docker push localhost:443/busybox
The push refers to repository [localhost:443/busybox]
0314be9edf00: Pushed
latest: digest: sha256:186694df7e479d2b8bf075d9e1b1d7a884c6de60470006d572350573bfa6dcd2 size: 527
My registry is hosted on an AWS EC2 instance. I can access it from inside that machine on localhost
, but I should also be able to access it from a remote machine using the public hostname or the public IP of the server where my registry is hosted. I have used -p 443:443
, which maps the port of my registry container on port 443 of my host.
Don’t forget to open port 443 (security group or firewall). If you try to log in, you’ll see the following error:
# Perform a docker login
$ docker login -u username https://ec2–xx–xx–xx–xx.eu-west-1.compute.amazonaws.com:443
Password:
Error response from daemon: Get https://ec2–xx–xx–xx–xx.eu-west-1.compute.amazonaws.com:443/v2/: x509: certificate signed by unknown authority
This is because we’re using self-signed certificates. We should configure the Docker daemon to trust our self-signed certificate.
On a Linux machine, you should create the following directory. The directory should match the hostname of the server that’s hosting the registry.
$ sudo mkdir -p /etc/docker/certs.d/ec2–xx–xx–xx–xx.eu-west-1.compute.amazonaws.com:443/
Next, you should copy the domain.crt
, which we generated earlier to this directory and call it ca.crt
.
Now try to log in again:
# Perform a docker login
$ docker login -u username https://ec2–xx–xx–xx–xx.eu-west-1.compute.amazonaws.com:443
Password:
Login Succeeded
Conclusion
We have deployed a Docker registry using TLS and htpasswd. We need to authenticate before we can push an image. We also learned how to access the registry from a remote machine.