Years ago, I used Artifactory to create a simple private registry that had private and proxy repos behind a grouped repo to make the repo look like one. The group repo defined which repo should be the default write repo. This was nifty, though managing SSL wasn't fun, and then I was running Artifactory on a VM.

Forward to today, where we have nice tools like Traefik and Nexus3. Traefik, easily integrates into my DNS server to allow for dynamic generation of SSL for my internal services. Nexus for my personal use is OpenSource and fits my budget for caching and hosting repos.

Why do I need SSL for my private services? First, I can. Second, browsers are trying to be more and more secure and having to save private SSL certs all the time are annoying.

I'm running my repo behind a Traefik proxy, with integration with Let's Encrypt to provide my SSL cert. I can quickly add a label in my docker stack for nexus3: traefik.frontend.rule=Host:nexus.cool.terzo.org. With this 1 label line I have an SSL cert and A frontend port to start serving out my nexus repo.

Digging into Nexus3's docker registry, you have to expose private ports to enable a docker registry. This is due to how docker does all it's API calls expecting to be at the top level (https://docs.docker.com/registry/spec/api/) of a server.

When setting this up in nexus3, you create a local docker repo, which is your private repo. Next create a proxy repo that points to say the hub. Finally create an overlay group that combines those repos into one. The proxy repo "ready-only" has to have it's own port (18078) then the writing repo needs it's own port (18088) as well.

Initially I started with:

  • registry.cool.terzo.org for docker pull.
  • registry-write.cool.terzo.org for uploading registries.

This sucks, having to tag and and push with different host names gets's old.

Using the magic of Traefik, you can route the docker api based on the API methods.

Adding these labels to the nexus3 compose file:

labels:
  - traefik.docker.network=proxy
  - traefik.repo.port=8081
  - traefik.repo.frontend.rule=Host:nexus.cool.terzo.org
  - traefik.repo.frontend.redirect.entryPoint=https
  - traefik.docker.port=18078
  - traefik.docker.protocol=http
  - traefik.docker.frontend.rule=Host:registry.cool.terzo.org;Method:GET,HEAD
  - traefik.docker.frontend.redirect.entryPoint=https
  - traefik.docker-write.port=18088
  - traefik.docker-write.protocol=http
  - traefik.docker-write.frontend.rule=Host:registry.cool.terzo.org;Method:PUT,DELETE,POST,PATCH
  - traefik.docker-write.frontend.redirect.entryPoint=https

What this does is creates 3 backends, the default, which is the standard nexus 8081 http access. You can hit nexus.cool.terzo.org and reach the default app with SSL. Next, I created a frontend docker that points to nexus on 18078, the read-only port. I'm sending HTTP GET and HEAD methods to this port. At this point docker pull registry.cool.terzo.org/alpine:3.7 will work. Adding the final frontend docker-write pointing to 18088 accepting PUT, DELETE, POST, and PATCH methods. This allows for docker push registry.cool.terzo.org/myspace/image:tag to work.

Enjoy!