Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Private Docker Registry

A self-hosted Docker registry with a web UI, running as a Dockge stack on TrueNAS (or any Docker host). Useful for storing images built locally — like the SSH container — so they can be reused without rebuilding from scratch.


Overview

This stack runs two containers:

  • registry — the official Docker registry, with htpasswd authentication and delete support enabled
  • registry-ui — a lightweight web UI (joxit/docker-registry-ui) for browsing and managing images

The registry is exposed on port 7000 (mapped from the internal 5000) and the UI on port 7001.


Prerequisites

  • Dockge running on your Docker host
  • htpasswd available on the host (part of apache2-utils on Ubuntu/Debian, or httpd-tools on RHEL/Fedora)
  • A data path for persistent storage (e.g. /mnt/your-pool/data)

Step 1: Create the Auth Directory and Credentials

The registry uses htpasswd for basic authentication. Create the auth file before starting the stack, otherwise the registry will fail to start.

On your TrueNAS shell (or Docker host):

mkdir -p /mnt/your-pool/data/docker-registry/auth
htpasswd -Bc /mnt/your-pool/data/docker-registry/auth/htpasswd <your-username>

You’ll be prompted to set a password. The -B flag uses bcrypt hashing (recommended).

Note: The data directory for registry image layers will be created automatically at /mnt/your-pool/data/docker-registry/data when the container first starts.


Step 2: Deploy with Dockge

In Dockge, create a new stack called docker-registry and paste the following:

services:
  registry:
    image: registry:2
    container_name: docker-registry
    restart: unless-stopped
    ports:
      - 7000:5000
    volumes:
      - ${DATA_PATH}/docker-registry/data:/var/lib/registry
      - ${DATA_PATH}/docker-registry/auth:/auth
    environment:
      REGISTRY_STORAGE_DELETE_ENABLED: "true"
      REGISTRY_AUTH: htpasswd
      REGISTRY_AUTH_HTPASSWD_REALM: Registry
      REGISTRY_AUTH_HTPASSWD_PATH: /auth/htpasswd
    labels:
      homepage.group: Dev
      homepage.name: Docker Registry
      homepage.icon: docker.png
      homepage.description: Private container registry
  registry-ui:
    image: joxit/docker-registry-ui:latest
    container_name: registry-ui
    restart: unless-stopped
    ports:
      - 7001:80
    environment:
      SINGLE_REGISTRY: "true"
      REGISTRY_TITLE: Homelab Registry
      DELETE_IMAGES: "true"
      SHOW_CONTENT_DIGEST: "true"
      NGINX_PROXY_PASS_URL: http://registry:5000
    depends_on:
      - registry
    labels:
      homepage.group: Dev
      homepage.name: Registry Browser
      homepage.icon: docker.png
      homepage.href: http://<truenas-ip>:7001
      homepage.description: Browse container images
networks: {}

Set the environment variable

In Dockge’s env section (or a .env file), set:

DATA_PATH=/mnt/your-pool/data

Deploy the stack. Both containers should come up within a few seconds.


Step 3: Log In from Your Laptop

Before pushing or pulling images, authenticate Docker against the registry:

docker login <truenas-ip>:7000

Enter the username and password you set in Step 1.


Step 4: Push and Pull Images

Tag and push a local image

docker tag my-image:latest <truenas-ip>:7000/my-image:latest
docker push <truenas-ip>:7000/my-image:latest

Pull an image

docker pull <truenas-ip>:7000/my-image:latest

Use in a Compose file

image: <truenas-ip>:7000/my-image:latest

Step 5: Browse the Registry UI

Open http://<truenas-ip>:7001 in your browser. You can browse repositories, inspect image tags and digests, and delete images from the UI.

Note: The UI connects to the registry through Docker’s internal network (http://registry:5000), so it does not require the registry to be exposed externally.


Troubleshooting

Registry returns 401 Unauthorized

The htpasswd file may be missing or in the wrong location. Verify:

ls -la /mnt/your-pool/data/docker-registry/auth/htpasswd

Re-run the htpasswd command from Step 1 if needed, then restart the stack.

docker login fails with “http: server gave HTTP response to HTTPS client”

Docker requires HTTPS for registries unless the address is marked as insecure. Add the registry to your Docker daemon’s insecure registries list on any machine that needs to push/pull:

{
  "insecure-registries": ["<truenas-ip>:7000"]
}

On Linux this goes in /etc/docker/daemon.json. Restart the Docker daemon after saving:

sudo systemctl restart docker

On Docker Desktop (Mac/Windows), add it via Settings → Docker Engine.

UI shows “No repositories found” despite images being present

Confirm the NGINX_PROXY_PASS_URL in the UI service points to http://registry:5000 (the internal service name), not the external host port.