Skip to content
intermediate Phase 6 · Docker Production

Private Registries

Set up and manage private Docker registries with authentication.

1h
0 problems
Topic Progress 0%

Private Registry Setup

Private Registry Setup

Docker Registry (Official)

The simplest way to run a private registry:

# Run registry container
docker run -d -p 5000:5000 --name registry \
  -v registry_data:/var/lib/registry \
  registry:2

# Tag and push image
docker tag myapp:latest localhost:5000/myapp:latest
docker push localhost:5000/myapp:latest

# Pull image
docker pull localhost:5000/myapp:latest

# List images in registry
curl http://localhost:5000/v2/_catalog
# {"repositories":["myapp"]}

Registry with Authentication

# Create htpasswd file
mkdir -p auth
apt-get install apache2-utils
htpasswd -Bbn admin secret123 > auth/htpasswd

# Run registry with auth
docker run -d -p 5000:5000 --name registry \
  -v registry_data:/var/lib/registry \
  -v $(pwd)/auth:/auth \
  -e "REGISTRY_AUTH=htpasswd" \
  -e "REGISTRY_AUTH_HTPASSWD_REALM=Registry Realm" \
  -e "REGISTRY_AUTH_HTPASSWD_PATH=/auth/htpasswd" \
  registry:2

# Log in
docker login localhost:5000
# Username: admin
# Password: secret123

Registry with TLS

# Generate self-signed certificate
mkdir -p certs
docker run --rm \
  -v $(pwd)/certs:/certs \
  -e "REGISTRY_HTTP_ADDR=0.0.0.0:443" \
  -e "REGISTRY_HTTP_TLS_CERTIFICATE=/certs/cert.pem" \
  -e "REGISTRY_HTTP_TLS_KEY=/certs/key.pem" \
  registry:2

# Or use Let's Encrypt with certbot
certbot certonly --standalone -d registry.company.com

# Run with TLS
docker run -d -p 443:443 --name registry \
  -v registry_data:/var/lib/registry \
  -v /etc/letsencrypt:/etc/letsencrypt \
  -e "REGISTRY_HTTP_ADDR=0.0.0.0:443" \
  -e "REGISTRY_HTTP_TLS_CERTIFICATE=/etc/letsencrypt/live/registry.company.com/fullchain.pem" \
  -e "REGISTRY_HTTP_TLS_KEY=/etc/letsencrypt/live/registry.company.com/privkey.pem" \
  registry:2

Docker Compose for Registry

services:
  registry:
    image: registry:2
    ports:
      - "443:443"
    environment:
      REGISTRY_HTTP_ADDR: "0.0.0.0:443"
      REGISTRY_HTTP_TLS_CERTIFICATE: /certs/cert.pem
      REGISTRY_HTTP_TLS_KEY: /certs/key.pem
      REGISTRY_AUTH: htpasswd
      REGISTRY_AUTH_HTPASSWD_REALM: "Registry Realm"
      REGISTRY_AUTH_HTPASSWD_PATH: /auth/htpasswd
    volumes:
      - registry_data:/var/lib/registry
      - ./certs:/certs:ro
      - ./auth:/auth:ro

volumes:
  registry_data:

Cloud Container Registries

Cloud Container Registries

Amazon ECR (Elastic Container Registry)

# Create repository
aws ecr create-repository --repository-name myapp --region us-east-1

# Log in to ECR
aws ecr get-login-password --region us-east-1 | \
  docker login --username AWS --password-stdin \
  123456789.dkr.ecr.us-east-1.amazonaws.com

# Tag and push
docker tag myapp:latest 123456789.dkr.ecr.us-east-1.amazonaws.com/myapp:latest
docker push 123456789.dkr.ecr.us-east-1.amazonaws.com/myapp:latest

# Lifecycle policy (auto-delete old images)
aws ecr put-lifecycle-policy \
  --repository-name myapp \
  --lifecycle-policy-text '{
    "rules": [{
      "rulePriority": 1,
      "description": "Keep last 10 images",
      "selection": {
        "tagStatus": "any",
        "countType": "imageCountMoreThan",
        "countNumber": 10
      },
      "action": {"type": "expire"}
    }]
  }'

Google Container Registry (GCR)

# Authenticate
gcloud auth configure-docker

# Tag and push
docker tag myapp:latest gcr.io/my-project/myapp:latest
docker push gcr.io/my-project/myapp:latest

# Or use Artifact Registry (newer)
artifactregistry repositories create my-repo --repository-format=docker
docker tag myapp:latest us-central1-docker.pkg.dev/my-project/my-repo/myapp:latest
docker push us-central1-docker.pkg.dev/my-project/my-repo/myapp:latest

Azure Container Registry (ACR)

# Create ACR
az acr create --name myregistry --sku Standard

# Log in
az acr login --name myregistry

# Tag and push
docker tag myapp:latest myregistry.azurecr.io/myapp:latest
docker push myregistry.azurecr.io/myapp:latest

# Enable admin access (for simple auth)
az acr update -n myregistry --admin-enabled true

Docker Hub (Private)

# Log in
docker login

# Push to personal repo
docker tag myapp:latest username/myapp:latest
docker push username/myapp:latest

# Push to organization
docker tag myapp:latest myorg/myapp:latest
docker push myorg/myapp:latest

Registry Comparison

Registry Free Tier Auth Vulnerability Scanning
Docker Hub 1 private repo Token Docker Scout
ECR 500MB/month free IAM Inspector
GCR 500MB free IAM Container Analysis
ACR 100MB free Azure AD Defender
Harbor Self-hosted OIDC/LDAP Trivy/S Clair

Registry Maintenance

Registry Maintenance

Garbage Collection

Remove unused image layers from the registry:

# Stop registry
docker stop registry

# Run garbage collection
docker run --rm \
  -v registry_data:/var/lib/registry \
  registry:2 \
  registry garbage-collect /etc/docker/registry/config.yml

# Restart registry
docker start registry

# Automated garbage collection (cron)
0 2 * * * docker run --rm -v registry_data:/var/lib/registry registry:2 registry garbage-collect /etc/docker/registry/config.yml

Image Retention Policies

# docker-compose.yml with retention
services:
  registry:
    image: registry:2
    environment:
      REGISTRY_STORAGE_DELETE_ENABLED: "true"
# Delete specific image by digest
curl -X DELETE http://localhost:5000/v2/myapp/manifests/sha256:abc123...

Registry Health Check

# Check registry health
curl http://localhost:5000/v2/
# {}

# List all repositories
curl http://localhost:5000/v2/_catalog

# List tags for a repository
curl http://localhost:5000/v2/myapp/tags/list

# Get image manifest
curl -H "Accept: application/vnd.docker.distribution.manifest.v2+json" \
  http://localhost:5000/v2/myapp/manifests/latest

Backup Registry Data

# Backup registry volumes
docker run --rm \
  -v registry_data:/source:ro \
  -v $(pwd):/backup \
  alpine tar czf /backup/registry-backup.tar.gz -C /source .

# Restore
docker volume create registry_data_restored
docker run --rm \
  -v registry_data_restored:/target \
  -v $(pwd):/backup \
  alpine tar xzf /backup/registry-backup.tar.gz -C /target

Registry Mirroring

// /etc/docker/daemon.json
{
  "registry-mirrors": ["https://registry-mirror.company.com"]
}
# Pull images through mirror automatically
docker pull nginx:1.25
# Docker checks mirror first, falls back to Docker Hub