Docker Registry featured image

Setting Up a Private Docker Registry on Ubuntu 18.04

Introduction

Docker Registry is a centralized application that handles the delivery and storage of various Docker container images. This collection of container images saves a lot of time for developers. Docker images provide the exact same environment as to how it was built using virtualization. Thus, building Docker images takes a good amount of time from developers. A good example of using a Docker registry would be when a developer can download an image from a registry with all his requirements. This in turn saves him a lot of time in preparing all these packages and prerequisites. Various continuous integration tools can also be used to update the Docker images throughout the development.

Docker Hub is a free public registry in which you can host your Docker images, though there may be cases when you want to keep your Docker images private. Therefore, it is recommended to use a private registry that allows you to protect your Docker images.

This tutorial will guide you through setting up and securing a private Docker Registry. You will be using Docker Compose to define the configurations required to run your Docker applications and an Nginx server for diverting traffic to a running Docker container. After completing this tutorial you will be able to host your Docker images in a private Docker registry and pull your custom Docker images from a remote machine.

Prerequisites

To carry on with the tutorial, you’ll need the following:

Step 1: Docker Registry – Installation and Configuration

You can use the Docker command-line tool for managing a few Docker containers, but once you move towards complex applications more and more Docker containers are required to run in parallel. Many web applications usually consist of a database like MySQL or MongoDB, a web server like Nginx or Apache Tomcat, and a scripting language.

Docker Compose is an excellent tool for managing multiple containers through one .yml file. You can easily set up configurations and communication information for the containers. Docker Compose also provides some commands for the user to effectively manage the application.

You will use Docker Compose to configure the Docker Registry since it is also an application that has multiple components. First, let’s set up a compose.yml file with a storage location for the private Docker Registry.

After that, create a Docker Registry directory on the machine meant to host the private Docker Registry, and create a data directory by following:

You can use any text editor to edit the docker-compose.yml:

The basic configurations for Docker Registry are as follows:

In the above configuration, the environment section sets up any environment variables to be included during the runtime of the container. Since we have set "REGISTRY_STORAGE_FILESYSTEM_ROOTDIRECTORY" environment variable, the Docker Registry application will take the directory for storage of data as /data.

However, because of the configuration in the volumes section – ./data:/data, the /data directory from the container will be mapped to your server’s /data directory. All the data that gets stored will be in the ~/docker-registry/data on the machine.

The ports section configuration essentially translates to the mapping of port 5000 from the server to port 5000 in the Docker container. This will forward the requests received on port 5000 of the server to the Docker registry application.

Verifying Installation

To verify the setup, start Docker Compose using:

In the output you will see that the Docker Registry image is getting downloaded. After some time an output similar to the following screenshot will show up:

docker_compose_up_output Docker Registry

The No HTTP secret provided warning will be resolved at a later point in the tutorial. The output listening on 5000 port determines that the application is running successfully.

After this step, Docker Compose will keep waiting for your input. Hit CTRL+C to stop the Docker registry container. Now you have a Docker Registry setup ready. In the next steps of the tutorial, you will set up an authentication mechanism to get rid of the security concerns.

Step 2: Using Nginx for Port Forwarding

After setting up HTTPS on the Docker registry server using Nginx, you can use port forwarding to port 5000. This will enable you to access the Docker registry at example.com.

When securing Nginx using How to Secure Nginx With Let’s Encrypt prerequisite, you already have your configurations in /etc/nginx/sites-available/example.com.

Next, open the file with any text editor:

Go to the location line, it will look similar as below:

Now that your registry is running on port 5000, Nginx will forward the traffic to the same port. Also, it will append the headers that are coming with the request which are required for additional information by the server. Replace the content of the location section with the following:

In the code snippet, the $http_user_agent section confirms whether the incoming request from a client is above version 1.5 and verifies that the Go application is not a user agent. More information about the header configuration can be found at Docker Registry Nginx Guide.

After modifying the configurations, you can restart Nginx to apply the changes:

Check whether Nginx is routing the traffic to port 5000 using:

Open any browser, and try to open the below url:

You should see an empty curly brace or an empty JSON object:

And the terminal should print similar output as shown below:

