Private Docker Registry

Private Docker Registry




Docker Inc has open sourced their registry for us to run on premise. It comes without a nice shiny GUI and will require API calls to do common things like listing the images in the registry or delete an image from it. It comes with several caveats as well and they are very clear about it. It is up to you to decide if you want to go cloud (Docker Hub or Quay for example), install the Docker Trusted Registry (Docker Hub on premise!) or go the DIY route.

DIY? Well, down the rabbit hole we go! We’ll concentrate our efforts on the registry v2 as v1 is deprecated. You can work in a non secure mode, i.e. plain HTTP, or (strong hint), in a secured mode (SSL) using a certificate (like you would to secure your web server). Authentication is part of the bundle as well. We’ll try to make a simple, yet secure registry of our own.

Let’s start with the non secure setup. We’ll need 2 VMs (to make our push/pull requests a bit more realistic). It’ll work just fine on a single VM, but I like to be closer to reality if possible and spinning up another VM is simple enough. One VM will run the registry. The other VM will simulate a user using our registry. In order to set up, we’ll use Vagrant to create the 2 CentOS 7 based VMs (you will need to do commands as root) and docker machine to quickly install and secure docker.

Here is our Vagrant file

vagrant up and install docker using docker machine

reg01 will run the registry and reg02 will be used to interact with it.

On to the registry on reg01: docker pull registry:2 (don’t forget the tag)

We’ll skip using localhost (no security concerns) and go straight for the unsecure setup. If you have a DNS, reg01 should be known as or whatever you choose as domain name. As we won’t create a DNS subnet to test stuff on throw away VMs, we’ll go with the classic /etc/hosts entry. On each VM, we’ll enter the following in /etc/hosts (as root user)

Now that our registry has a name, we’ll restart each of the docker daemons to instruct them about an unsecure registry we want to use. On both VMs, edit /etc/systemd/system/docker.service and add --insecure-registry at the end of the ExecStart line. Restart the docker service.

Last, we’ll create a directory we’ll use as a volume to store the registry’s data. You can decide what storage strategy you want to use later on: filesystem, S3, Azure, … For the time being, we use filesystem (default). /reg on reg01 will do just fine. We’re all set.

On reg01, run the registry with

Check time!

LGTM! Our registry should be empty, and oh surprise, it is (response is an empty array)

On reg02, pull the ubuntu image or whatever image you prefer, tag it and push it to your private registry. Delete the tag and the ubuntu image. Now pull the image again, but this time, from your private registry.

If you’re curious, your data is in /reg

And voilà!

The problem is: anyone with access to the registry can use it. It’s all HTTP. And you will have to configure each docker daemon to use the insecure registry.

During our evaluation phase, we can secure it with a self signed certificate. A proper certificate should be acquired if you decide to commit to one or more internal registries.

On reg01, we will generated a self signed certificate (as previously linked to) in the /root directory

In /root

Copy the certificate to the right place on both VMs (renaming domain.crt to ca.crt in the process). You should end up on both VMs with

Remove the --insecure-registry from the docker service, reload the systemd daemon, restart docker on both VMs. Yes, you have to do this on ALL docker daemons you will be using! Remember the caveats I talked about earlier?

If you haven’t already done it, stop and remove the running registry container on reg01

Now start the registry again, but this time, with the certificate and key we created earlier.

Check …

My first try at a pull resulted in an error, subsequent push/pull worked without an issue though. Doh?!

Our catalog should have one more image in it


Now that we have secured our registry, we can move on to the authentication part.

Before we do, we’ll trust the certificate on each VM at the OS level. In our last curl command we used the -k flag to allow the connection with our self signed certificate. Without it curl tells you the certificate cannot be verified, blah blah … This will come back and bite us, so let’s get rid of it.

On both VMs

Stop and restart the docker service on each VMs. (Yes, you’ll have to do this everywhere your docker daemon is supposed to have access to the registry). BTW, if you issue a curl command without the -k flag now, it’ll work just fine.

Next, authentication. Basic auth is built in and uses the Apache htpasswd tool. It’s very similar to your classic web server basic authentication (only bcrypt encryption is allowed here).

We’ll create a fake user/password. Use whatever you want, I’m going to go with bob/bob2015 because I’m very creative, … well …

Stop and remove the registry container if it’s still running, we’ll restart it with a few more environment variables to take authentication into account.

We can verify the registry is not open to all anymore

LGTM! Time to log in

Done! New users can be added any time but you’ll need to restart the registry (the caveats, …, you know)

All good but that looooong command line to start the registry needs to go. Docker-compose to the rescue.

On reg01

Here’s our docker-compose.yml file

Starting up the registry is a lot simpler now (you can skipp the -p reg01 if you prefer).

Interacting with the registry is done via the APIs. We’ve already requested the list of repositories a few times. The complete API documentation is here (Implementation incomplete). At the time of this writing, there’s no web UI supporting registry v2. The two main Web UIs supporting registry V1 are on the fence, but not there yet.

You can dig deeper in the registry’s configurations to start customising it.

Tip: if 443 is not yet taken on your docker host running the registry, change your docker-compose.yml file to expose 443:5000 and you’ll be able to tag you images without the port information.

Word of caution: deleting images from the registry is not supported yet (20150818): #422. If you build and push a lot of images to your private registry (auto building on your CI platform for example), this could become and issue. The “work around” for now is to monitor used/free space and regularly schedule a complete wipe off of the data or plan ahead (calculate your average usage and allocate enough storage capacity to last a few months).

Nothing’s holding you back from creating your own docker registry now.

Next, we’ll see how to use apache httpd web server with basic authentication as a reverse proxy to our registry.

Olivier Robert
No Comments

Post a Comment