A registry is a stateless, highly scalable, server-side application that stores and lets you distribute Docker images. At a high level, a registry is a collection of different repositories which contain our images. These images have different tags. We generally use a private registry when we want to -

  • keep control of the distribution of images
  • control where the images are stored
  • integrate image storage and distribution tightly into your in-house development workflow

Prerequisites

I am using Ubuntu 18.04, so all commands will be related to this system.

Make sure that you have met the following prerequisites before continuing with this tutorial:

  1. You need to have Docker and Docker Compose installed on your host
  2. You need to have an installed nginx.
  3. Examples assume you have a domain: rcherara.com, and that you want to start registry on: registry.rcherara.com

These article  assume the following:

  • Your registry URL is https://registry.rcherara.com/.
  • Your DNS, routing, and firewall settings allow access to the registry’s host on port 443.
  • You have already obtained a certificate from a certificate authority (CA).

The registry supports using Let’s Encrypt to automatically obtain a browser-trusted certificate. For more information on Let’s Encrypt, see https://letsencrypt.org/how-it-works/ or https://rcherara.ca/secure-nginx-with-lets-encrypt/ and the relevant section of the registry configuration.

To get the SSL Certificate, we can use openssl to create Self-Signed SSL or to use Let's Encrypt SSL

Create a self-signed certificate with OpenSSL

Create a Certificate Authority private key :

$ openssl req -new -newkey rsa:1024 -nodes -out ca.csr -keyout ca.key

Capture-d--cran-2020-01-30---05.35.59

For your country code use : https://www.digicert.com/ssl-certificate-country-codes.htm

Create your CA self-signed certificate:

$ openssl x509 -trustout -signkey ca.key -days 365 -req -in ca.csr -out ca.pem

Capture-d--cran-2020-01-30---05.37.55

$ openssl x509 -trustout -signkey ca.key -days 365 -req -in ca.csr -out ca.pem

Capture-d--cran-2020-01-30---05.41.35

Issue a client certificate by first generating the key, then request (or use one provided by external system) then sign the certificate using private key of your CA:

$ openssl genrsa -out client.key 1024
$ openssl req -new -key client.key -out client.csr
$ openssl ca -in client.csr -out client.cer

Capture-d--cran-2020-01-30---05.45.08

Copy SSL certificate files of your domain to the 'ssl' directory.

$ sudo cp /home/rcherara/ca.pem  /etc/nginx/ssl/fullchain.pem
$ sudo cp /home/rcherara/ca.key  /etc/nginx/ssl/privkey.pem

Capture-d--cran-2020-01-30---13.53.05

Let's Encrypt SSL

You can  secure your Nginx with Let's Encrypt SSL as explained in my tutorial  here :

Secure Nginx with Let’s Encrypt
Let’s Encrypt is a free, automated, and open certificate authority developed by the Internet Security Research Group (ISRG) that provides free SSL certificates. Prerequisites Before you proceed, make sure that you have met the following prerequisites: * You have a domain name pointing to your p…
Secure Ngnix with Let's Encrypt SSL

Deploy your registry using a Docker-Compose file

$ mkdir docker-volumes
$ mkdir docker-volumes/registry/
$ mkdir docker-volumes/registry/registry
$ mkdir docker-volumes/registry/auth

Capture-d--cran-2020-01-30---01.37.40

Use the following example docker-compose.yml as a template.

Create  docker-compose.yml file:

version: "3"
services:
  registry:
    restart: always
    image: 'registry:2'
    ports:
      - "5000:5000"
    environment:
      REGISTRY_AUTH: htpasswd
      REGISTRY_AUTH_HTPASSWD_PATH: /auth/htpasswd
      REGISTRY_AUTH_HTPASSWD_REALM: Registry Realm
    volumes:
      - /home/rcherara/docker-volumes/registry/registry:/var/lib/registry
      - /home/rcherara/docker-volumes/registry/auth:/auth

In my case I have an certificate and I use this configuration

