This is a simple example of a Docker Registry with Let's Encrypt SSL. It uses Caddy as a reverse proxy and Let's Encrypt for SSL.
Caution
This repo serves as a simple example of a Docker Registry with Let's Encrypt SSL. It isn't considered production-ready. We use this repo simply for testing purposes with other applications.
- 🔒 Automatic HTTPS - Let's Encrypt certificates via Caddy (zero configuration)
- 🔐 Basic Authentication - htpasswd-based user authentication
- 👥 Multi-user Support - Separate admin (read-write) and reader (read-only) accounts
- 🚀 Easy Setup - One-command deployment with Docker Compose
- 📦 Latest Registry - Uses Docker Registry v3 (OCI Distribution Spec compliant)
- 🔄 Auto-renewal - SSL certificates automatically renewed
- 📊 HTTP/3 Support - Modern protocol support out of the box
# Copy environment template
cp env.example .env
# Edit with your domain and email
nano .envUpdate .env:
REGISTRY_DOMAIN=registry.example.com # Your actual domainOption A: Using the setup script (recommended)
./setup.shOption B: Manual setup
mkdir -p auth
# Create admin user (read-write)
docker run --rm --entrypoint htpasswd httpd:2 -Bbn admin YourPassword > auth/htpasswd
# Add reader user (read-only)
docker run --rm --entrypoint htpasswd httpd:2 -Bbn reader YourPassword >> auth/htpasswddocker-compose up -d# Check logs
docker-compose logs -f
# Test the endpoint (wait ~30 seconds for cert generation)
curl https://registry.example.com/v2/
# Should return: {} (after authentication)# Login
docker login registry.example.com
# Username: admin (or reader)
# Tag and push (admin only)
docker tag ubuntu:latest registry.example.com/myapp:latest
docker push registry.example.com/myapp:latest
# Pull (both users)
docker pull registry.example.com/myapp:latest- Docker and Docker Compose installed
- Domain name with DNS A record pointing to your server
- Ports 80 and 443 open on your firewall/security group
- Public IP address (required for Let's Encrypt validation)
| User | Access | Use Case |
|---|---|---|
admin |
Read-Write | Push and pull images |
reader |
Read-Only* | Pull images only |
# Login to registry
docker login registry.example.com
# Pull an image from Docker Hub
docker pull alpine:latest
# Tag for your registry
docker tag alpine:latest registry.example.com/alpine:latest
# Push to your registry
docker push registry.example.com/alpine:latest
# Pull from your registry
docker pull registry.example.com/alpine:latestAdd more users to the htpasswd file:
# Add a new user
docker run --rm --entrypoint htpasswd httpd:2 -Bbn newuser password >> auth/htpasswd
# Restart registry to apply changes
docker-compose restart registryWe're Dan and Jay - a two person team with a passion for open source products. We created Server Side Up to help share what we learn.
- 📖 Blog - Get the latest guides and free courses on all things web/mobile development.
- 🙋 Community - Get friendly help from our community members.
- 🤵♂️ Get Professional Help - Get custom solutions built for your team.
- 💻 GitHub - Check out our other open source projects.
- 📫 Newsletter - Skip the algorithms and get quality content right to your inbox.
- 🐥 Twitter - You can also follow Dan and Jay.
- ❤️ Sponsor Us - Please consider sponsoring us so we can create more helpful resources.
If you appreciate this project, be sure to check out our other projects.
- The Ultimate Guide to Building APIs & SPAs: Build web & mobile apps from the same codebase.
- Building Multi-Platform Browser Extensions: Ship extensions to all browsers from the same codebase.
- Bugflow: Get visual bug reports directly in GitHub, GitLab, and more.
- SelfHost Pro: Connect Stripe or Lemonsqueezy to a private docker registry for self-hosted apps.
- AmplitudeJS: Open-source HTML5 & JavaScript Web Audio Library.
- Spin: Laravel Sail alternative for running Docker from development → production.
- Financial Freedom: Open source alternative to Mint, YNAB, & Monarch Money.

