Self-Host Nexus Repository to Beat Docker Hub Rate Limits
Your pipeline goes red at three in the afternoon. Nothing changed in the code. The logs say toomanyrequests: You have reached your pull rate limit, and by the time you've finished reading the error it works again, so you re-run the job and move on.
Then it happens again next week.
Docker Hub allows 100 pulls per six hours for anonymous users, and that quota is counted per IP address. Your CI runners almost certainly share one NAT gateway, which means the whole fleet spends a single budget. Authenticating as a free Docker Personal account raises it to 200 per six hours, which buys you time rather than a fix.
The actual fix is to stop pulling from the internet on every build.
What a Repository Manager Does
Nexus Repository sits between your builds and the outside world. The first time anyone asks for postgres:18, Nexus fetches it from Docker Hub and keeps a copy. Every request after that is served from your own disk.
The mental model that makes Nexus click is its three repository types:
| Type | What it's for |
|---|---|
| Proxy | Mirrors an upstream registry and caches what you pull. This is the one that solves rate limits. |
| Hosted | Stores artifacts you publish yourself. Your internal libraries and images live here. |
| Group | One URL that fans out across several repositories in order. Point your tooling here and forget the rest. |
That third one is what people miss. You don't configure npm to check your private registry and then fall back to the public one. You create a group containing both, point .npmrc at the group, and Nexus resolves in order. One URL for developers, one place to change policy.
It speaks Maven, npm, Docker, PyPI, NuGet, RubyGems, Helm, Go, apt and yum, among others. In practice this means one service replaces the four different caching hacks your team accumulated.
The Side Effect Nobody Mentions
Rate limits are what gets you to install it. Reproducible builds are why you keep it.
When an upstream package is yanked, a registry has an outage, or a maintainer force-pushes a tag, your builds keep working because you already have the bytes. That's a quieter benefit than "CI stopped failing" but it's the one that matters at three in the morning.
Deploying It
Nexus is a Java application, and sizing it like a small Go binary is the most common mistake.
- Java 21 is required. Sonatype tests on OpenJDK.
- Memory: allocate up to two-thirds of available RAM to Nexus, leaving a third for the system. Sonatype's smallest deployment profile assumes 8 GB RAM and 2 CPUs. Below that you will be fighting the JVM rather than using the product.
- Disk: at least 4 GB free at all times. The application itself is around 390 MB; the data directory grows with whatever you cache, so plan generously.
- Port 8081 serves the web UI by default. Docker registry endpoints get their own connector ports, configured per repository.
That last point catches people. A Docker proxy repository isn't reachable on 8081 alone. You assign it an HTTP connector port, then point your daemon at that.
Read This Before You Commit
The free edition was renamed from OSS to Community Edition in early 2025, starting with version 3.77.0. It remains open source under the Eclipse Public License, so this is a rename rather than a rug-pull. But Community Edition carries usage limits, and they are not generous:
| Limit | Community Edition |
|---|---|
| Total components | 40,000 |
| Requests per day | 100,000 |
Two things worth knowing about those numbers.
They went down, not up. Version 3.87.0 cut the component ceiling from 100,000 to 40,000 and daily requests from 200,000 to 100,000. If you're reading an older tutorial quoting the higher figures, it's out of date.
Failed requests count. A misconfigured client retrying against a 404 burns your daily budget just as effectively as a successful pull.
When you cross either threshold, Nexus doesn't fall over. It pauses the addition of new components until usage drops back under both limits, so existing artifacts keep serving while new ones stop landing. Confusing if you don't know it's happening, which is exactly why it belongs in an article rather than a footnote.
For a small team proxying a handful of registries, 40,000 components is a lot of room. For a large monorepo shop pulling transitive Maven dependencies, you will find the ceiling.
Troubleshooting
Docker client can't log in to your proxy. Check you're pointing at the repository's connector port, not 8081.
Builds still hit Docker Hub. Something is bypassing the proxy. Check for hardcoded docker.io/ prefixes in your compose files and Dockerfiles.
"New components are not being added". You've hit a Community Edition limit. Check the Usage Center in the UI.
Nexus is slow or the JVM is thrashing. Almost always undersized memory. Revisit the two-thirds rule before you tune anything else.
Cached artifacts vanish unexpectedly. Check your cleanup policies. Proxy repositories have a "not recently used" eviction that is easy to set too aggressively.
Running It
Nexus Repository on Elestio starts at $30/month fully managed, with SSL, automated backups, monitoring and updates handled, across Hetzner, DigitalOcean, Vultr, Linode, Scaleway, Netcup, AWS or your own VM. Size it against Sonatype's 8 GB guidance rather than the bare minimum, because this is a JVM service and it will use what you give it.
Set up one Docker proxy repository first. Point a single project at it, watch the pull counts drop, and expand from there. That's a thirty-minute change that removes an entire category of intermittent CI failure.
Thanks for reading ❤️ See you in the next one 👋