Deploying a private, secured Docker Registry within 15 minutes

Written on April 08, 2016

After using Docker in development, you might want to put your application into production. Depending on your need, you might not want to push your private Docker images for your application to the Docker Hub, but have a private registry instead.

Docker has been providing the private registry on GitHub for a long time and it works pretty well. The downside is that it doesn't provide security features like RBAC.

That's where 3rd party solutions kick in.

We've been evaluating several solutions like AWS EC2 Container Registry (ECR) and others.
In the end, we're now running on Harbor, an Open Source registry server from VMware build around the aforementioned Docker registry.

Harbor is being developed in Golang and provides these key features:

  • Access Control: RBAC (Role Based Access Control) is provided. User management can be integrated with existing enterprise identity services like AD/LDAP.
  • Audit: All access to the registry are logged and can be used for audit purpose.
  • GUI: User friendly single-pane-of-glass management console.
  • Project based approach to separate images and access to them

First, here are some screenshots from harbor, starting with the admin dashboard:

Beside user self registration (can be turned off), the Admin can invite users:

Admins can create projects:

You can see all images for a particular project:

The Harbor User Guide shows some more screenshots.

The goal of this post is to get a Harbor instance running on DigitalOcean with HTTPS enabled using Docker Machine.

I'm assuming that you're familiar with Docker Machine basics and have it up and running. Furthermore, you'll need to have the Docker engine and Docker Compose installed which are required by Harbor for deployment.
And because we want to enable HTTPS, you should have grabbed a certificate from DigiCert or somewhere else.

First, clone the latest Harbor version from GitHub:

$ git clone [email protected]:vmware/harbor.git

Inside the Deploy folder there are several configuration options within the harbor.cfg file.

There are two options you have to configure at a minimum:

hostname =
ui_url_protocol = https

Inside the Deploy/config/nginx folder there are two nginx configuration files named nginx.conf and nginx.https.conf.

The file being used by Harbor is nginx.conf. Because we want to use HTTPS, we need to get Harbor use nginx.https.conf:

$ mv nginx.conf nginx.conf.bak
$ cp nginx.https.conf nginx.conf

Then we have to modify the new nginx.conf and replace the two occurrences of with our own Harbor URI, e.g.

Regarding the certificate, there a two options: Use the cert filename from DigiCert (in my case) and the server.key file and modify the nginx.conf accordingly or rename the certificate to harbordomain.crt.

Either case, you have to copy the cert file and the key file from your Certificate Signing Request to the Deploy/config/nginx/cert folder.

The SSL settings within the nginx.conf should look like this:

ssl_certificate /etc/nginx/cert/harbor_yourdomain_com.pem;
ssl_certificate_key /etc/nginx/cert/harbor_yourdomain_com.key;

Next, from the bash, run the following command within the Deploy folder:

$ ./prepare

This will copy the settings to their appropriate destinations.

With that done, lets create our Docker Machine instance for deployment. To create a DigitalOcean Droplet using Docker Machine, we need an API access token which can be created at the DigitalOcean Website (Azure or AWS are similar):

Copy your token and keep it safe, you won't see it again at the DigitalOcean website.

Now, back to the bash, we can create a Droplet using Docker Machine - make sure it has at least 2GB of RAM:

$ docker-machine create --driver digitalocean --digitalocean-access-token <yourtokenfromabove> --digitalocean-size 2GB

Docker Machine provides more options for the --driver like the region. Just read the Docker Machine Driver Documentation for more.

When the Droplet is up and running (this should take only a few seconds), activate that particular Docker Machine instance:

$ eval $(docker-machine env

Because we want to spin up the containers required by Harbor using Docker Compose, we have to copy the settings from the Deploy/config directory first to our Docker Machine instance.

First, get the absolute path to the Deploy directory (cd first into it):

$ echo $PWD

The result should be something like this:


Now we create the exact same absolute folder structure (including the config subfolder) inside the Docker Machine instance and copy the contents of our local Deploy/config folder into it:

$ docker-machine ssh harbor.ỳ 'mkdir -p /home/<yourusername>/src/harbor/Deploy/config
$ docker-machine scp -r ./config$PWD

Next, build the container images using Docker Compose (inside the Deploy folder):

$ docker-compose build

And as a last step, we're spinning up our containers:

$ docker-compose up -d

Now you should be able to browse

And of course, you can start pushing and pulling Docker images to and from your own registry now!

After creating a new project (I'm using test here) and user as an Admin inside Harbor, you can push new images to Harbor like this:

$ docker tag customerservice:1.0.0
$ docker login -u <username> -p <password> -e <email>
$ docker push

And we're done!

As a side note: If you want to disable user self registration, apply this setting in harbor.cfg:

self_registration = off

P.S.: This post mostly is a combination of the Harbor Installation Guide and the Deploying Harbor using Docker Machine Guide (the latter I contributed to the Harbor project, so I didn't just copy existing stuff).