Creating a Docker Private Registry on Your LAN

Pop quiz, hotshot: You wake up still groggy from the new year party the night before. Everyone is still asleep. What do you do?

Answer: Setup a github pages site, hookup your custom domain, and fight with markdown while writing your first jekyll blog post on how to set up a docker private registry on a LAN using a self-signed certificate and raw IP addresses instead of domain names.

Here goes nothing:

The Scenario

Your garage startup has been developing some docker images and wants to have a private docker registry to commit and pull images to and from internally. You just have a small subnet and want to designate a machine to serve as the registry and other docker host machines that will pull and commit the images from that registry. Since this is all local and behind your firewall, you decide that a simple self-signed certificate will suffice for security. Also, you want to use raw IP addresses rather than a full-blown domain name since you don’t plan to have your registry accessible over the web.

To work through this scenario, we will use two ubuntu virtual machines. One to act as the registry and one to act as a client docker host.

On Registry Machine

We are working with a fresh Ubuntu 16.04 install on a VirtualBox VM with a bridged interface at 192.168.1.106. So, we’ll install all the required pieces.

1. Install Docker

We can’t do much without docker.

Run the official installation script like so (it will ask you for a sudo password):

curl -sSL https://get.docker.com/ | sh

Then add yourself to the docker groups like so (if you skip this you’ll always have to run as superuser):

sudo usermod -aG docker <username>

Then (and this step is important): log all the way out and then log back in (so your new group will be picked up).

Once you log back in, open a terminal and run the command docker version. If you see the docker version and client running, you are good to go.

Screenshot of docker version command

2. Modify openssl.cnf for IP address

After docker is installed, we’ll need to create a self-signed certificate to use in our registry. The certificate generator usually wants a domain name for the certificate, but we don’t want to deal with all that in a small subnet. We’ll just use straight IPs. To make that work, we’ll need to modify the openssl config file.

Edit the /etc/ssl/openssl.cnf and add subjectAltName = IP:192.168.1.106 (use your registry IP address here) into the [ v3_ca ] section (mine was on line 224).

Like so:

sudo vi /etc/ssl/openssl.cnf
...
[ v3_ca ]   <===== UNDER THIS LINE
subjectAltName = IP:192.168.1.106   <====== ADD THIS LINE
...

3. Create certificate

Now it’s time to create the actual self-signed certificate. Run the following commands, answer the questions, and you’ll have a domain.key and a domain.crt file in the certs directory.

mkdir certs
openssl req -newkey rsa:4096 -nodes -sha256 \
-keyout certs/domain.key -x509 -days 365 \
-out certs/domain.crt

4. Start Registry with TLS

Now we can fire up our registry docker container with the following command (make sure you are one level up from your certs directory). Docker will pull the registry container from dockerhub and start it up for us.

docker run -d -p 5000:5000 --name registry \
-v $(pwd)/certs:/certs \
-e REGISTRY_HTTP_TLS_CERTIFICATE=/certs/domain.crt \
-e REGISTRY_HTTP_TLS_KEY=/certs/domain.key registry:2

You can run docker ps now and see the registry container running.

Screenshot of commands for starting the docker private registry

5. Put something in the Registry

Our registry is up and running, but it’s currently empty. Let’s put something in it so we can see it working. We will pull and ubuntu image from dockerhub, tag it into our localhost repository, and then push it into the repository.

docker pull ubuntu
docker tag ubuntu localhost:5000/ubuntu
docker push localhost:5000/ubuntu

We are now up and running. Next, we move over to our other VM that will interact with our new docker private registry.

6. Install ssh

We’ll go ahead and install and run ssh on the registry machine now. With it listening on port 22, it’ll be easier to pull the certificate onto the other machine in a bit using scp.

sudo apt install ssh

On Client Docker Host Machine

For our docker host machine that will be a client to our private registry, we are again working with a fresh Ubuntu 16.04 install on a VirtualBox VM with a bridged interface at 192.168.1.107.

1. Install Docker

Again, we can’t do much without docker.

Run the official installation script like so (it will ask you for a sudo password):

curl -sSL https://get.docker.com/ | sh

Then add yourself to the docker groups like so (if you skip this you’ll always have to run as superuser):

sudo usermod -aG docker <username>

Then (and this step is important): log all the way out and then log back in (so your new group will be picked up).

Once you log back in, open a terminal and run the command docker version. If you see the docker version and client running, you are good to go.

Screenshot of docker version command

2. Configure Docker Daemon to Trust Registry Certificate

First, we create some folders and scp the certificate from the registry over the the host machine. This makes the docker daemon trust the certificate.

sudo mkdir -p /etc/docker/certs.d/192.168.1.106:5000/
sudo scp z@192.186.1.106:/home/z/certs/domain.crt /etc/docker/certs.d/192.168.1.106:5000/ca.crt

We also go ahead and make the OS trust the certificate too.

sudo scp z@192.186.1.106:/home/z/certs/domain.crt /usr/local/share/ca-certificates/192.168.1.106.crt
sudo update-ca-certifications

4. Restart Docker Daemon

Now, we restart so the certificate is noticed.

sudo service docker restart

5. Pull from registry

Finally, we try and pull from our registry and get our image.

docker pull 192.168.1.106:5000/ubuntu

And it’s working!

Screenshot of pulling an image from the docker private registry

6. DRINK!

Water that is… I think I’m getting too old to party like that anymore.

Written on January 1, 2017