Docker Registry: Zot vs Harbor vs Distribution

Docker Registry: Zot vs Harbor vs Distribution

Compare Zot, Harbor, and Docker Distribution for a self-hosted container registry. Pick the right registry for a homelab, team, or CI pipeline.

💡 Disclosure: This article contains affiliate links. If you make a purchase through these links, we may earn a small commission at no extra cost to you. This helps support the site and keeps the content free.

A private Docker registry sounds like infrastructure cosplay until a public image disappears, a rate limit stops a deployment, or a CI job needs an image that should never leave your network.

Then docker pull stops being a harmless command. Your images are build artifacts. Treating them as disposable downloads is a weak link in an otherwise careful self-hosted setup.

The three sensible choices are Docker Distribution, Zot, and Harbor. They are not interchangeable. Distribution is the tiny dependable baseline, Zot is the modern lightweight option, and Harbor is a full platform that can become more work than the registry it protects.

The short answer

Docker DistributionZotHarbor
Best forOne private registryHomelab or small teamTeams and production policies
Setup effortVery lowLowHigh
Web UINoYesYes
Image signing supportBasic registry APIOCI-native featuresStrong policy integrations
Vulnerability scanningNoOptional extensionsBuilt in via Trivy
Resource appetiteTinyLightHeavy
My pickThrowaway internal cacheMost self-hostersOnly with a clear need

If you want one recommendation: start with Zot. It provides a proper UI, works with standard OCI images, and does not require turning your homelab into a small Kubernetes company.

Use Docker Distribution when you truly only need a private endpoint. Use Harbor when several people ship images, need scanning and retention rules, and will actually maintain those controls.

Why Docker Hub is not enough

Docker Hub is fine for public base images. It is not where I would put a private app image, an internal build cache, or an image that needs to stay available during an internet outage.

A self-hosted registry gives you three practical wins:

  • Private delivery: CI pushes an image once; your server pulls it from infrastructure you control.
  • Repeatable deployments: You retain the exact image digest that was approved and tested.
  • Less external dependency: Rebuilds and restarts are not held hostage by an upstream outage or a changed tag.

This does not mean mirror every image on the internet. That is how a 30GB disk quietly becomes a 300GB disk. Keep images you build, images you depend on heavily, and a small curated cache.

Docker Distribution - the boring baseline

Docker Distribution is the registry implementation behind the familiar registry:2 image. It stores layers, exposes the registry API, and otherwise stays out of your way.

That lack of features is both its strength and its limitation. There is no polished web UI, no built-in scanner, and no team workflow. For an internal CI registry behind a private network, that can be exactly right.

Here is a minimal Compose service:

services:
  registry:
    image: registry:2
    container_name: registry
    restart: unless-stopped
    ports:
      - "5000:5000"
    environment:
      REGISTRY_STORAGE_DELETE_ENABLED: "true"
    volumes:
      - ./registry-data:/var/lib/registry

Tag and push an image with:

docker tag my-app:1.0 registry.example.internal:5000/my-app:1.0
docker push registry.example.internal:5000/my-app:1.0

The catch is TLS and authentication. Do not solve that by exposing port 5000 over plain HTTP to the internet. Put it behind a reverse proxy with a real certificate, or keep it reachable only through a private network. Also remember that deleting a tag does not immediately reclaim disk space; registry garbage collection is a separate maintenance task.

Pick Distribution if: it is just you, your CI runner, and a couple of images. It has the fewest moving parts and the smallest blast radius.

Zot - the registry I would deploy first

Zot is a lightweight OCI registry written in Go. Unlike plain Distribution, it includes a web UI and is built around modern OCI artifact workflows. That matters when you want to store more than basic Docker images over time.

Its biggest advantage is the ratio of capability to operational burden. You get a registry that is pleasant to browse without installing a database, a scanner stack, and a collection of background services before pushing your first image.

A conservative starting point is to use the project’s documented Compose or binary installation, enable TLS, then expose it only on a private hostname. Keep the initial configuration simple: storage, authentication, TLS, and retention. Add syncing or advanced extensions only after you have a real use case.

I prefer Zot for a homelab because it makes the healthy path easy. You can see repositories and tags in a browser, yet clients still use normal Docker and OCI commands. There is no special workflow to teach your CI pipeline.

One warning: a slick UI is not a security boundary. Give each CI system a dedicated credential, do not reuse an admin account in pipelines, and pin deployment images by digest when the workload matters. Our Cosign guide explains why tags alone are not enough.

Pick Zot if: you want a private registry you will still enjoy operating six months from now, without the weight of an enterprise platform.

Harbor - powerful, but earn the complexity

Harbor is a container registry platform, not merely a place to put layers. It adds projects, robot accounts, retention rules, replication, vulnerability scanning with Trivy, signing-related integrations, and detailed access controls.

Those features solve real problems. A team can separate production from experimental images, block images with unacceptable vulnerabilities, and automatically delete stale tags. A registry with no cleanup policy eventually becomes an expensive archive of bad ideas.

But Harbor is not a five-minute container. It has multiple components, persistent state, and resource requirements that deserve a proper server and backup plan. Running it on a tiny VPS because the dashboard looks nice is the classic self-hosting mistake: installing a solution larger than the problem.

Use Harbor when your images cross team boundaries, when compliance or security gates are real requirements, or when you need replication across sites. If nobody will review scan findings or own the retention policy, its best features become decorative complexity.

Pick Harbor if: you have several users, production deployment stages, and a written reason for every extra control.

Security rules that matter more than the product

The registry choice matters less than these habits:

  1. Never publish an unauthenticated registry to the public internet. A registry leak can expose proprietary code, package metadata, and sometimes accidentally baked-in secrets.
  2. Use HTTPS everywhere. Docker clients reject insecure registries by default for a reason. Do not train yourself to bypass that warning.
  3. Use separate robot or service credentials. A CI runner needs push permission to one project, not admin permission to your whole registry.
  4. Set retention before storage becomes a problem. Keep immutable release tags, prune untagged layers, and test cleanup on non-critical repositories first.
  5. Back up registry data and metadata together. A volume snapshot without the platform database is not a complete Harbor backup.

If you administer the registry remotely from untrusted networks, do not expose its admin panel just because it has HTTPS. Use a VPN or private overlay network. That keeps the management surface off the public internet entirely.

🚀NordVPN

Manage private infrastructure over an encrypted VPN instead of exposing registry administration to public networks.

Get NordVPN →

Affiliate link — we may earn a commission at no extra cost to you.

My decision tree

  • I only need a private endpoint for CI: Docker Distribution.
  • I want a small, modern registry with a UI: Zot.
  • I need scanning, projects, policy, replication, and multiple teams: Harbor.
  • I am unsure: Zot, with one private project and a documented backup. You can migrate when the requirements become real.

Do not start with Harbor because it is the biggest name. Start with the smallest registry that lets you deploy confidently, then add controls when you can name the incident they would prevent.

The useful next step is simple: push one image you built yourself to a private registry, deploy it by digest, and write down how you would restore it. That exercise exposes more about your delivery chain than another weekend spent comparing dashboards.


For related hardening, read Docker network security for self-hosters, rootless Docker, and validating Docker Compose before deployment.

Stay in the loop 📬

Get self-hosting tutorials, tool reviews, and infrastructure tips delivered to your inbox. No spam, unsubscribe anytime.

Join 0 self-hosters. Free forever.