The last line depicts that a request was made /v2/, which was requested from the browser. The container received the request you made via port forwarding resulting in the response of an empty curly brace. Code 200 signifies that the request handling is successful. In the next step, let’s move towards security improvements.

Step 3: Authentication Setup

Now that Nginx is handling the requests properly, let’s secure your Docker registry with HTTP authentication for controlling the access to your registry. To do this create an authentication file using htpasswd and add users to it. This method is swift to set up and start.

First, install htpasswd package using:

Create a directory for storing authentication information and switch to that directory. $_ essentially translates to the last argument of the previous command:

Now, create the user as shown below, and change the username with the username you desire. You will be using BCrypt encryption, denote that by using the -B flag. The prompt will then ask for a password:

Now, let’s instruct Docker to use the file you created for authentication:

Add the below content to the docker-compose.yml for enabling Docker to authenticate users based on your configuration:

The authentication scheme htpasswd is specified using the REGISTRY_AUTH environment variable. Similarly, REGISTRY_AUTH_HTPASSWD_REALM and REGISTRY_AUTH_HTPASSWD_PATH refer to the htpasswd realm and path to authentication file.

To verify that the authentication is working you can try running the registry and checking if it prompts for username and password:

Open any browser and try to open https://example.com/v2. You should get a prompt for username and password. After a successful authentication you will see an empty curly brace again. This confirms your authentication setup is successful.

Step 4: Setting up Docker Registry as a Service

To make sure that the registry starts whenever the system starts, you have to make some changes in docker-compose.yml. Also, you can set the registry to restart, in case of any system failures. Use any text editor to modify the docker-compose.yml and add the below content:

The final docker-compose.yml file should look similar to the screenshot below:

docker_compose_yaml

Start the Docker registry in the background using the -d flag. This will keep the process running even after you exit the session:

Now your registry is secure and running in the background. You will start working on file uploads in the next step.

Step 5: Changing Nginx File Upload Size

Nginx holds a limit of 1MB on file uploads. Before doing large-size image uploads you may have to increase this limit in Nginx. Even though Docker images are split into separate layers by Docker, they sometimes go over 1GB. To increase the limit make the following configuration changes in Nginx:

Afterward, restart the Nginx service for the configuration changes to take effect:

Step 6: Publishing Images to Private Docker Registry

Your private Docker registry is ready to host the images. For the sake of this tutorial, let’s create a simple Ubuntu image. You will download this image from the publically available Docker Hub. You will use this Ubuntu image to check pushing and pulling from your private Docker registry.

Using the client machine, create an Ubuntu image. The -i and -t flags denote interactive mode and provide you shell access into the container:

After finishing the downloading you will land up inside the Ubuntu container, as you can see below:

Ubuntu Image Download

Create any file, in this example 'cloudsigma'. In the next step you will be able to verify the existence of this file, in turn confirming publishing is successful:

To exit the running container use:

The below command will create a new image, consisting of the ubuntu base image and an additional file 'cloudsigma'. Commit the changes:

Now this image exists locally in the machine. You can now push the image to the Docker registry you have created. Start with logging in to your registry:

Provide the username and password as you have set in the previous steps. Then, tag the new image with the location of the private registry so as to push the image in the registry:

Push the image to the registry using:

You should get a similar output as below:

So far you have confirmed whether your registry allows authenticated users to push the images to the registry. In the next step, you will verify if you can pull the images from the private Docker registry.

Step 7: Pulling Images From the Docker Registry

Log in to the machine hosting the registry server so as to check if you can pull the images from the client-server.

Log in to the registry using a previously set username and password:

Now check if you can pull the image which was created in the last step:

You will return to your prompt once Docker finishes downloading the image. Try running the downloaded image and you will see the 'cloudsigma' file which you created in the previous step:

List and verify the files:

You have successfully set up a secure Docker registry to host your custom Docker images.

Conclusion

In this tutorial, you have set up your private Docker Registry and published a Docker image as well. The next step will be to explore various CI tools so that you can automate this process of pushing the images to a private registry. This can be of great help for having the same behavior of the code in development or in a production environment.

You can also check out our other Docker tutorials to get more information about what you can do with Docker:

About Pranay Kapgate

Software Engineer | Open Source Software aficionado