| title | Local Docker Registry | ||||
|---|---|---|---|---|---|
| description | Deploy a local Docker registry behind HAProxy for reliable CVM image pulls | ||||
| section | Prerequisites | ||||
| stepNumber | 4 | ||||
| totalSteps | 7 | ||||
| lastUpdated | 2026-01-22 | ||||
| prerequisites |
|
||||
| tags |
|
||||
| difficulty | intermediate | ||||
| estimatedTime | 20 minutes |
This tutorial guides you through deploying a local Docker registry behind HAProxy. The registry runs on localhost:5000 and HAProxy handles TLS termination, providing secure external access via registry.yourdomain.com.
| Challenge | Solution |
|---|---|
| Docker Hub rate limits | Local registry has no pull limits |
| Network reliability | Local pulls are fast and consistent |
| CVM boot timing | Registry must respond quickly during boot |
| Image availability | Cached images always available |
When a CVM boots, it pulls Docker images. If this fails, the CVM fails to start. A local registry with proper SSL ensures reliable deployments.
External Request Internal
┌──────────────────────────────────────────────────────────────┐
│ │
│ registry.yourdomain.com:443 → HAProxy → localhost:5000 │
│ (TLS) (proxy) (registry) │
│ │
└──────────────────────────────────────────────────────────────┘
HAProxy handles:
- TLS termination using Let's Encrypt certificates
- SNI-based routing to the registry on localhost:5000
- Unified configuration with other services (VMM management, gateway, etc.)
Before starting, ensure you have:
- Completed HAProxy Setup - HAProxy installed and configured
- Completed SSL Certificate Setup - Registry certificate obtained
- Docker installed and running
Verify the DNS record:
dig +short registry.yourdomain.comShould return your server's IP address.
If you prefer to deploy manually, follow these steps.
Note: HAProxy and SSL certificates must already be set up. If you haven't completed HAProxy Setup and SSL Certificate Setup, do those first. HAProxy is already configured to proxy
registry.yourdomain.comtolocalhost:5000.
sudo mkdir -p /var/lib/registryThe registry runs on localhost:5000 (not exposed externally). HAProxy handles external TLS connections.
docker run -d \
--name registry \
--restart always \
-p 127.0.0.1:5000:5000 \
-v /var/lib/registry:/var/lib/registry \
registry:2docker ps | grep registryExpected output shows container running:
abc123 registry:2 ... Up 2 minutes 127.0.0.1:5000->5000/tcp registry
Test the registry API locally (without TLS):
curl -s http://127.0.0.1:5000/v2/An empty response or {} indicates success - the registry is running.
Test the registry through HAProxy:
curl -s https://registry.yourdomain.com/v2/An empty response or {} indicates success.
Check the catalog (empty initially):
curl -s https://registry.yourdomain.com/v2/_catalogExpected response: {"repositories":[]} (no images pushed yet)
The KMS Docker image is built from source and pushed to your local registry during Phase 4 (KMS Build & Configuration). This is handled by:
- Follow the KMS Build & Configuration tutorial.
Do not attempt to pull KMS images from Docker Hub. The tutorial workflow builds everything from source to ensure you have a verifiable, reproducible deployment.
At this point, your registry should be running but empty:
curl -sk https://registry.yourdomain.com/v2/_catalogExpected response:
{"repositories":[]}Images will appear here after completing the KMS build phase.
Run this verification script:
# Replace with your registry domain
DOMAIN="registry.yourdomain.com"
echo "Registry Container: $(docker ps --format '{{.Names}}' | grep -q registry && echo 'running' || echo 'not running')"
echo "Local Port 5000: $(ss -tln | grep -q 127.0.0.1:5000 && echo 'listening' || echo 'not listening')"
echo "HAProxy Port 443: $(ss -tln | grep -q :443 && echo 'listening' || echo 'not listening')"
echo "SSL Certificate: $(openssl s_client -connect $DOMAIN:443 -servername $DOMAIN </dev/null 2>/dev/null | grep -q 'Verify return code: 0' && echo 'valid' || echo 'invalid or expired')"
echo "Local Registry: $(curl -s -o /dev/null -w '%{http_code}' http://127.0.0.1:5000/v2/ | grep -q '200' && echo 'responding' || echo 'not responding')"
echo "External via HAProxy: $(curl -s -o /dev/null -w '%{http_code}' https://$DOMAIN/v2/ | grep -q '200' && echo 'responding' || echo 'not responding')"
echo "Repositories: $(curl -s https://$DOMAIN/v2/_catalog)"All checks should show positive status. The repositories list will be empty until you complete the KMS build phase.
For detailed solutions, see the Prerequisites Troubleshooting Guide:
- Certificate Verification Failed
- 503 Service Unavailable from HAProxy
- 502 Bad Gateway from HAProxy
- DNS Not Resolving (Docker Registry)
- Registry Container Not Starting
- HAProxy Configuration Error
With the local Docker registry running, proceed to:
- Contract Deployment - Deploy KMS contracts to Sepolia
- KMS Build & Configuration - Prepare KMS for CVM deployment