---
title: Running Secured Docker Registry 2.0
description: The new Docker Registry 2.0 was released on April 16th, 2015. It was completely rewritten in Go with added support for the new Docker Registry HTTP API V2 (thus only working with Docker 1.6+), promising to provide faster and more secure distribution of images.
image: http://cdn2.hubspot.net/hubfs/2668666/All-InOne-2016/Image/bg-img.jpg
---

Check out our **[Cloud Native Services](https://www.container-solutions.com/services) **and** **book a call with one of our experts today! 

[![Container Solutions](https://blog.container-solutions.com/hubfs/CS_blog/logo-main.svg "Container Solutions")](http://container-solutions.com)

- share:
- [**](https://www.facebook.com/sharer/sharer.php?u=https%3A%2F%2Fblog.container-solutions.com%2Frunning-secured-docker-registry-2-0)
- [**](https://www.twitter.com/share?url=https%3A%2F%2Fblog.container-solutions.com%2Frunning-secured-docker-registry-2-0)
- [**](http://www.linkedin.com/shareArticle?mini=true&url=https://blog.container-solutions.com/running-secured-docker-registry-2-0)
- [**](https://blog.container-solutions.com/running-secured-docker-registry-2-0#)

[![](http://cdn2.hubspot.net/hubfs/2668666/All-InOne-2016/Image/bg-img.jpg) ](https://blog.container-solutions.com/running-secured-docker-registry-2-0)

# Running Secured Docker Registry 2.0

[Jaroslav Holub](https://blog.container-solutions.com/author/jaroslav-holub)

 April 28, 2015

 6 minutes Read

The new Docker Registry 2.0 was [released](http://blog.docker.com/2015/04/faster-and-better-image-distribution-with-registry-2-0-and-engine-1-6/) on April 16th, 2015. It was completely rewritten in Go with added support for the new Docker Registry HTTP API V2 (thus only working with Docker 1.6+), promising to provide faster and more secure distribution of images. If you work with Docker and for some reason decided not to use the public Docker Hub, a private Docker Registry is an essential part of your architecture. But even if you don't have private images, you will likely need to use your own registry in production/testing for efficiency.

The default installation, however, runs without encryption and authentication. I was wondering what’s involved in securing it. There is an official [tutorial](https://github.com/docker/distribution/blob/master/docs/deploying.md#configure-tls-on-a-registry-server) on how to configure TLS on a registry server. TLS/SSL is absolutely necessary for any secure setup, but I also wanted to enable an authentication mechanism. The [Configuration Reference](https://docs.docker.com/registry/configuration) document describes two authentication options supported by Docker Registry itself: so-called *silly* and *token* solutions. The *silly* one is apparently only useful for very limited development use-cases. The *token* solution seems to be more serious, but because of the lack of documentation (at the time of writing), I decided to find an alternative approach to secure it. In this article I’m going to show you how to set up the Docker Registry 2.0 with username/password authentication and SSL using the official [Docker Registry image](https://registry.hub.docker.com/u/library/registry/) and a custom configured [nginx ](http://nginx.org/en/)as a proxy server.

Note:

Docker daemon considers any private registry secure only if it uses transport layer security, a copy of its CA certificate is placed on the Docker host at `/etc/docker/certs.d/<ip>:<port>/ca.crt` and Docker is able to verify the certificate validity. In other cases (including usage of self-signed certificates), you need to run the Docker daemon with `--insecure-registry` flag.

First, run the registry:

```
  
docker run -v $(pwd)/data:/tmp/registry-dev --name docker-registry registry:2.0
```

I gave it a name, so we can refer to it from the nginx configuration. Because it’s nice to have stateless containers, I attached a volume where registry stores its data.

Because we want our registry to be accessible only by people who know the password, let’s create a `.htpasswd` file. You can do it like this: `htpasswd -c .htpasswd exampleuser`

The last bits are writing the nginx configuration and finally running the proxy. The nginx config file might look like this:

```

server {
   listen 443 ssl;
   server_name localhost;
 
   add_header Docker-Distribution-Api-Version registry/2.0 always;
 
   ssl on;
   ssl_certificate /etc/nginx/ssl/docker-registry.crt;
   ssl_certificate_key /etc/nginx/ssl/docker-registry.key;
 
   proxy_set_header Host $host;
   proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
   proxy_set_header X-Real-IP $remote_addr;
   proxy_set_header X-Forwarded-Proto $scheme;
   proxy_set_header X-Original-URI $request_uri;
   proxy_set_header Docker-Distribution-Api-Version registry/2.0;
 
   location / {
     auth_basic "Restricted";
     auth_basic_user_file /etc/nginx/.htpasswd;
     proxy_pass http://docker-registry:5000;
   }
}
	
```

We need to use `always` parameter of `add_header` directive, introduced only recently in [nginx 1.7.5](http://nginx.org/en/CHANGES). The reason is that nginx doesn't send headers with auth_basic requests by default. Previously, you'd have to use nginx-extras package that includes [HttpHeadersMore](http://wiki.nginx.org/HttpHeadersMoreModule) plugin and use that.

Looking at the rest of the nginx configuration; it’s SSL only proxy, so we need to attach the certificates to the container to `/etc/nginx/ssl/docker-registry.crt` and `/etc/nginx/ssl/docker-registry.key` respectively. There is `auth_basic` enabled, for which we need to attach `/etc/nginx/.htpasswd` file, which we just generated. We use name of the already running registry:2.0 container in the `proxy_pass` directive, together with port 5000, exposed from the container by default.

Now we run the proxy container. You can use [Docker Registry Proxy](https://registry.hub.docker.com/u/containersol/docker-registry-proxy/) image, that we created for your convenience. It's derived from nginx:1.7 and applies the configuration described above. You only need to provide it with `REGISTRY_HOST` and `REGISTRY_PORT` variables pointing to the registry container and `SERVER_NAME` variable that stands for the nginx `server_name`  directive. A directory with SSL certificates must be mounted to the container as well as our .htpasswd file. Expose HTTPS port 443 to the host and add a link to our already running `docker-registry` container:

```
  
docker run -p 443:443   \
(out)    -e REGISTRY_HOST="docker-registry"  \
(out)    -e REGISTRY_PORT="5000"   \
(out)    -e SERVER_NAME="localhost"  \
(out)    --link docker-registry:docker-registry  \
(out)    -v $(pwd)/.htpasswd:/etc/nginx/.htpasswd:ro  \
(out)    -v $(pwd)/certs:/etc/nginx/ssl:ro  \
(out)    containersol/docker-registry-proxy
```

Let’s verify that our Registry works properly.

```
  
docker login -u  -p  -e  localhost:443
docker pull hello-world
docker tag hello-world:latest localhost:443/hello-secure-world:latest
docker push localhost:443/hello-secure-world:latest
```

You should see a successful push to your private Docker Registry, secured with SSL and basic http authentication. Although this setup seems to work, use it at your own risk and please let us know if you spot any issues!

[### Friction

](https://blog.container-solutions.com/friction)

[![prev-arrow](https://cdn2.hubspot.net/hubfs/3842749/Wow%202019/Images/left-arrow.png) Previous article](https://blog.container-solutions.com/friction)

[ Next article ![next-arrow](https://cdn2.hubspot.net/hubfs/3842749/Wow%202019/Images/right-arrow.png) ](https://blog.container-solutions.com/things-we-learned-proxy-problems-in-docker-1-5)

[

### Things we learned - Proxy problems in Docker 1.5

](https://blog.container-solutions.com/things-we-learned-proxy-problems-in-docker-1-5)

Comments

Leave your Comment

![cs-logo-white](https://blog.container-solutions.com/hs-fs/hubfs/cs-logo-white.png?width=150&height=61&name=cs-logo-white.png "cs-logo-white")

#### **Talk to sales**

[info@container-solutions.com](mailto:info@container-Solutions.com)

#### Stay In Touch

- [**](https://www.linkedin.com/company/container-solutions/)
- [**](https://twitter.com/containersoluti)

© 2024 Container Solutions