Running Your Own Docker Container Registry Made Easy

Containers, DevOps, Docker, Software, Virtualization -

Running Your Own Docker Container Registry Made Easy

This article will cover how you can easily set up a local or externally accessible Docker registry for hosting your own built Docker images.

I have recently gone from running the most minimal HTTP version of the registry on my machine to support my local docker image development workflows to running my own private docker registry available to private and public hosts with access control. I’ll run you through all the steps and gotchas so you can set up whatever kind of registry you need as it’s become a key part of my Dev Ops infrastructure and probably will be for you as well when you see how easy it is.

Running a Docker registry

You can start with running the provider docker registry image from Docker co for a minimal Docker registry setup. This will start an HTTP version of the server without access control accessible on port 5000.

 $ docker run -d -p 5000:5000 — name registry registry:latest

 

Once the registry image has been pulled and is up and running on your machine, you are ready to push your built images to it. Prefix your image tag with your host and port localhost:5000 whenever you tag or push to that registry.

  $ docker push localhost:5000/test-image

 

If you get the following error when trying to push to your HTTP registry, you will need to do some configuration to work around a security restriction for registries to be HTTP only unless the hosts are whitelisted for the docker deamon.

 $ docker push localhost:5000/ubuntu-localUsing default tag: latest
Error response from daemon: Get https://localhost:5000/v2/: http: server gave HTTP response to HTTPS client

 

to work around this error for local testing we can configure our Docker daemon to allow for HTTP connection to our local Docker registry that is running. You will want to configure your Docker daemon.json file with the following config and restart the docker service on your machine to have the settings take effect.

 {
“insecure-registries” : [“localhost:5000”]
}

 

You can find this file at /etc/docker/daemon.json on a Unix based machine and C:\ProgramData\docker\config\daemon.json on windows. However, when running Docker for Windows and Mac, you can also access it via the Docker desktop GUI.

Docker desktop daemon settings screen

Once you have restarted Docker, you should be able to push to the HTTP registry. You can read more about testing a local insecure HTTP registry at the following docs.

Once you have restarted Docker, you should be able to push to the HTTP registry. You can read more about testing a local insecure HTTP registry at the following docs.

https://docs.docker.com/registry/insecure/

An HTTP Docker registry should only be used for local development, testing, or over a secure internal network so use it at your own risk. After the image has been pushed to the registry, you can verify that your image is now available for consumption with the following command to your registries API or via calling docker pull with your local registry tagged image.

 $ curl -X GET http://localhost:5000/v2/_catalog
{“repositories”:[“my-image”]}$ docker pull localhost:5000/ubuntu-local

 

Docker registry access control

Now, if you would like to restrict who can and can’t write to your docker registry, you can force users to log in to your registry before reading or writing to it. Users and their passwords to the registry in its most simple form are handled in a htpasswd format. You can generate the password file for your users by using the following command and container switching out your user and password as needed for your use case.

 $ mkdir auth
$ docker run
— rm \
— entrypoint htpasswd \
httpd:2 -Bbn testuser testpassword >> ./auth/htpasswd

 

With this password file generated for your users, you can mount the file into your Docker registry container and configure the REGISTRY_AUTH_HTPASSWD_PATH environment variable to point to this password file inside the container. You should also configure the REGISTRY_AUTH and REGISTRY_AUTH_HTPASSWD_REALM environment variables for basic auth like in the snippet below.

 $ docker run -d \
-p 5000:5000 \
— restart=always \
— name registry \
-v “$(pwd)”/auth:/auth \
-e “REGISTRY_AUTH=htpasswd” \
-e “REGISTRY_AUTH_HTPASSWD_REALM=Registry Realm” \
-e REGISTRY_AUTH_HTPASSWD_PATH=/auth/htpasswd \
registry:2

Your container should now require basic authentication with the credentials you created to push to it. Before you push or pull from your access controlled Docker registry, you should configure Docker for that registry by running the login command.

 $ docker login -u testuser -p testpassword localhost:5000

You can now push and pull like normal from your private docker registry.

Externally accessible Docker registry

So now that you have a local Docker registry, you will want to do a few more things if you plan to have it externally accessible. For private or public Docker registries that are externally accessible, you will want to run them over HTTPS to assure the person downloading your images they are coming from who you say you are. Whatever your use case, you will want to read the documentation from docker to understand your registry’s security and make it work for your setup and requirements.

https://docs.docker.com/registry/deploying/#run-an-externally-accessible-registry

Docker Registry TLS configuration

You should configure TLS for any externally accessible Docker registry to assure the consumer of your images that the image data they are received is coming from who they expected it to be. Setting this up is nice and easy with the Docker registry image, mount your .crt and .key file that you might generate with a tool like cerbot into the image and assign the REGISTRY_HTTP_TLS_CERTIFICATE and REGISTRY_HTTP_TLS_KEY environment variables to the paths of your domains certificate and keys inside the container.

 $ docker run -d \
— restart=always \
— name registry \
-v “$(pwd)”/certs:/certs \
-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

 

Once the image is up and running, you will be able to push and pull from the registry by using your domain for the registry host to push and pull images from.

 $ docker pull node
$ docker tag node myregistry.domain.com/dev-node
$ docker push myregistry.domain.com/dev-node
$ docker pull myregistry.domain.com/dev-node

 

This setup will not trigger the same HTTP error as earlier requiring the whitelisting of the registry host and is thus the recommended method to have your Docker registry serve its images to your users.

Reverse proxy the Docker Registry

If you already have a reverse proxy on your network doing your SSL termination, you can offload SSL to your reverse proxy and continue running your registry over HTTP. You can also have the authentication of users be performed in the reverse proxy if this is where you centralise SSO for your network. The docker registry docs are best referred to here with a complete NGINX config example to start from with all the necessary paths and redirects to serve the API properly and to handle the possibility of multiple docker versions connecting and implementing different versions of the docker api.

https://docs.docker.com/registry/recipes/nginx/

Final thoughts

Running a docker registry is very easy with the provided docker registry image from Docker co. Its flexibility with configuration makes it work for the setup you need. One important thing that we didn’t discuss here that you might want to consider is the built-in storage backends for common object storage services like S3, Azure, etc. You can read more about it here.

https://docs.docker.com/registry/storage-drivers/

This will work perfectly for scaling your setup for multiple users or if you plan to load balance the service and share their underlying storage.

Connect Further

  • If you are in the market for some homelab or home server products check our store's products.
  • You can also find some of our other blog posts.
  • Connect on our social media accounts over on Facebook and Instagram.

  

Leave a comment