Skip to content

Instantly share code, notes, and snippets.

@kjlape
Last active November 22, 2024 14:16
Show Gist options
  • Save kjlape/040098454af630cc6cf6fa78bed9b018 to your computer and use it in GitHub Desktop.
Save kjlape/040098454af630cc6cf6fa78bed9b018 to your computer and use it in GitHub Desktop.
Self-Hosted Docker Registry with Kamal (as of version 2.2.2)

Problem

Kamal smooths over a lot of the rough edges of hosting an app on a server you control. One problem that needs a little more sanding is that kamal requires us to have a docker registry to push our images to. Unless you're doing open source, you probably want these app images to stay private! Until we get an official answer from kamal here's a workaround that I've been using.

Be aware that you still need some kind of public image hosting due to limitations in kamal as of version 2.2.2. There's a hack at the bottom of this document to work around this limitation as well.

Steps to deploy

  • Change values in the deploy config to suit your setup
  • Run kamal deploy
  • Run kamal htpasswd-set <username> <password> to set as many credentials as you need or rotate keys
  • Enjoy!

Optional: Self-host (Do this before deploying)

On your local machine…

  • docker run --volume ./auth:/auth --rm --entrypoint htpasswd httpd:2 -Bb /auth/htpasswd <username> <password>
  • docker run --volume ./auth:/auth --rm --port 5000:5000 -e "REGISTRY_AUTH=htpasswd" -e "REGISTRY_AUTH_HTPASSWD_REALM=Registry Realm" -e REGISTRY_AUTH_HTPASSWD_PATH=/auth/htpasswd registry:2
  • In another terminal ngrok http 5000
  • Copy the ngrok url, and place it in your kamal config under registry/server
  • Ensure the credentials you gave it are configured in your kamal secrets
  • Run the steps to deploy
  • Optional: Replace the ngrok url with your freshly deployed docker registry
  • I also have a video about this on YouTube
service: docker-registry
image: my-company/docker-registry
servers:
web:
- 1.3.3.7
proxy:
ssl: true
host: docker.my-company.com
app_port: 5000
healthcheck:
path: /
registry:
username: username
server: <some url>.ngrok-free.app
password:
- KAMAL_REGISTRY_PASSWORD
builder:
arch: arm64 # This is the platform I tested on, but it should work on any platform.
volumes:
- auth:/auth
env:
clear:
REGISTRY_HTTP_ADDR: 0.0.0.0:5000
REGISTRY_AUTH: htpasswd
REGISTRY_AUTH_HTPASSWD_REALM: Registry Realm
REGISTRY_AUTH_HTPASSWD_PATH: /auth/htpasswd
aliases:
shell: app exec --interactive --reuse "sh"
htpasswd-set: server exec docker run --volume auth:/auth --rm --entrypoint htpasswd httpd:2 -Bb /auth/htpasswd
htpasswd-delete: server exec docker run --volume auth:/auth --rm --entrypoint htpasswd httpd:2 -D /auth/htpasswd
htpasswd-print: server exec docker run --volume auth:/auth --rm --entrypoint cat httpd:2 /auth/htpasswd
FROM registry:2
@waynehoover
Copy link

Can you explain why you need to run ngrok, and why we couldn't just spin up a docker registry locally and then use localhost:5000 as the registry:server:?

@kjlape
Copy link
Author

kjlape commented Nov 14, 2024

Can you explain why you need to run ngrok, and why we couldn't just spin up a docker registry locally and then use localhost:5000 as the registry:server:?

@waynehoover Sure! It's because the destination server can't access my local docker registry without some kind of tunnel. It needs to be accessible on the outside somehow.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment