8.0 KiB
Nexus — Artifact Repository & Docker Registry
Sonatype Nexus3 serves as the homelab's self-hosted artifact repository and Docker registry pull-through cache, fronted by Traefik.
See docker-compose/nexus/ for the deployment files.
Why
Docker Hub rate limits, regional access issues (see GitLab CI/CD for the registry.gitlab.com geo-block), and the desire for a single place to host internal Docker images all pointed toward a local registry. Nexus3 does that plus more — it can proxy Docker Hub, host private images, and serve as a general Maven/npm/pypi repository if needed.
What it does
| Capability | Purpose |
|---|---|
| Docker Hub pull-through cache | Containers pull from docker.home.server instead of Hub directly — avoids rate limits and works even when Hub is slow or blocked |
| Docker registry (group repo) | Single endpoint that combines the Hub cache + any private repos |
| Artifact repository | Maven, npm, pypi, raw, and other formats — ready for future use |
| Web UI | Browse cached images, manage repositories, view connection status |
Setup
First boot
cd docker-compose/nexus
cp .env.example .env # edit with your values
docker compose up -d
Nexus takes 1-2 minutes to fully start (JVM warmup). The health check waits up to 90 seconds before checking.
Initial admin password
The admin password is set via NEXUS_SECURITY_INITIAL_PASSWORD in the .env file. After first login at https://nexus.home.server, Nexus prompts you to change it.
Important: The initial password in .env is only used on first boot. After that, Nexus stores its own password in its data volume. Changing the .env value afterward does nothing — you change the password through the Nexus UI or REST API.
Docker registry setup
The Docker registry requires creating a connector port inside Nexus after first boot:
- Log in to the Nexus web UI
- Go to Server Administration → Docker
- Create a HTTP connector on port
5005(or whatevernexus_docker_connector_portis set to in.env) - Create a Docker (proxy) repository pointing at Docker Hub
- Create a Docker (group) repository that includes the proxy repo
- The group repo is what clients pull from — its external URL is
https://docker.home.server
Configuring Docker daemon on clients
Add the registry as an insecure registry (since it uses a self-signed cert):
{
"insecure-registries": ["docker.home.server"]
}
Or use the --registry-mirror flag in the Docker daemon config (set via the Ansible docker role).
Architecture
┌──────────────────────────────────────────┐
│ Nexus3 (port 8081) │
│ │
│ ┌─────────────┐ ┌──────────────────┐ │
│ │ Docker Hub │ │ Docker Group │ │
│ │ Proxy Repo │◄─┤ (pull-through │ │
│ │ │ │ cache + private)│ │
│ └─────────────┘ └───────┬──────────┘ │
│ │ │
│ ┌────────────────────────┴──────────┐ │
│ │ HTTP Connector :5005 │ │
│ └────────────────────────┬──────────┘ │
└───────────────────────────┼──────────────┘
│
┌────────┴────────┐
│ Traefik :443 │
│ docker.home. │
│ server │
└────────┬────────┘
│
┌────────┴────────┐
│ Clients pull │
│ from here │
└─────────────────┘
Two Traefik routes
Nexus exposes two domains through Traefik:
| Domain | Backend Port | Purpose |
|---|---|---|
nexus.home.server |
8081 | Web UI and REST API |
docker.home.server |
5005 | Docker registry (pull-through cache) |
Both are routed via Traefik labels in the compose file — no dynamic config YAML needed since Nexus is a proper Docker container on web_net.
Resource usage
Nexus is the heaviest single container in the stack. Current tuning for an 8GB / DDR3 / 4-core host:
| Setting | Value | Notes |
|---|---|---|
Heap (-Xms/-Xmx) |
1536m | Below Sonatype's 8GB recommendation but reasonable |
| Direct memory | 512m | For blob store I/O |
| Memory limit | 2560m | Hard cap — container can't exceed this |
| Memory reservation | 1536m | Soft guarantee for scheduling |
With the rest of the stack running, free -h typically shows ~3.3GB available. Nexus idles around 1-1.5GB after warmup.
Do not run Nexus alongside GitLab Omnibus — together they exceed the host's RAM. The Ansible provisioning playbook can set up either one; pick based on what you need more.
Networking
web_net— front-facing network shared with Traefik (HTTPS access)app_net— internal network for app-to-registry communication (GitLab CI, other services that push/pull images)
The two-network setup keeps the registry accessible to internal services without exposing it through Traefik unnecessarily — though the Docker registry route IS exposed via Traefik for convenience.
Security notes
- Admin password is set on first boot via environment variable, then managed through the Nexus UI
- Self-signed TLS cert — clients need
insecure-registriesor equivalent trust configuration - The Docker registry endpoint is LAN-only via Pi-hole DNS
- Nexus stores all data in a Docker named volume (
nexus_data) — back this up regularly - REST API access is available at
https://nexus.home.server/service/rest/— protected by Nexus authentication
Backups
The nexus_data volume contains all repository data, configuration, and the database. To back up:
docker compose stop nexus
tar czf /backups/nexus-$(date +%Y%m%d).tar.gz -C /var/lib/docker/volumes/nexus_data _data
docker compose start nexus
For a hot backup (without stopping), use the Nexus REST API task system to create a backup task through the UI.
Troubleshooting
- Slow startup — Nexus takes 1-2 minutes on first boot. The health check has a 90-second
start_periodbefore it starts checking. Be patient. - "Connection refused" on docker.home.server — the Docker registry connector port (5005) is created inside Nexus after first boot through the UI. Until that's done, the Docker registry route returns 500.
- Memory pressure — if the host starts swapping, reduce
nexus_heapandnexus_mem_limit. Nexus works fine with less memory if you're only using it as a Docker pull-through cache. - Geo-blocked registries — if you're proxying
registry.gitlab.comand it's geo-blocked (see GitLab CI/CD), the proxy repo will fail. Use a different upstream or skip that proxy.
Lessons learned
- Nexus's Docker registry requires a two-step setup: deploy the container first, then create the HTTP connector and repositories through the web UI. There's no way to fully automate the initial repo setup via environment variables — the REST API works but the UI is simpler for first-time setup.
- Running Nexus alongside GitLab Omnibus on an 8GB host is not viable — both are JVM-based and hungry for memory. Pick one, or upgrade the hardware.
- The pull-through cache pattern is genuinely useful even on a home network — it's not just about rate limits, but also about having a local copy when Hub is slow or you're working offline.