Running a local Docker registry on a Synology NAS
With a lot of searching I pieced together resources from many different places to finally arrive at a working solution to running a local Docker registry on my Synology NAS within my home network. Let's dive into the details of how to accomplish this.
The Problem
Docker expects registries to be secure. If you run a Docker registry like so:
docker run --rm -p 5555:5000 --name registry registry:2
And try to pull an image from it or push to it, you will be met with the following error.
$ docker build --tag 192.168.1.222:5555/hello .
$ docker push 192.168.1.222:5555/hello
...
Get https://192.168.1.222:5555/v2/: http: server gave HTTP response to HTTPS client
We will go through the steps to secure our registry and trust the certificate in order to consume the registry on our local network.
Alternative: Trusting an insecure registry
Now, you don't technically have to use a certificate. If you choose not to, you will need to insecurely trust the registry with the following in your Docker config.
{
"insecure-registries" : ["192.168.1.222:5555"]
}
Steps
The general steps I took are as follows.
- Self-sign a certificate for local use only
- Run the Docker registry
- Push and pull images
1. Self-sign a certificate for local use only
Disclaimer: Although we are making our local instance secure within our network, this is not considered secure publicly. We would want to get a certificate signed for public use from a trusted Certificate Authority (CA) for that. Without further ado, let's create our self-signed certificate!
Create a file called mydomain.cnf
with the following contents.
[req]
default_bits = 4096
default_md = sha256
distinguished_name = req_distinguished_name
x509_extensions = v3_req
prompt = no
[req_distinguished_name]
C = US
ST = Utah
L = Orem
O = MyCompany
OU = MyDivision
CN = 192.168.1.222
[v3_req]
keyUsage = keyEncipherment, dataEncipherment
extendedKeyUsage = serverAuth
subjectAltName = @alt_names
[alt_names]
IP.1 = 192.168.1.222
Now replace the values of the following fields.
C
(country code)ST
(state)L
(city)CN
andIP.1
with the IP address on your local network
Then run the following command to generate the key and certificate.
openssl req -new -nodes -x509 -days 365 -keyout mydomain.key -out mydomain.crt -config ./mydomain.cnf
2. Run the Docker registry
Now it's time to run the registry!
On your Synology, create the following docker-compose.yml
file.
version: '3.8'
services:
registry:
container_name: registry
image: registry:2
restart: unless-stopped
ports:
- 5555:5000
environment:
REGISTRY_HTTP_TLS_CERTIFICATE: /certs/domain.crt
REGISTRY_HTTP_TLS_KEY: /certs/domain.key
volumes:
- /volume1/docker/registry/data:/var/lib/registry
- /volume1/docker/registry/certs:/certs
Replace the volume mount paths with your own path and the port with whatever you prefer.
Trust the certificate
Without trusting the certificate, when pushing to the registry or pulling images from the registry, you will be met with the following error.
$ docker-compose up
Pulling myimage (192.168.1.222:5555/myimage:)...
ERROR: Get "https://192.168.1.222:5555/v2/": x509: certificate signed by unknown authority
Synology
To trust the certificate on Synology, add a copy of mydomain.crt
to /var/packages/Docker/etc/certs.d/192.168.1.222:555/ca.crt
MacOS
To trust the certificate on MacOS, run the following command in the directory of the certificate.
sudo security add-trusted-cert -d -r trustRoot -k /Library/Keychains/System.keychain mydomain.crt
3. Push and pull images
Now you can successfully and securely push an image!
Create a dockerfile.
FROM alpine
CMD ["echo", "Hello, World!"]
Build and push it to the registry.
docker build --tag 192.168.1.222:5555/hello .
docker push 192.168.1.222:5555/hello
Now run it from anywhere on your network!
docker run --rm 192.168.1.222:5555/hello
Bonus
If you want to see the images in the registry to verify that they are actually there, you can hit the endpoints on the registry as follows.
List image repositories
$ curl https://192.168.1.222:5555/v2/_catalog
{"repositories":["hello"]}
List image tags
$ curl https://192.168.1.222:5555/v2/hello/tags/list
{"name":"hello","tags":["latest"]}
Conclusion
We made it! We successfully setup and (locally) secured a Docker registry and pushed some images to it. We then pulled the image and ran it on a separate device on the network. Great work!