Create a Private Docker Registry
Tags: docker, linux, ubuntu
Published: 2021-06-06 20:34:46

Dockerized applications and automated pipelines mean that you will eventually need a docker registry sooner or later.

#What is a Docker Registry?

It is essentially a place where you store Docker images organized in repositories. You can push images to the remote Docker registry and pull images where you want them.

#Docker Hub

Nifty service that Docker.com runs is Docker hub or a Docker Registry that has many things automated so you don't have to bother with configuring it on your own server (which we will get to in a bit).

Free tier is also fairly generous at Docker hub because it provides you with unlimited public repositories and one private repository. More private repositories are available in paid tiers and you can find pricing info here: [Docker Pricing](https://www.docker.com/pricing)

#Create your own private registry

If you want to house your Docker images on your own server, then you have to create a private registry or how the Docker documentation states it, deploy a registry server.

#Prerequisites

Before deploying a private registry, you will need to have several prerequisites checked:
- Server running Ubuntu (preferably latest Ubuntu 20.04) that is properly configured. You can read about it in the post here: [Configure New Ubuntu Server](https://dev.to/semirteskeredzic/configure-new-ubuntu-20-04-server-4p4b)
- Docker & Docker-compose properly installed on the server that will host the Docker registry. You can read about it here: [Install Docker & Docker-compose on Ubuntu server](https://dev.to/semirteskeredzic/docker-docker-compose-on-ubuntu-20-04-server-4h3k)
- Properly installed Nginx. You can read about it here: [Install Nginx on Ubuntu server](https://dev.to/semirteskeredzic/install-nginx-on-ubuntu-20-04-server-12ni)
- Domain name that resolves to your host server (where you will host registries)
- SSL Secured Nginx on your host server

#Installing & Configuring

Since we have to run registry from a docker image there are two ways we will go through here,
1. Quick - running with `docker` command from the CLI
2. Using docker-compose - running with the `yml` file using `docker-compose`

Before going through each one, go on and create a few directories to keep the things organized:
```
$ mkdir docker-registry
$ cd ~/docker-registry
$ mkdir data
```

##Quick

While in our `docker-registry` folder, we can run docker registry with just one line of code:
```
$ docker run -d -p 5000:5000 --restart=always --name registry registry:2
```
This will run our registry from the image `registry` in background mode with the usage of the port 5000.
This is a great first step just to see it working. However it is not secure enough or configured enough for production-based environments.
Go on and stop the running container by running this command:
```
$ docker container stop registry
```
Proceed with removing the container alltogether:
```
$ docker container rm -v registry
```
If we want to store data to our host server filesystem instead of relying on the data inside the docker volume, we could use this command:
```
docker run -d \
  -p 5000:5000 \
  --restart=always \
  --name registry \
  -v ~/docker-registry/data:/var/lib/registry \
  registry:2
```
*Note: when writing a docker command in multiple lines just use backslash `\` at the end of the line and press enter.*

##Using docker-compose

You can write entire configuration in one `yml` file and run it with docker-compose, this way you see the configuration more clearly and you are able to make modifications and see previous configurations.
While in your `docker-registry` directory, create and enter edit mode using nano:
```
$ nano docker-compose.yml
```
You can now enter following code to the file:
```
version: '3'

services:
  registry:
    image: registry:2
    restart: always
    ports:
    - "5000:5000"
    environment:
      REGISTRY_STORAGE_FILESYSTEM_ROOTDIRECTORY: /data
    volumes:
      - ./data:/data
```
You can already see that we are using same image, utilizing same port and using volume location `~/data` in our filesystem.
You can exit and save using `CTRL+X` then `Y` and then `ENTER`
Run the docker-compose with:
```
$ docker-compose up
```
Now your docker registry is up and running.

#Configure HTTP Authentication

We can put HTTP Authentication with the Nginx using username and password so the access to our server hosting registries is secured with those credentials.
First update local packages:
```
$ sudo apt update
```
Then install a package we will use:
```
$ sudo apt install apache2-utils -y
```
We will store our credentials in separate folder so go create one and enter it:
```
$ mkdir ~/docker-registry/auth
$ cd ~/docker-registry/auth
```
We will now enter following command and you replace `username` with the username you want it to be:
```
$ htpasswd -Bc registry.password username
```
You will be prompted for password so enter it as required. If we used a docker-compose file, we need to update it to include credentials. Open docker-compose file using `nano`:
```
$ nano ~/docker-registry/docker-compose.yml
```
Now alter existing docker-compose using following template:
```
version: '3'

services:
  registry:
    image: registry:2
    restart: always
    ports:
    - "5000:5000"
    environment:
      REGISTRY_AUTH: htpasswd
      REGISTRY_AUTH_HTPASSWD_REALM: Registry
      REGISTRY_AUTH_HTPASSWD_PATH: /auth/registry.password
      REGISTRY_STORAGE_FILESYSTEM_ROOTDIRECTORY: /data
    volumes:
      - ./auth:/auth
      - ./data:/data
```
Run your docker-compose:
```
$ docker-compose up
```
If you want to use inline CLI `docker` command use this:
```
docker run -d \
  -p 5000:5000 \
  --restart=always \
  --name registry \
  -e REGISTRY_AUTH=htpasswd \
  -e REGISTRY_AUTH_HTPASSWD_REALM=Registry \
  -e REGISTRY_AUTH_HTPASSWD_PATH=/auth/registry.password \
  -v ~/docker-registry/data:/var/lib/registry \
  registry:2
```

#Secure your host server with SSL

In order for docker-registry to function properly you must have secured HTTPS connection and that requires that you install a certificate provided by Certificate Authority. There is a free SSL certificate provided by Let's Encrypt and you can do this with the help of `certbot`
Find the guide here: [Certbot Ubuntu installation](https://certbot.eff.org/lets-encrypt/ubuntubionic-nginx)

Remember that you need to have a domain pointing to your host server IP address before being able to activate Let's encrypt.

#Check firewall

Check the firewall status with the following command:
```
$ sudo ufw status
```
And make sure to allow all Nginx that includes HTTPS:
```
$ sudo ufw allow 'Nginx Full'
```

#Nginx file Upload size

File upload size is set quite low for nginx when you freshly install and configure it. You need to increase that amount so you can push larger images to your docker registry. Open Nginx configuration:
```
$ sudo nano /etc/nginx/nginx.conf
```
Now edit the line that says `client_max_body_size` in the `http` section and set the value to `8000m` which sets the maximum size to 8GB. Save changes and exit configuration.
After making any changes in Nginx configuration be sure to restart the Nginx:
```
$ sudo systemctl restart nginx
```

Congratulations! You now have a private docker registry that is password protected and HTTPS secured. You can push your own images there and pull it wherever you need them. Use `docker` commands to login to your docker-registry just as you would with `Docker Hub`, and use push and pull commands in the same way.

Thank you for reading.