DI

Distribution Registry UI

Web user interface for the Docker Distribution registry

Developer Tools & Git ★ 3.5k stars Easy setup MIT

A lightweight web user interface that sits in front of the Docker Distribution registry, letting teams browse, search, and delete container images. It adds a usable front end to the bare registry API.

Key features

  • Browse registry images
  • Tag and digest viewing
  • Image deletion
  • Search across repositories

Pros & cons

Strengths

  • Adds usability to bare registry
  • Tiny footprint

Trade-offs

  • No authentication of its own
  • Requires a running registry

Distribution Registry UI replaces

Last reviewed Sep 13, 2026 · 872 words

Distribution Registry UI has no authentication of its own and never will. It is a static Riot.js page that talks to your registry's HTTP API, either straight from the browser or through a small nginx proxy baked into the image. That one fact decides the whole deployment: whatever protects the registry (htpasswd, a token server, a VPN) is exactly what protects the UI, and nothing more. Get that straight first and the rest is a 10-minute compose file.

It is a front end, not a registry

The name confuses people. This project does not store images. It sits in front of Distribution, the reference registry that ships as the registry:2 image on port 5000, and gives you what the registry's API famously lacks: a list of repositories, the tags in each, the digest and size of each layer, and a delete button. If you already push to a bare registry and inspect it with curl /v2/_catalog, this replaces that habit with a page. If you do not yet have a registry, you need both containers.

The image is joxit/docker-registry-ui, and the useful settings are all environment variables:

services:
  registry:
    image: registry:2
    environment:
      - REGISTRY_STORAGE_DELETE_ENABLED=true
    volumes:
      - ./registry-data:/var/lib/registry
      - ./auth:/auth:ro
    restart: unless-stopped

  registry-ui:
    image: joxit/docker-registry-ui:main
    ports:
      - "8080:80"
    environment:
      - SINGLE_REGISTRY=true
      - REGISTRY_TITLE=homelab
      - NGINX_PROXY_PASS_URL=http://registry:5000
      - DELETE_IMAGES=true
      - SHOW_CONTENT_DIGEST=true
    restart: unless-stopped

NGINX_PROXY_PASS_URL is the setting that matters. Without it the page calls the registry directly from your browser, which means CORS headers on the registry and a registry URL that resolves from your laptop. With it, the UI's nginx proxies every API call, so the registry can stay on an internal Docker network and never be published at all. Use proxy mode unless you have a reason not to.

Deleting an image takes three steps, not one

The delete button is the reason most people install this, and it is the part that disappoints them. Three things have to be true. First, the registry must have REGISTRY_STORAGE_DELETE_ENABLED=true, because Distribution refuses deletes by default. Second, the UI needs DELETE_IMAGES=true. Third, and this is the step nobody reads about, deleting a tag through the API only removes the manifest reference. The layers stay on disk until you run garbage collection inside the registry container:

docker compose exec registry registry garbage-collect /etc/docker/registry/config.yml

Run it during a quiet moment, since pushes during a GC pass can leave a repository in a broken state, and put it on a weekly cron once you trust it. A registry that has had 6 months of CI pushes without GC is routinely 30 to 50 GB of unreferenced layers, so this is not a cosmetic step.

Auth has to come from the registry, or from a proxy in front of the UI

Since the UI has no login, there are two sane patterns. The simple one is htpasswd on the registry itself, which Docker clients already understand for docker login; in proxy mode the UI passes your browser's basic-auth prompt straight through, so one set of credentials covers push, pull, and browse. The tidier one is forward auth on the UI with Authelia or Authentik behind Caddy or Traefik, while the registry keeps htpasswd for the Docker CLI. Do not skip the second half of that: putting SSO on the web page while port 5000 sits open with no auth protects the map, not the territory.

When to stop and run Harbor instead

At 3,526 stars this project is popular precisely because it stays small: 128 MB of RAM, no database, one container. That is the right size for a single developer or a homelab that pushes a dozen images a week. It is the wrong size the moment you need per-project permissions, vulnerability scanning, replication to a second site, or an audit log of who pushed what. Harbor does all of that and costs you 1 to 2 GB of RAM and 8 containers. A quieter middle option: if you already run Gitea or Forgejo, their built-in container registry gives you a browsable UI with real accounts and no extra service at all.

The other thing this tool does not solve is the reason people leave Docker Hub in the first place, namely pull rate limits on public images. A private registry holds your images; for caching upstream ones you configure Distribution as a pull-through mirror, which this UI can browse but the compose above does not set up.

What I'd do

Proxy mode, registry on an internal network only, htpasswd on the registry, the UI published through the same reverse proxy as everything else in the dev-tools corner of the homelab. Delete enabled on both sides and a Sunday-night garbage-collect cron from day one, because retrofitting GC onto a bloated registry is when the broken-manifest stories happen. If a second person needs their own namespace, or you want scan results before deploying, that is the day to move to Harbor rather than bolt more around this.

Compare Distribution Registry UI

4 head-to-head comparisons.

Similar developer tools & git apps