registry:
  restart: always
  image: registry:2
  ports:
    - 5000:5000
  environment:
    REGISTRY_HTTP_TLS_CERTIFICATE: /etc/nginx/ssl/fullchain.pem
    REGISTRY_HTTP_TLS_KEY: /etc/nginx/ssl/privkey.pem
    REGISTRY_AUTH: htpasswd
    REGISTRY_AUTH_HTPASSWD_PATH: /auth/htpasswd
    REGISTRY_AUTH_HTPASSWD_REALM: Registry Realm
  volumes:
    - /home/rcherara:/certs
    - /home/rcherara/docker-volumes/registry/registry:/var/lib/registry
    - /home/rcherara/docker-volumes/registry/auth:/auth

Now we can start  your registry by issuing the following command in the directory containing the docker-compose.yml file:

$ docker-compose up -d

Capture-d--cran-2020-01-30---01.48.40

$ docker run --entrypoint htpasswd registry:2 -Bbn testuser testpassword > ./docker-volumes/registry/auth/htpasswd

Capture-d--cran-2020-01-30---01.47.55

 $ docker login localhost:5000

Capture-d--cran-2020-01-30---02.55.36

Configure the  domain registry.rcherara.com

$ sudo touch /etc/nginx/sites-available/registry.rcherara.com.conf
$ sudo vi /etc/nginx/sites-available/registry.rcherara.com.conf

Capture-d--cran-2020-01-30---01.49.44

Capture-d--cran-2020-01-31---23.15.16-1

Paste the following configuration.

upstream docker-registry {
server registry:5000;
}

server {
listen 80;
server_name registry.rcherara.com;
return 301 https://registry.rcherara.com$request_uri;
}

server {
listen 443 ssl http2;
server_name registry.rcherara.com;

ssl_certificate /etc/nginx/ssl/fullchain.pem;
ssl_certificate_key /etc/nginx/ssl/privkey.pem;

# Log files for Debug
error_log  /var/log/nginx/error.log;
access_log /var/log/nginx/access.log;

location / {
    # Do not allow connections from docker 1.5 and earlier
    # docker pre-1.6.0 did not properly set the user agent on ping, catch "Go *" user agents
    if ($http_user_agent ~ "^(docker\/1\.(3|4|5(?!\.[0-9]-dev))|Go ).*$" )  {
        return 404;
    }

    proxy_pass                          http://docker-registry;
    proxy_set_header  Host              $http_host;
    proxy_set_header  X-Real-IP         $remote_addr;
    proxy_set_header  X-Forwarded-For   $proxy_add_x_forwarded_for;
    proxy_set_header  X-Forwarded-Proto $scheme;
    proxy_read_timeout                  900;
}

}

Save and close.

Validate the Configuration and Start Nginx

Validate the configuration file has no syntax errors. This is good practice, as a simple syntax error will prevent the Nginx service from starting, preventing visitors from accessing your site.

$ sudo nginx -t -c /etc/nginx/sites-available/registry.rcherara.com.conf

Capture-d--cran-2020-01-30---02.11.35

Provided no errors were found, enable the site. To do so we’ll need to create a symbolic link of the site configuration file in the sites-enabled directory.

$ sudo ln -s /etc/nginx/sites-available/registry.rcherara.com.conf /etc/nginx/sites-enabled/registry.rcherara.com.conf

Start or restart the Nginx service.

$ sudo systemctl start nginx

If Nginx is already running, reload all configuration files without stopping the service.

$ sudo systemctl reload nginx

Verify that Nginx is running.

$ sudo systemctl status nginx

Also restart nginx so it loads new config for registry.rcherara.com.conf

$ sudo service nginx restart

In order to check that we configured everything correctly, go to console on your local machine, which you would use to build images (your laptop probably), and try to login:

$ docker login registry.rcherara.com

Capture-d--cran-2020-01-30---13.55.50

username : testuser 
password : testpassword

Docker clients can now pull from and push to your registry using its external address. The following commands demonstrate this:

$ docker pull ubuntu:16.04
$ docker tag ubuntu:16.04 registry.rcherara.com/my-ubuntu
$ docker push registry.rcherara.com/my-ubuntu
$ docker pull registry.rcherara.com/my-ubuntu

Capture-d--cran-2020-01-30---14.06.59

http://registry.rcherara.com:5000/v2/_catalog/

https://registry.rcherara.com/v2/_catalog/

Because we  use BasicAuth to authenticate to registry we need to setup SSL so that our login/password is not taken by man in the middle attack.
Currently my nginx config  support SSL which is required to make our registry accessible from outside.

Enjoy!