#2474: Private Container Registries: Docker Hub vs GHCR vs Self-Hosting

Comparing Docker Hub, GitHub Container Registry, and self-hosted options for private container storage.

0:000:00
Episode Details
Episode ID
MWP-2632
Published
Duration
25:28
Audio
Direct link
Pipeline
V5
TTS Engine
chatterbox-regular
Script Writing Agent
deepseek-v4-pro

AI-Generated Content: This podcast is created using AI personas. Please verify any important information independently.

Private Container Registries: Docker Hub, GHCR, and Self-Hosting Compared

The Multi-Architecture Challenge

Building containers on a powerful x86 machine and deploying to Raspberry Pis introduces a fundamental mismatch: your build machine produces amd64 images, but the Pi needs arm64 (or arm/v7 for older models). The bridge is Docker Buildx, which uses QEMU emulation to build for multiple architectures from a single command. A single docker buildx build --platform linux/amd64,linux/arm64 --push produces a manifest list — when the Pi pulls the image, Docker automatically selects the arm64 variant; when your x86 server pulls it, it gets amd64. Same tag, same registry, no confusion.

However, QEMU emulation is slow. For simple Go binaries or small Python apps, the slowdown is negligible. For anything with heavy compilation — Rust, C++, large dependency trees — the ARM build can take several times longer than native amd64 builds. Serious users often move to native ARM runners in CI, Apple Silicon Macs, or GitHub Actions ARM runners.

Docker Hub: Simple but Restrictive

Docker Hub's free tier offers exactly one private repository. Public repos are unlimited, but private storage is capped at one. Pull rate limits apply: 200 pulls per six hours for authenticated free users, stricter for anonymous pulls. Multiple Pis or frequent CI pulls can hit these limits quickly.

The Pro tier costs $5/month and unlocks unlimited private repos. Storage recommendations are under 1GB per repo, strongly under 5GB — multi-architecture images with multiple variants can exceed this quickly. Docker Hub remains the "just works" option with excellent search and discovery, purpose-built for Docker images.

GitHub Container Registry: "Unlimited" but Misleading

GHCR markets unlimited private repositories, but storage across all GitHub Packages (including Actions artifacts and caches) is capped at 500MB on the free tier, with 1GB monthly data transfer out. Transfers within GitHub Actions are free, but pulling images to an external Raspberry Pi counts against the cap.

A notable security incident in 2022 saw a researcher discover that GHCR was leaking private repository names through HTTP response headers. The bug, caused by Azure Blob Storage metadata leaking source repository names during internal blob copies, was fixed within months. GitHub paid a $617 bounty. The broader concern: GHCR uses a single Azure Blob Storage bucket for all customers, creating multi-tenant metadata risks.

Authentication quirks also persist — pulling private GHCR images into Kubernetes clusters (especially minikube) can produce "unauthorized" errors requiring finicky imagePullSecrets configuration.

Self-Hosting: Three Options

CNCF Distribution (formerly Docker Distribution) is the lightweight base. Run as a single container, point at S3/NFS/GCS/Azure Blob storage. Minimal features: no web UI, basic auth only, no vulnerability scanning.

Harbor is CNCF-graduated with full RBAC, vulnerability scanning, image replication, and a web UI. Harbor Satellite is specifically designed for edge/IoT — a lightweight local registry that syncs with a central instance, ideal for Raspberry Pis with spotty connectivity.

Sonatype Nexus Repository handles multiple artifact formats (Docker, Maven, PyPI) and supports image signing for supply chain security.

A practical 15-minute setup guide exists: deploy the registry:2 image behind Traefik with Let's Encrypt TLS, add htpasswd auth, and pair with Watchtower for auto-updates. The catch is everything after those 15 minutes — garbage collection (layers accumulate forever unless manually cleaned), TLS certificate renewal, backups, disaster recovery, and bandwidth costs.

The Verdict

For a solo developer with one or two Pis, paying $5/month for Docker Hub Pro removes all operational burden: unlimited private repos, no pull rate limits, no garbage collection, no TLS management. Self-hosting eliminates vendor lock-in but requires ongoing maintenance. The choice comes down to whether you value zero operational overhead or complete independence from external dependencies.

