Running Your Own Docker Registry
What This Article Covers
- What a Docker Registry is and when you need one.
- How to run the official Registry.
- Pushing and pulling images.
- Authentication, TLS, and security.
- Backup and maintenance tips.
Introduction: Running Your Own Docker Registry
A Docker Registry is a storage location for Docker images. By default, images come from Docker Hub, but sometimes you want to serve your own images locally or across an internal network. Your own Registry is useful for CI/CD pipelines, isolated environments, data privacy, or when Docker Hub is unavailable.
This article walks through running the official Docker Registry locally or in a homelab environment.
Key Concepts
- Registry: Storage location for Docker images.
- Repository: Collection of images under a single name.
- Tag: Version identifier for an image.
- Push: Upload an image to the Registry.
- Pull: Download an image from the Registry.
- TLS: Encrypted connection.
- Basic Auth: Username and password access.
- Garbage Collection: Cleanup of unreferenced layers.
When You Need Your Own Registry
- Distribute custom images across an internal network.
- Speed up CI/CD pipelines.
- Avoid Docker Hub rate limits.
- Keep data out of public registries.
- Supply air-gapped environments.
- Share build cache between hosts.
Starting the Registry
The official Registry runs as a simple container:
docker run -d -p 5000:5000 --name registry registry:2
Test it:
curl http://localhost:5000/v2/_catalog
Tagging and Pushing Images
Rename an existing image and upload it:
docker tag mein-image:latest localhost:5000/mein-image:latest
docker push localhost:5000/mein-image:latest
Pulling Images
docker pull localhost:5000/mein-image:latest
Persistent Storage with Volumes
docker run -d -p 5000:5000 --name registry \
-v registry-data:/var/lib/registry \
registry:2
Enabling TLS
For production or remote access, secure the Registry with TLS. You can use a certificate from a CA or a self-signed certificate.
Self-Signed Certificate
mkdir -p certs
openssl req -newkey rsa:4096 -nodes -sha256 -keyout certs/registry.key -x509 -days 365 -out certs/registry.crt
Run the Registry with the certificate:
docker run -d -p 5000:5000 --name registry \
-v $(pwd)/certs:/certs \
-v registry-data:/var/lib/registry \
-e REGISTRY_HTTP_TLS_CERTIFICATE=/certs/registry.crt \
-e REGISTRY_HTTP_TLS_KEY=/certs/registry.key \
registry:2
On the client side, accept the certificate:
mkdir -p /etc/docker/certs.d/localhost:5000
cp registry.crt /etc/docker/certs.d/localhost:5000/ca.crt
Authentication
Simple Basic Auth using htpasswd:
mkdir auth
docker run --rm --entrypoint htpasswd httpd:2 -Bbn admin meinpasswort > auth/htpasswd
Run the Registry with authentication:
docker run -d -p 5000:5000 --name registry \
-v $(pwd)/auth:/auth \
-e REGISTRY_AUTH=htpasswd \
-e REGISTRY_AUTH_HTPASSWD_REALM="Registry Realm" \
-e REGISTRY_AUTH_HTPASSWD_PATH=/auth/htpasswd \
-v registry-data:/var/lib/registry \
registry:2
Log in:
docker login localhost:5000
Registry with Compose
services:
registry:
image: registry:2
container_name: registry
ports:
- "127.0.0.1:5000:5000"
volumes:
- registry-data:/var/lib/registry
- ./certs:/certs
- ./auth:/auth
environment:
- REGISTRY_HTTP_TLS_CERTIFICATE=/certs/registry.crt
- REGISTRY_HTTP_TLS_KEY=/certs/registry.key
- REGISTRY_AUTH=htpasswd
- REGISTRY_AUTH_HTPASSWD_REALM=Registry Realm
- REGISTRY_AUTH_HTPASSWD_PATH=/auth/htpasswd
restart: unless-stopped
volumes:
registry-data:
Garbage Collection
Unreferenced layers can consume storage space. Run a cleanup:
docker exec registry bin/registry garbage-collect /etc/docker/registry/config.yml
Backup
Registry data lives in /var/lib/registry. A simple backup approach:
docker run --rm -v registry-data:/data -v $(pwd):/backup alpine tar -czf /backup/registry-backup.tar.gz -C /data .
Security
- Always use TLS for network access.
- Enable authentication.
- Never expose the Registry to the public internet.
- Restrict access via VPN or Tailscale.
- Apply backups and updates regularly.
- Enable logging.
Common Pitfalls
- No TLS: Newer Docker versions block insecure registries.
- Insecure Registry: Possible but not recommended.
- Wrong tag names: Image names must include the Registry host.
- Authentication not configured: Push fails without login.
- Storage fills up: Missing garbage collection.
- Certificate not trusted: Client needs the CA certificate.
Further Reading and Resources
- BotServ.de Docker Commands
- BotServ.de Docker Volumes
- BotServ.de Docker Backup
- BotServ.de Docker Security
- BotServ.de Tailscale Basics
FAQ: Docker Registry
Do I need my own Registry? If you distribute many custom images internally, yes. For occasional images, Docker Hub is fine.
Can I make the Registry public? Only with TLS, auth, and rate limiting. Better to keep it internal.
Is the Registry scalable? A single container works for small setups. For larger scenarios, look at Distribution or Harbor.
How do I delete old images? Via API or garbage collection. Individual tags can be removed through the Registry API.
What is Harbor? An advanced open-source Registry project with a UI, authentication, and security scanning.
Sources and Further Reading
- Docker Registry: https://distribution.github.io/distribution/
- Docker Registry Image: https://hub.docker.com/_/registry
- Harbor: https://goharbor.io/
Running your own Docker Registry lets you serve images locally or across an internal network. It starts quickly as a container but should be secured with TLS and authentication for production or remote use. Keep tag names clean, run regular backups, enable garbage collection, and restrict network access. A well-managed Registry saves bandwidth, speeds up deployments, and keeps your images under your control.


