A private Docker registry lets you store and distribute your own container images without relying on a public registry — useful for proprietary applications or organizations wanting full control over image storage.
Why Run Your Own Registry
- Keep proprietary application images private, entirely under your own control
- Avoid rate limits or availability dependencies on third-party public registries
- Faster image pulls if your registry is closer to your deployment infrastructure
Prerequisites
- Docker installed
- A domain name (for proper TLS-secured registry access)
Step 1 — Run the Registry Container
docker run -d \
--name registry \
--restart unless-stopped \
-p 5000:5000 \
-v registry-data:/var/lib/registry \
registry:2
Step 2 — Add HTTPS via Reverse Proxy
Docker registries require HTTPS for non-localhost access by default — see How to Install Nginx Proxy Manager with Docker to route a domain with SSL to your registry.
Step 3 — Add Basic Authentication
mkdir auth
docker run --rm --entrypoint htpasswd registry:2 -Bbn myuser mypassword > auth/htpasswd
docker run -d \
--name registry \
--restart unless-stopped \
-p 5000:5000 \
-v registry-data:/var/lib/registry \
-v $(pwd)/auth:/auth \
-e REGISTRY_AUTH=htpasswd \
-e REGISTRY_AUTH_HTPASSWD_REALM="Registry" \
-e REGISTRY_AUTH_HTPASSWD_PATH=/auth/htpasswd \
registry:2
Step 4 — Log Into Your Private Registry
docker login registry.yourdomain.com
Step 5 — Tag and Push an Image
docker tag myapp:1.0 registry.yourdomain.com/myapp:1.0
docker push registry.yourdomain.com/myapp:1.0
Step 6 — Pull the Image on Another Server
docker login registry.yourdomain.com
docker pull registry.yourdomain.com/myapp:1.0
Adding a Web UI (Optional)
The base registry has no built-in web interface — several open-source registry UI projects exist, providing browsable image listing/management if you want a friendlier interface beyond the command line.
Storage Considerations
Registry storage grows with every pushed image/tag — consider using object storage (see How to Set Up Self-Hosted S3-Compatible Object Storage with MinIO) as the registry's storage backend for more scalable, decoupled storage rather than relying solely on local VPS disk.
Setting Up Garbage Collection
docker exec registry bin/registry garbage-collect /etc/docker/registry/config.yml
Removes unreferenced image layers (from deleted/overwritten tags), reclaiming storage space that would otherwise accumulate indefinitely.
Integrating with CI/CD
See How to Build a Simple CI/CD Pipeline with GitHub Actions — configure your pipeline to push built images directly to your private registry as part of the deployment process.
Common Errors
"http: server gave HTTP response to HTTPS client" — Docker requires HTTPS for non-localhost registries by default; verify your reverse proxy is correctly serving HTTPS, not just forwarding to the registry's plain HTTP port without TLS termination.
Continue Reading
- How to Install Nginx Proxy Manager with Docker
- How to Set Up Self-Hosted S3-Compatible Object Storage with MinIO
- How to Build a Simple CI/CD Pipeline with GitHub Actions
Browse more articles in Docker & Containers.