What a private Docker registry is
A registry is the server that stores container images and serves them when someone runs docker pull. Docker Hub is the default public registry, but as soon as you need to control where your images live (for compliance, for bandwidth, or simply to stop depending on a third party) you run your own with the reference implementation from the Distribution project, packaged as the registry:3 image.
How tagging and pushing an image works
An image name carries the registry encoded up front: host:port/repository:tag. docker tag alpine:3.21 localhost:5000/alpine:mine copies nothing; it just creates a local alias pointing at the same image ID, and it is docker push that actually ships the layers to the registry. The source behind that push endpoint lives in the distribution/distribution repository.
Securing the registry with htpasswd and TLS
An unauthenticated registry is an open bin: anyone with network access to port 5000 can push or pull images. The registry:3 image supports basic auth (a bcrypt-hashed username and password via htpasswd) and TLS in front of port 5000; in production the two always ship together, because Docker only sends credentials in the clear to hosts it treats as “insecure”, which by default means only localhost. In this lab we generate an htpasswd file with a throwaway user and password (changeme) to see the bcrypt format the registry requires; wiring it up for real only takes REGISTRY_AUTH=htpasswd, REGISTRY_AUTH_HTPASSWD_PATH and a certificate under REGISTRY_HTTP_TLS_CERTIFICATE at container start.
If you’re exposing the registry under your own domain, our Nginx Proxy Manager on Docker guide covers the TLS certificate side for any container. To understand the rest of the networking this lab touches, we have dedicated guides on Docker networking and volumes and bind mounts; if you’d rather read a written walkthrough without the video, the long-form version is how to run a private Docker image registry. This and the rest of our hands-on labs follow the same rule: everything you see actually ran.
FAQ
What is the official image used to run a private Docker registry?
The registry:3 image, maintained by the Distribution project (the reference implementation of the container registry). It replaces the older registry:2, which still works but no longer gets the latest fixes.
How do I tell Docker to use my registry instead of Docker Hub?
By prefixing the image name with the registry's host and port: localhost:5000/alpine:mine instead of alpine:mine. That prefix is the only thing that tells Docker Hub images apart from images in your own registry.
Is it safe to leave a Docker registry with no authentication or TLS?
Not for production. Without authentication, anyone with network access to port 5000 can push or pull images; without TLS, Docker only sends credentials in the clear to hosts it treats as insecure (by default, only localhost). The registry supports both together: htpasswd for authentication and a certificate to encrypt the traffic.
What is the difference between docker tag and docker push?
docker tag doesn't move a single byte: it creates a new local alias pointing at the same image ID. docker push is the command that actually ships the image's layers to the registry encoded in that alias.