Contents

How to Set Up a Private Docker Registry with UI and Authentication

If you work with Docker and need your own private registry to store images — this guide is for you. Let’s explore how to deploy Docker Registry with a convenient web interface and set up authentication through Nginx.

First, let’s create a docker-compose.yml file with two services: the registry itself and a UI for it.

version: '3'
services:
  registry:
    image: registry:2
    ports:
      - "5005:5000"
    volumes:
      - ./data:/var/lib/registry
      - ./auth:/auth
    environment:
      REGISTRY_STORAGE_DELETE_ENABLED: "true"
      # Enable authentication
      REGISTRY_AUTH: htpasswd
      REGISTRY_AUTH_HTPASSWD_REALM: Registry Realm
      REGISTRY_AUTH_HTPASSWD_PATH: /auth/htpasswd
    restart: unless-stopped
  registry-ui:
    image: joxit/docker-registry-ui:latest
    ports:
      - "8089:80"
    environment:
      REGISTRY_TITLE: My Docker Registry
      # UI connects to registry locally
      NGINX_PROXY_PASS_URL: http://registry:5000
      SINGLE_REGISTRY: "true"
      DELETE_IMAGES: "true"
      SHOW_CATALOG_NB_TAGS: "true"
      # UI will pass credentials
      REGISTRY_SECURED: "false"
    depends_on:
      - registry
    restart: unless-stopped

Key points explained:

  • registry:2 — official Docker Registry version 2 image
  • REGISTRY_STORAGE_DELETE_ENABLED — allows deleting images via API
  • REGISTRY_AUTH: htpasswd — use basic authentication via htpasswd
  • joxit/docker-registry-ui — convenient web interface for viewing and managing images
  • DELETE_IMAGES: “true” — allows deleting images through UI

For authentication, you need to create an htpasswd file. First, install the utilities:

sudo apt-get install apache2-utils

Create a directory for auth files and generate htpasswd:

mkdir -p auth
htpasswd -Bc auth/htpasswd username
Note

The -B flag uses bcrypt for encryption (recommended), -c creates a new file

To access the registry through a single domain, let’s configure Nginx as a reverse proxy:

# UI on root
location / {
    proxy_pass http://localhost:8089;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;
}

# Registry API on /v2/
location /v2/ {
    proxy_pass http://localhost:5005;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;

    # Pass Authorization header to registry
    proxy_set_header Authorization $http_authorization;
    proxy_pass_header Authorization;

    client_max_body_size 0;
    chunked_transfer_encoding on;
}

Important details:

  • location / — proxies UI to the domain root
  • location /v2/ — proxies registry API (all Docker commands work through /v2/)
  • proxy_set_header Authorization — passes authentication from client to registry
  • client_max_body_size 0 — allows uploading images of any size
  • chunked_transfer_encoding on — required for correct transfer of large files

Start the services:

docker-compose up -d

Now you can work with the registry:

# Login to registry
docker login registry.yourdomain.com

# Push an image
docker tag myimage:latest registry.yourdomain.com/myimage:latest
docker push registry.yourdomain.com/myimage:latest

# Pull an image
docker pull registry.yourdomain.com/myimage:latest

The web interface will be available at https://registry.yourdomain.com, and the Docker API at https://registry.yourdomain.com/v2/

  • Use HTTPS — make sure to configure an SSL certificate (Let’s Encrypt)
  • Restrict access — add IP whitelisting or VPN for additional protection
  • Regular backups — keep the ./data folder with images backed up
  • Disk space monitoring — images quickly consume space, configure cleanup of old tags

Now you have your own private Docker Registry with a convenient interface! 🎉

Related Content