Self-hosted Docker Registry and Web-UI with HTTPS support
Why? I want to host and run some private docker images on my Unraid NAS.
For Docker Registry, it is a no-brainer that we can use the official one (docker hub link).
On Unraid, this is the existing docker app “DockerRegistry”. Once installed and started, it listens on port 5000.
Now we have two issues need to be sorted out:
- Both docker cli and Unraid docker doesn’t like registry on HTTP (
server gave HTTP response to HTTPS client
) - Docker Registry doesn’t comes with web UI. We would be lost really soon on what are there in this registry.
Here is what I found for reference.
Update 28/09/2024: It turns out that adding HTTPS support is NOT that difficult. So you no longer need this section.
Please see the new 3rd section for details. Still keeping this section for reference
To allow docker cli talking to registry on HTTP, need to add insecure-registries
option to docker daemon.
In below examples, I am referring to my HTTP docker registry as
192.168.88.77:5000
On Ubuntu Linux:
$ cat /etc/docker/daemon.json
{"insecure-registries":["192.168.88.77:5000"]}
On Unraid NAS (source):
# cat /boot/config/docker.cfg
...
DOCKER_OPTS="--insecure-registry 127.0.0.1:5000"
# /etc/rc.d/rc.docker restart
Refer to this for other OS.
For a just-work web UI, I found this one written in Go: https://github.com/genuinetools/reg
Last update was in 2019, but still works perfectly. If you want something heavy / enterprise level, try https://github.com/goharbor/harbor
I wrote a wrapper Dockerfile to make it listening on port 5001:
FROM 192.168.88.77:5000/reg:latest
ENV REGISTRY_URL=192.168.88.77:5000
EXPOSE 5001
# override the entrypoint from base image
ENTRYPOINT []
CMD ["/bin/sh", "-c", "reg server --registry ${REGISTRY_URL} --port 5001 --force-non-ssl"]
Works perfectly:
This section has been added on 28/09/2024 for HTTPS setup.
It is trivial to add HTTPS support with an HTTPS proxy solution (e.g. I am using Nginx Proxy Manager aka NPM in below examples).
Assume you have already both docker registry and UI running.
Just to recap:
- Docker registry listens on 192.168.88.77:5000 (in HTTP mode). The actual registry API is behind
http://192.168.88.77:5000/v2/
- The registry UI (reg) listens on 192.168.88.77:5001
Also as pre-requisite, you need to get an HTTPS certificate. I will skip this part. Assume you have sorted it out in NPM already. My domain name / certificate is docker.example.com
(You may ask then you are exposing your private registry to public. No I didn’t. I have a custom local DNS entry to resolve docker.example.com
to local IP)
For step 2 above, you also need to modify Environment Variable with a new value docker.example.com
. In my case I just updated the original Dockerfile:
ENV REGISTRY_URL=docker.example.com
Note that we no longer need to specify port number 5000 since it defaults to port number 443 (HTTPS) now.
Create a new proxy host in NPM:
Then in “SSL” tab select your earlier docker.example.com
certificate.
Once this is done, you get a nice and clean setup:
- Access
https://docker.example.com
shows you the registry UI - Anywhere you can refer your registry to
docker.example.com/image:version
- You also no longer need any hack for insecure registry mentioned in section 1.
Also just a quick reference on how to push to private registry:
docker build . -t my-image:latest
docker tag my-image:latest docker.example.com/my-image:latest
docker push docker-example.com/my-image:latest