A comprehensive guide for setting up a secure private Docker registry with authentication, UI, backup, and restoration capabilities.
- Prerequisites
- Registry Setup
- Authentication Setup
- UI Configuration
- Backup and Restoration
- Maintenance and Cleanup
- Troubleshooting
- Ubuntu 20.04 or later
- Docker installed
- Docker Compose installed
- Sufficient storage space (recommended: at least 50GB)
- Root or sudo access
# Create base directory
mkdir -p ~/docker-registry/{data,auth}
cd ~/docker-registry
Create docker-compose.yml
:
version: '3'
services:
registry:
image: registry:2
ports:
- "5000:5000"
environment:
REGISTRY_AUTH: htpasswd
REGISTRY_AUTH_HTPASSWD_REALM: Registry
REGISTRY_AUTH_HTPASSWD_PATH: /auth/registry.password
REGISTRY_STORAGE_FILESYSTEM_ROOTDIRECTORY: /data
volumes:
- ./auth:/auth
- ./data:/data
ui:
image: joxit/docker-registry-ui:latest
ports:
- "8080:80"
environment:
- REGISTRY_TITLE=Private Docker Registry
- REGISTRY_URL=http://registry:5000
- SINGLE_REGISTRY=true
- REGISTRY_SECURED=true
- BASIC_AUTH_USER=admin
- BASIC_AUTH_PASSWORD=redhat
depends_on:
- registry
sudo apt update
sudo apt install apache2-utils -y
# Create credentials file
htpasswd -Bc auth/registry.password admin
# Enter password when prompted (e.g., redhat)
# Add additional users (if needed)
htpasswd -B auth/registry.password additional_user
docker-compose up -d
On each client machine that needs to access the registry:
# Edit or create daemon.json
sudo nano /etc/docker/daemon.json
# Add the following content
{
"insecure-registries": ["your-registry-ip:5000"]
}
# Restart Docker
sudo systemctl restart docker
# Edit containerd configuration
sudo nano /etc/containerd/config.toml
# Add the following configuration
[plugins."io.containerd.grpc.v1.cri".registry]
[plugins."io.containerd.grpc.v1.cri".registry.mirrors]
[plugins."io.containerd.grpc.v1.cri".registry.mirrors."your-registry-ip:5000"]
endpoint = ["http://your-registry-ip:5000"]
# Restart containerd
sudo systemctl restart containerd
Create registry_backup.sh
:
#!/bin/bash
# Configuration
REGISTRY_HOME="/root/docker-registry"
BACKUP_DIR="/data/registry_backups"
BACKUP_NAME="registry_backup_$(date +%Y%m%d_%H%M%S)"
KEEP_LAST_N=5
# Create backup directory
mkdir -p "$BACKUP_DIR"
# Create backup
echo "Creating backup..."
tar -czf "$BACKUP_DIR/$BACKUP_NAME.tar.gz" \
-C $(dirname "$REGISTRY_HOME") \
--exclude="docker-registry/data/docker/registry/v2/blobs" \
docker-registry
# Cleanup old backups
cd "$BACKUP_DIR"
ls -t | grep 'registry_backup_.*\.tar\.gz$' | tail -n +$((KEEP_LAST_N + 1)) | xargs -r rm
echo "Backup completed: $BACKUP_DIR/$BACKUP_NAME.tar.gz"
# Make script executable
chmod +x registry_backup.sh
# Add to crontab (run daily at 2 AM)
crontab -e
0 2 * * * /root/docker-registry/registry_backup.sh
Create registry_restore.sh
:
#!/bin/bash
if [ $# -ne 1 ]; then
echo "Usage: $0 /path/to/backup.tar.gz"
exit 1
fi
BACKUP_FILE="$1"
REGISTRY_HOME="/root/docker-registry"
# Stop registry
cd $REGISTRY_HOME
docker-compose down
# Backup current state
tar -czf "pre_restore_$(date +%Y%m%d_%H%M%S).tar.gz" ./*
# Restore from backup
rm -rf ./*
tar -xzf "$BACKUP_FILE" -C "$REGISTRY_HOME/.."
# Start registry
docker-compose up -d
echo "Restore completed. Please verify registry is functioning correctly."
Create cleanup_registry.sh
:
#!/bin/bash
# Configuration
REGISTRY_URL="http://localhost:5000"
USERNAME="admin"
PASSWORD="redhat"
KEEP_LAST_N=20
DRY_RUN=false
# Function to get auth token
get_auth_token() {
echo $(echo -n "$USERNAME:$PASSWORD" | base64)
}
# Function to get tags for a repository
get_tags() {
local repo=$1
local tags_json=$(curl -sf -u "${USERNAME}:${PASSWORD}" \
"$REGISTRY_URL/v2/$repo/tags/list")
if [ $? -eq 0 ] && [ ! -z "$tags_json" ]; then
echo "$tags_json" | jq -r '.tags[]?' 2>/dev/null || echo ""
else
echo ""
fi
}
# Function to get manifest digest
get_digest() {
local repo=$1
local tag=$2
local digest=$(curl -sf -I -u "${USERNAME}:${PASSWORD}" \
-H "Accept: application/vnd.docker.distribution.manifest.v2+json" \
"$REGISTRY_URL/v2/$repo/manifests/$tag" | grep Docker-Content-Digest | awk '{print $2}' | tr -d $'\r')
echo "$digest"
}
# Function to delete a tag
delete_tag() {
local repo=$1
local digest=$2
if [ "$DRY_RUN" = true ]; then
echo "Would delete: $repo@$digest"
else
echo "Deleting: $repo@$digest"
curl -sf -X DELETE -u "${USERNAME}:${PASSWORD}" \
"$REGISTRY_URL/v2/$repo/manifests/$digest"
fi
}
echo "Starting registry cleanup process..."
# Process each repository
for repo in $(curl -sf -u "${USERNAME}:${PASSWORD}" "$REGISTRY_URL/v2/_catalog" | jq -r '.repositories[]'); do
echo "Processing repository: $repo"
tags_output=$(get_tags "$repo")
if [ -z "$tags_output" ]; then
continue
fi
readarray -t tags < <(echo "$tags_output" | sort -V)
total_tags=${#tags[@]}
if [ $total_tags -gt $KEEP_LAST_N ]; then
to_delete=$((total_tags - KEEP_LAST_N))
echo "Found $total_tags tags, keeping last $KEEP_LAST_N, will delete $to_delete"
for ((i=0; i<$to_delete; i++)); do
tag=${tags[$i]}
digest=$(get_digest "$repo" "$tag")
if [ ! -z "$digest" ]; then
delete_tag "$repo" "$digest"
fi
done
fi
done
echo "Cleanup process completed"
if [ "$DRY_RUN" = false ]; then
echo "Running garbage collection..."
docker exec registry registry garbage-collect /etc/docker/registry/config.yml
fi
# Make script executable
chmod +x cleanup_registry.sh
# Add to crontab (run weekly)
crontab -e
0 3 * * 0 /root/docker-registry/cleanup_registry.sh
- Authentication Failures
# Verify auth file exists and is correctly formatted
cat ~/docker-registry/auth/registry.password
# Recreate auth file if needed
htpasswd -Bc ~/docker-registry/auth/registry.password admin
- Registry Access Issues
# Test registry connectivity
curl -u admin:redhat http://registry-ip:5000/v2/_catalog
# Check registry logs
docker-compose logs registry
- UI Access Issues
# Check UI container logs
docker-compose logs ui
# Verify UI is running
curl http://localhost:8080
# Check port availability
netstat -tulpn | grep 8080
-
Regular Maintenance
- Monitor disk usage regularly
- Keep backups in multiple locations
- Test restoration process periodically
- Review and update cleanup policies
-
Security
- Use strong passwords
- Regularly rotate credentials
- Keep Docker and components updated
- Monitor access logs
-
Performance
- Clean up old images regularly
- Monitor system resources
- Optimize storage usage
If
docker-compose
throws an error, usedocker compose
(w/o the hyphen)