Downloads

Episode Audio

Download the full episode as an MP3 file

Download MP3
Transcript (TXT)

Plain text transcript file

Transcript (PDF)

Formatted PDF with styling

#2474: Private Container Registries: Docker Hub vs GHCR vs Self-Hosting

Corn
Daniel sent us this one — he's building containers on a beefy x86 machine and deploying to Raspberry Pis, which means he's wrestling with the multi-architecture problem. But the real question is about private container registries. He's looking at three options: Docker Hub with its stingy free tier, GitHub Container Registry with its unlimited repos but security question marks, and self-hosting as the pure play. There's a lot to unpack here.
Herman
Oh, this is a great one. And before we dive in — quick note, today's script is being generated by DeepSeek V four Pro. So if I sound unusually coherent, that's why.
Corn
I was going to say, you seem suspiciously well-rested.
Herman
Alright, let's get into the build workflow first, because that's the part most people gloss over. If you're building on a strong machine and targeting a Raspberry Pi, you can't just run docker build and call it a day. Your x86 machine produces amd64 images. The Pi needs arm64 — or arm/v7 if you're on an older Pi 3B. The tool that bridges this gap is Docker Buildx.
Corn
Buildx is what, exactly? I've seen the commands but I've never had to use it myself.
Herman
It's Docker's multi-platform build engine. You create a builder that supports multiple architectures, typically by pulling in QEMU for emulation, and then you run a single command — docker buildx build --platform linux/amd64,linux/arm64 --tag yourimage:latest --push. — and it produces what's called a manifest list. When the Pi pulls that image, Docker automatically selects the arm64 variant. When your x86 server pulls it, it gets amd64. Same tag, same registry, zero confusion.
Corn
The tag is the same, but the actual bits are architecture-specific. That's elegant. How slow is the QEMU emulation for ARM builds on x86?
Herman
That's where it gets interesting. It works, but it's slow. Emulating ARM on x86 with QEMU is not a fast path. For a simple Go binary or a small Python app, you probably won't notice. But if you're compiling anything substantial — a Rust project, a C++ application, anything with heavy dependencies — the ARM build can take several times longer than the native amd64 build. That's why a lot of serious users end up moving to native ARM runners in CI, or using something like GitHub Actions with ARM runners, or even building directly on an Apple Silicon Mac since those are ARM-native.
Corn
The "build on strong machine, push to Pi" workflow works at small scale, but it has friction. That's worth flagging upfront. Let's start with Docker Hub, since it's the default everyone knows.
Herman
Docker Hub's free tier is brutally simple. You get one private repository. That's it. Public repos are unlimited, but if you want to keep your containers private, you get exactly one. And there are pull rate limits — two hundred pulls per six hours for authenticated free users, and much stricter limits for anonymous pulls. If you're running multiple Pis or you're pulling images frequently in a CI pipeline, you can hit those limits fast.
Corn
One private repo. That's almost comical. What does it cost to get more?
Herman
The Pro tier starts at five dollars a month and gives you unlimited private repos. Team and Business tiers go up from there. It's not expensive in absolute terms, but for a solo developer or someone just tinkering with a Raspberry Pi cluster, five dollars a month for something that feels like it should be table stakes can sting. Docker Hub does have advantages though — it's purpose-built for Docker images, the search and discovery experience is excellent, and they now host curated catalogs for AI models, MCP servers, and hardened images. It's the "just works" option.
Corn
The storage situation?
Herman
Docker recommends keeping repos under one gigabyte, and strongly under five gigs. Push past that and you start running into problems. So if your images are large — and multi-architecture images with multiple variants can add up — Docker Hub might not be the right home anyway, even if you pay.
Corn
Alright, so Docker Hub is simple but restrictive. Now let's talk about the one that markets itself as the generous alternative — GitHub Container Registry. Unlimited private repos, right?
Herman
This is where the "unlimited" marketing gets tricky. Yes, GHCR gives you unlimited private repositories. But the storage across all GitHub Packages — that includes GHCR, Actions artifacts, and caches — is capped at five hundred megabytes on the free tier. Five hundred meg. And you get one gigabyte of monthly data transfer out. Transfers within GitHub Actions are unlimited, but if you're pulling images to a Raspberry Pi sitting on your desk, that's data transfer out, and it counts against your cap.
Corn
Unlimited repos, but a five hundred meg storage cap. That's a hard contradiction. You could have a hundred private repos, each with five megabytes of images, and you're done. That's not unlimited in any meaningful sense.
Herman
A lot of developers discover this the hard way — they push a few multi-architecture images, each with two or three variants, and suddenly they're hitting the storage ceiling with no warning beyond a billing page they probably didn't read. Docker Hub's "one private repo" is honestly more transparent. You know exactly what you're getting. GHCR's "unlimited repos" is technically true but practically misleading.
Corn
Then there's the security angle. Daniel specifically flagged security concerns with GHCR.
Herman
So there was a notable incident in twenty twenty-two. A security researcher named Jason Hall — he's at Chainguard, which does supply chain security — discovered a bug in GHCR that was leaking the names of private repositories through HTTP response headers. GHCR is backed by a single Azure Blob Storage bucket, and when blobs were copied internally, Azure's metadata was leaking the source repository name. Even for private repos.
Corn
Someone could discover that a private repo existed and what it was called, just from the headers?
Herman
They couldn't access the image layers — you'd still need the SHA256 hash for that — but knowing that a repo called "acmecorp-production-deploy" exists and is private tells an attacker where to look. It's reconnaissance. Phishing targets, credential-stuffing targets, places to search for accidentally exposed secrets. The bug was reported in March twenty twenty-two, confirmed within three days, fixed by May, and the disclosure was cleared in January twenty twenty-three. GitHub paid a six hundred and seventeen dollar bounty.
Corn
Six hundred and seventeen dollars for a data leak from private repos.
Herman
And the broader question is structural. GHCR uses a single Azure Blob Storage bucket for all customers. Multi-tenant architecture always carries this risk — metadata leaking between tenants in ways the provider didn't anticipate. The bug was fixed, but it makes you wonder: what other metadata channels exist that haven't been discovered yet? If you're a solo developer with a hobby project, this probably doesn't matter. If you're building something where the existence of the project itself is sensitive, it very much does.
Corn
GHCR has authentication quirks too, right? I've seen people complain about pulling private images into Kubernetes.
Herman
There are persistent reports of "unauthorized" errors when pulling private GHCR images into Kubernetes clusters — minikube especially. You need to configure imagePullSecrets with base64-encoded authentication, and the setup is finicky. It's not broken, but it's not seamless either. Docker Hub's authentication is comparatively straightforward because it's the default everywhere.
Corn
Alright, so Docker Hub is honest but restrictive, GHCR is generous on paper but stingy in practice with a security scar. That brings us to option three: self-hosting. What does the landscape look like?
Herman
Three main open-source contenders. The simplest is the CNCF Distribution registry — it used to be called Docker Distribution, sometimes just called "The Registry." It's the lightweight OCI-compliant base that powers Docker Hub itself. You run it as a single container, point it at a storage backend — S3, NFS, Google Cloud Storage, Azure Blob — and you're done. It's minimal, it's fast, and it has almost no features out of the box. No web UI, no access control beyond basic auth, no vulnerability scanning.
Corn
It's the "I just need a bucket for my images" option.
Herman
If you want more, there's Harbor. Harbor is a CNCF-graduated project — full-featured, with policy-driven role-based access control, vulnerability scanning, image replication, and a proper web UI. They recently launched something called Harbor Satellite, which is designed specifically for edge and IoT environments. You run a lightweight local registry at the edge, and it syncs with a central Harbor instance, which is perfect if you have inconsistent network connectivity.
Corn
That edge use case is actually compelling for Raspberry Pi deployments. If your Pis are in the field with spotty connections, having a local registry cache could be the difference between a working deployment and a failed one.
Herman
And the third option is Sonatype Nexus Repository. It's a multi-format artifact manager — Docker, Maven, PyPI, you name it. If you're already using Nexus for other artifacts, adding Docker registry support is natural. It also has image signing support, which is nice for supply chain security.
Corn
What about the practical setup? Daniel's a developer, not a full-time ops person. Can he actually get a self-hosted registry running in a reasonable amount of time?
Herman
There's a great guide from Thomas Bandt — March twenty twenty-six — that walks through a fifteen-minute setup. You deploy the registry:2 image behind Traefik as a reverse proxy, with Let's Encrypt for TLS certificates, add htpasswd authentication for basic access control, and pair it with Watchtower for automatic container updates on the deployment server. The whole stack — registry, Watchtower, Traefik — runs on a single machine.
Corn
Fifteen minutes sounds optimistic. What's the catch?
Herman
The catch is everything that comes after the fifteen minutes. Garbage collection is the big one. The registry keeps every pushed image forever unless you manually delete via the API and run bin/registry garbage-collect. There's no built-in retention policy. You push an image, you push a new version, the old layers sit there indefinitely. Over time, your storage fills up with orphaned blobs, and you have to remember to clean house.
Corn
It's not just "set it and forget it.
Herman
Not at all. You're also on the hook for TLS certificate renewal — Let's Encrypt automates most of it, but when it breaks, you're the one fixing it at 2 AM. Backups are your responsibility. Disaster recovery is your problem. If the server dies, your registry is gone unless you've been backing up the storage backend. And bandwidth costs — if you're self-hosting on a cloud VM, you're paying for every gigabyte of image pulls. On a Raspberry Pi at home, that's less of an issue, but then you're dealing with home internet reliability.
Corn
The real question is: for a solo developer with a Raspberry Pi or two, is self-hosting worth the operational overhead, or is paying five bucks a month for Docker Hub Pro actually the smarter move?
Herman
I think the answer depends on what you value. If you want zero operational burden, pay the five dollars. Docker Hub Pro gives you unlimited private repos, removes the pull rate limits, and you never think about garbage collection, TLS certificates, or backups. Five dollars a month is probably less than the value of your time if you spend even one hour a month maintaining a self-hosted registry.
Corn
That's the pragmatic take. But there's a counterpoint — self-hosting removes external dependencies and vendor lock-in. If Docker Hub changes its pricing, or has an outage, or decides to deprecate something, you're not affected. You own the infrastructure.
Herman
That's true, and it matters more at scale. If you're running a small business with a dozen Pis in the field, the calculus shifts. A self-hosted registry with Harbor Satellite at the edge gives you resilience that a cloud registry can't match. And if you're dealing with sensitive code — proprietary algorithms, unreleased products — the GHCR metadata leak is a cautionary tale about what can go wrong when your private artifacts live on someone else's multi-tenant infrastructure.
Corn
Let's talk about that GHCR leak a bit more, because I think it's the most interesting part of this whole comparison. The bug was in Azure Blob Storage metadata propagation, right? When blobs were copied internally, the source repository name leaked. That's not a GHCR application bug — that's a cloud infrastructure behavior that GitHub apparently didn't anticipate.
Herman
And the implication is that when you use any cloud-hosted registry, you're trusting not just the registry software but the entire underlying cloud stack — storage, networking, metadata services — to properly isolate your data. The GHCR bug was fixed, but it was present for at least six weeks before it was discovered, and it took an external researcher to find it. How many similar bugs exist in ECR, in Artifact Registry, in ACR, that nobody's found yet?
Corn
That's the uncomfortable question. And it's not unique to registries — it's the fundamental tradeoff of cloud services. But registries feel different because they hold your deployable artifacts. If someone knows what private repos you have, they know what you're building, what your infrastructure looks like, what dependencies you're pulling in. It's a reconnaissance goldmine.
Herman
The supply chain angle is worth mentioning too. Every registry — cloud or self-hosted — is vulnerable to typosquatting, where someone publishes a malicious image with a name similar to a popular one. Cached image staleness is another issue — you pull an image, it gets cached, and you don't realize there's a newer version with a security patch. These problems exist regardless of where you host.
Corn
Security-wise, self-hosting doesn't magically solve everything. It removes the multi-tenant metadata leak risk, but you still have to worry about access control, image signing, and supply chain integrity.
Herman
And if you're self-hosting on a Raspberry Pi that's also running other services, your attack surface might actually be larger than if you used a managed registry. Docker Hub has a security team. Your Pi has...
Corn
Alright, let's get practical for Daniel and anyone else in this situation. What's the actual recommendation?
Herman
I'd break it into three tiers. If you're a solo developer with one or two projects, just pay for Docker Hub Pro. Five dollars a month, zero maintenance, and you get the best Docker-native experience. The pull rate limits go away, you get unlimited private repos, and you never think about garbage collection. It's the boring, correct answer.
Corn
If you're cost-sensitive or philosophically opposed to paying for things that used to be free?
Herman
Then self-host the CNCF Distribution registry. The fifteen-minute Traefik-plus-Watchtower setup is real and it works. But budget time for maintenance — set a calendar reminder to run garbage collection monthly, make sure your TLS certificates are auto-renewing, and have a backup strategy. If you're already running a home server or a Pi cluster, this is a natural addition. If you're setting up a server just for the registry, the electricity and time probably cost more than five dollars a month.
Corn
Where does GHCR fit?
Herman
GHCR makes sense if you're already deep in the GitHub ecosystem and your images are small. If all your containers are under a hundred megabytes and you're using GitHub Actions for CI/CD, the storage cap won't bite you and the data transfer is free within Actions. The unlimited private repos are genuinely useful if you have a lot of small projects. But the five hundred meg storage cap is a hard ceiling, and the twenty twenty-two leak is a reminder that "free" sometimes means "you're not the customer, you're the product testing the infrastructure.
Corn
There's one more angle I want to explore — the multi-architecture build pipeline itself. You mentioned earlier that QEMU emulation is slow for ARM builds on x86. What's the alternative if you're building frequently?
Herman
The serious approach is to use native ARM runners. GitHub Actions now has ARM runners available. You can set up a matrix build in your CI pipeline — amd64 on x86 runners, arm64 on ARM runners — and then merge the manifests with docker buildx imagetools create. The builds are fast because they're native, and you can push directly to whatever registry you're using.
Corn
If you're not using GitHub Actions?
Herman
Apple Silicon Macs are ARM-native and increasingly common. If you have an M1, M2, or M3 Mac, you can build ARM images natively at full speed. The amd64 build will be emulated and slow, but for Raspberry Pi deployments, you probably only care about the arm64 variant. You can build single-architecture images and skip the multi-platform complexity entirely.
Corn
That's actually a simpler workflow for the solo developer case. Build on your Mac, push to your registry, pull on the Pi. No emulation, no manifest lists, no complexity.
Herman
The multi-architecture workflow is elegant when you need to support both amd64 and arm64 from a single tag, but if your entire deployment target is Raspberry Pis, you're overcomplicating things by building amd64 variants at all. Just build arm64 and move on.
Corn
The advice might be: simplify before you optimize. If everything's running on ARM, don't build x86 images. If you have one or two private images, Docker Hub's limitations might not actually matter. If GHCR's storage cap is bigger than your total image size, the "unlimited" trap doesn't affect you.
Herman
And that's the thing about infrastructure decisions — the best choice depends on your actual numbers, not the marketing. Measure your image sizes. Count your private repos. Estimate your pull frequency. Then pick the option whose constraints you'll never notice, rather than the one with the best-sounding feature list.
Corn
One more thing on self-hosting. You mentioned garbage collection as the big operational pain point. Are there tools that automate this?
Herman
Harbor has built-in retention policies and garbage collection scheduling. That's one of the reasons to choose Harbor over the bare registry:2 image if you go the self-hosted route. You can set policies like "keep the last ten versions of each image" or "delete images older than thirty days," and Harbor handles the cleanup automatically. The CNCF Distribution registry requires you to script this yourself — call the API to list and delete tags, then run the garbage collection binary. It's not hard, but it's another thing to maintain.
Corn
Harbor is the "I want features but I still want to self-host" sweet spot.
Herman
Yes, with the caveat that Harbor is heavier. The registry:2 image is tiny — you can run it on a Raspberry Pi without breaking a sweat. Harbor needs more resources. For a single developer with a Pi cluster, Harbor might be overkill. For a small team or a business, it's probably the right call.
Corn
Alright, let's summarize the landscape. Docker Hub: one private repo on free, five bucks a month for unlimited, best Docker-native experience, pull rate limits on free tier. GHCR: unlimited private repos but five hundred meg storage cap, one gig monthly data transfer, past security incident involving metadata leakage, authentication quirks with Kubernetes. Self-hosted: no external dependencies, no rate limits, full control, but you own the maintenance, garbage collection, backups, and TLS.
Herman
The multi-architecture build workflow: use Buildx with QEMU for occasional builds, native ARM runners or Apple Silicon for frequent builds, and consider whether you even need multi-architecture if your entire fleet is ARM.
Corn
That's a clean summary. Daniel, hopefully that gives you enough to make the call. And for everyone else — measure your actual usage before you optimize for constraints you don't have.
Herman
Now: Hilbert's daily fun fact.
Herman
The national flag of Nepal is the only non-quadrilateral national flag in the world. It consists of two overlapping triangular pennants.
Corn
Where does this leave us practically? Let's give listeners a decision framework they can apply to their own projects.
Herman
Start by answering three questions. First, how many private container images do you actually have? If it's one or two, Docker Hub's free tier is fine. If it's more, move to question two.
Corn
Question two is total storage?
Herman
Add up the size of all your images across all architectures. If it's under five hundred megabytes, GHCR will work — just be aware of the security history and the authentication quirks. If it's over five hundred megs, GHCR's free tier is a non-starter.
Corn
Question three is your tolerance for operational overhead.
Herman
If the answer to "do I want to manage a server?" is no, pay the five dollars for Docker Hub Pro and move on with your life. If you're already running a home server and you enjoy this stuff, self-host with registry:2 or Harbor. The fifteen-minute setup is real, but the ongoing maintenance is also real.
Corn
I think there's also a fourth question that's worth asking: how sensitive is the code you're containerizing? If the existence of the project itself is confidential, the GHCR metadata leak — even though it's fixed — is a reminder that cloud registries have attack surfaces you can't control. Self-hosting eliminates that class of risk entirely.
Herman
That's fair. And for most hobby projects, it doesn't matter. But if you're building something for a client under NDA, or you're working on a prototype that hasn't been announced, the operational burden of self-hosting might be worth the confidentiality guarantee.
Corn
The decision tree is: count your repos, measure your storage, assess your sensitivity, and be honest about your willingness to do server maintenance. That's a better framework than "which registry is best.
Herman
One thing I want to emphasize — none of these options are bad. Docker Hub is solid. GHCR works for its target use case. Self-hosting is empowering and educational. The worst outcome is analysis paralysis where you spend more time choosing a registry than building your application.
Corn
That's the real trap. Pick one, push your images, deploy to your Pi, and iterate. You can always migrate later — it's just a docker pull and docker push away.
Herman
Registries are commodity infrastructure at this point. The switching cost is low. Don't overthink it.
Corn
One last thought — Daniel mentioned he's building on a strong machine and deploying to a lightweight server. The registry question is important, but the build workflow is equally important. If you're cross-compiling or emulating, get that pipeline solid before you worry about where the images live.
Herman
A slow, flaky build pipeline will cause more pain than a suboptimal registry choice. Invest in getting Buildx configured correctly, or set up native ARM builds on Apple Silicon if you have it. The registry is just storage. The build is where the complexity lives.
Corn
Alright, I think we've covered this from every angle. Docker Hub, GHCR, self-hosting — the tradeoffs are clear, the decision framework is practical, and the build workflow context makes it actionable. Thanks to Daniel for the prompt, and thanks to Hilbert Flumingtop for producing.
Herman
This has been My Weird Prompts. If you enjoyed this episode, leave us a review wherever you listen — it helps other people find the show.
Corn
We're back next time with whatever Daniel throws at us.

This episode was generated with AI assistance. Hosts Herman and Corn are AI personalities.