avatarAaron Berry

Summary

This article provides a guide on how to set up a local or externally accessible Docker registry for hosting Docker images, including steps for running a minimal Docker registry, configuring access control, and setting up TLS for external access.

Abstract

The article begins by explaining the benefits of running a local or externally accessible Docker registry for hosting Docker images. It then provides step-by-step instructions for setting up a minimal Docker registry using the provider Docker registry image from Docker co. The article also covers how to configure access control using basic authentication and htpasswd, as well as how to set up TLS for external access to the registry. The article concludes by recommending the use of built-in storage backends for common object storage services like S3 and Azure for scaling the setup for multiple users or load balancing.

Opinions

The author of the article expresses the opinion that running a Docker registry is a key part of DevOps infrastructure and can be easily set up using the provider Docker registry image from Docker co. The author also emphasizes the importance of configuring access control and TLS for external access to the registry to ensure security and trustworthiness. The author recommends the use of built-in storage backends for common object storage services for scaling the setup for multiple users or load balancing.

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 pull ubuntu
$ docker image tag ubuntu localhost:5000/ubuntu-local
$ docker push localhost:5000/ubuntu-local

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-local
Using 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.

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 runrm \
     — 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 thinking of getting a Medium subscription, you can help me out by using my referral link.
  • Check out my other writing here on Medium and if you want to keep up to date subscribe via Email.
  • Connect with me on LinkedIn if you want to chat, if you want to hire me I’m on Codementor.
Docker
Programming
Software
Software Development
Containers
Recommended from ReadMedium
avatarAI Rabbit
Goodbye Obsidian

7 min read