Private Docker Registry Setup: Image Storage and Management
Private Docker Registry setup, secure registry with TLS, authentication, image push/pull operations, enterprise registry with Harbor, and CI/CD integration.
Table of Contents
Private Docker Registry Setup
While public registries like Docker Hub are convenient, hosting your own registry for private images offers advantages in security, speed, and cost. This guide covers options from simple Docker Registry to enterprise Harbor.
Why a Private Registry?
| Advantage | Description |
|---|---|
| Security | Private images not exposed publicly |
| Speed | Fast pull/push on local network |
| Cost | No Docker Hub rate limits |
| Control | Full image lifecycle control |
| Compliance | Data localization requirements |
1. Simple Docker Registry (registry:2)
Basic Setup
# Start registry container
docker run -d \
--name registry \
--restart always \
-p 5000:5000 \
-v registry-data:/var/lib/registry \
registry:2
# Verify registry is running
curl http://localhost:5000/v2/
# Output: {}
Image Push and Pull
# Tag image
docker tag myapp:latest localhost:5000/myapp:latest
# Push to registry
docker push localhost:5000/myapp:latest
# Pull from registry
docker pull localhost:5000/myapp:latest
# List images in registry
curl http://localhost:5000/v2/_catalog
# Output: {"repositories":["myapp"]}
# List image tags
curl http://localhost:5000/v2/myapp/tags/list
2. Secure Registry with TLS
Creating a Self-Signed Certificate
# Create certificate directory
mkdir -p /etc/docker/certs/registry
# Create self-signed certificate
openssl req -newkey rsa:4096 -nodes -sha256 \
-keyout /etc/docker/certs/registry/domain.key \
-x509 -days 365 \
-out /etc/docker/certs/registry/domain.crt \
-subj "/CN=registry.example.com" \
-addext "subjectAltName=DNS:registry.example.com,IP:192.168.1.100"
# Add certificate to Docker's trusted certificates
mkdir -p /etc/docker/certs.d/registry.example.com:5000
cp /etc/docker/certs/registry/domain.crt \
/etc/docker/certs.d/registry.example.com:5000/ca.crt
# Restart Docker
systemctl restart docker
Starting Registry with TLS
docker run -d \
--name registry \
--restart always \
-p 5000:5000 \
-v registry-data:/var/lib/registry \
-v /etc/docker/certs/registry:/certs \
-e REGISTRY_HTTP_TLS_CERTIFICATE=/certs/domain.crt \
-e REGISTRY_HTTP_TLS_KEY=/certs/domain.key \
registry:2
3. Registry with Authentication
# Create htpasswd file
mkdir -p /etc/docker/registry/auth
docker run --rm \
--entrypoint htpasswd \
httpd:2 -Bbn admin StrongPass123! > /etc/docker/registry/auth/htpasswd
# Start registry with authentication
docker run -d \
--name registry \
--restart always \
-p 5000:5000 \
-v registry-data:/var/lib/registry \
-v /etc/docker/certs/registry:/certs \
-v /etc/docker/registry/auth:/auth \
-e REGISTRY_HTTP_TLS_CERTIFICATE=/certs/domain.crt \
-e REGISTRY_HTTP_TLS_KEY=/certs/domain.key \
-e REGISTRY_AUTH=htpasswd \
-e REGISTRY_AUTH_HTPASSWD_REALM="Registry Realm" \
-e REGISTRY_AUTH_HTPASSWD_PATH=/auth/htpasswd \
registry:2
# Login
docker login registry.example.com:5000
4. Registry with Docker Compose
# registry-compose.yml
version: '3.8'
services:
registry:
image: registry:2
restart: always
ports:
- "5000:5000"
environment:
REGISTRY_HTTP_TLS_CERTIFICATE: /certs/domain.crt
REGISTRY_HTTP_TLS_KEY: /certs/domain.key
REGISTRY_AUTH: htpasswd
REGISTRY_AUTH_HTPASSWD_REALM: Registry Realm
REGISTRY_AUTH_HTPASSWD_PATH: /auth/htpasswd
REGISTRY_STORAGE_DELETE_ENABLED: "true"
volumes:
- registry-data:/var/lib/registry
- ./certs:/certs:ro
- ./auth:/auth:ro
registry-ui:
image: joxit/docker-registry-ui:latest
restart: always
ports:
- "8080:80"
environment:
- REGISTRY_TITLE=REXE Private Registry
- REGISTRY_URL=https://registry.example.com:5000
- SINGLE_REGISTRY=true
depends_on:
- registry
volumes:
registry-data:
5. Harbor — Enterprise Registry
Harbor is a CNCF-supported enterprise-grade container registry.
# Download Harbor installer
wget https://github.com/goharbor/harbor/releases/download/v2.9.0/harbor-online-installer-v2.9.0.tgz
tar xzf harbor-online-installer-v2.9.0.tgz
cd harbor
# Edit configuration
cp harbor.yml.tmpl harbor.yml
nano harbor.yml
# harbor.yml (basic settings)
hostname: registry.example.com
https:
port: 443
certificate: /etc/harbor/certs/domain.crt
private_key: /etc/harbor/certs/domain.key
harbor_admin_password: StrongPass123!
data_volume: /data/harbor
# Install Harbor
./install.sh
# Login to Harbor
docker login registry.example.com
# User: admin
# Password: StrongPass123!
# Create project and push image
docker tag myapp:latest registry.example.com/myproject/myapp:latest
docker push registry.example.com/myproject/myapp:latest
6. Registry Cleanup (Garbage Collection)
# Clean up unused layers
docker exec registry registry garbage-collect \
/etc/docker/registry/config.yml
# Dry-run (check before deleting)
docker exec registry registry garbage-collect \
--dry-run \
/etc/docker/registry/config.yml
# Delete image (via API)
curl -X DELETE \
https://registry.example.com:5000/v2/myapp/manifests/DIGEST \
--cacert /etc/docker/certs/registry/domain.crt \
-u admin:StrongPass123!
7. CI/CD Integration
With GitHub Actions
# .github/workflows/build-push.yml
name: Build and Push
on:
push:
branches: [main]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Login to Private Registry
uses: docker/login-action@v3
with:
registry: registry.example.com:5000
username: ${{ secrets.REGISTRY_USER }}
password: ${{ secrets.REGISTRY_PASSWORD }}
- name: Build and Push
uses: docker/build-push-action@v5
with:
context: .
push: true
tags: registry.example.com:5000/myapp:${{ github.sha }}
Using Private Registry in Kubernetes
# Add registry credentials as secret
kubectl create secret docker-registry registry-secret \
--docker-server=registry.example.com:5000 \
--docker-username=admin \
--docker-password=StrongPass123! \
--docker-email=admin@example.com
# deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: myapp
spec:
template:
spec:
imagePullSecrets:
- name: registry-secret
containers:
- name: myapp
image: registry.example.com:5000/myapp:latest
Conclusion
A private Docker Registry is essential for image security and management in enterprise environments. Choose registry:2 for simple use cases, Harbor for enterprise features (RBAC, security scanning, replication). With a private registry on REXE servers, you can securely store your images and integrate them into your CI/CD pipelines.
Related Articles
K3s Kubernetes Setup: Lightweight Container Orchestration
Single and multi-node Kubernetes cluster setup with K3s, kubectl usage, creating deployments and services, application management with Helm. Kubernetes guide for VPS environments.
Docker Volume and Network Management: Persistent Storage and Network Configuration
Docker volume types (named, bind mount, tmpfs), volume management, Docker network modes (bridge, host, overlay), creating custom networks and container communication. Comprehensive guide.
Container Logging: Docker and Kubernetes Log Management
Docker log drivers, docker logs command, Kubernetes pod logs, centralized log collection (Loki, ELK Stack), log rotation, and production log management best practices.