A modern, open-source web interface for managing your Docker Registry
Self-hosted • Secure • Mobile-First • No Database Required
Prerequisites • Installation Production • Features • Development • Discussions
Managing Docker images in a self-hosted registry shouldn't require complex tools or compromising on security. Docker Registry UI provides a clean, modern interface that works seamlessly with your existing Docker Registry V2 API infrastructure.
You need a Docker Registry V2 API running. Here's how to start one locally for testing:
# Generate htpasswd file (username: admin, password: admin)
docker run --rm httpd:2.4-alpine htpasswd -nbB admin admin > registry.password
# Run Docker Registry 3 with authentication and delete enabled
docker run -d -p 5000:5000 \
-e REGISTRY_STORAGE_DELETE_ENABLED=true \
-e REGISTRY_AUTH=htpasswd \
-e REGISTRY_AUTH_HTPASSWD_REALM="Registry Realm" \
-e REGISTRY_AUTH_HTPASSWD_PATH=/auth/registry.password \
-v $(pwd)/registry.password:/auth/registry.password \
-v registry-data:/var/lib/registry \
--name registry \
registry:3Your registry will be available at http://localhost:5000 with credentials admin:admin.
CRITICAL: This application MUST be deployed behind a reverse proxy with authentication. Never expose it directly to the internet.
Architecture:
Internet → Reverse Proxy (Auth) → Registry UI (localhost:3000) → Docker Registry
Create a .env file in the root directory:
| Variable | Required | Default | Description |
|---|---|---|---|
NODE_ENV |
Yes | development |
Environment mode (development or production) |
HOST |
Yes | 127.0.0.1 |
Host to bind |
PORT |
Yes | 3000 |
Port for the application server |
REGISTRY_URL |
Yes | - | URL of your Docker Registry V2 API |
REGISTRY_USERNAME |
No | - | Username for registry authentication |
REGISTRY_PASSWORD |
No | - | Password for registry authentication |
REGISTRY_TOKEN_CACHE_TTL |
Yes | 300 |
Token cache duration in seconds (60-3600) |
ENABLE_USER_LOGGING |
No | false |
Enable user logging from X-Forwarded-User header |
NUXT_PUBLIC_REGISTRY_URL |
No | localhost:5000 |
Public URL users should use in "docker pull" commands |
Example Configuration:
NODE_ENV=production
HOST=127.0.0.1
PORT=3000
REGISTRY_URL=https://registry.example.com
NUXT_PUBLIC_REGISTRY_URL=mypublicregistry.com
REGISTRY_USERNAME=admin
REGISTRY_PASSWORD=your-secure-password
REGISTRY_TOKEN_CACHE_TTL=300
ENABLE_USER_LOGGING=trueNginx Configuration
server {
listen 443 ssl http2;
server_name registry-ui.example.com;
ssl_certificate /path/to/cert.pem;
ssl_certificate_key /path/to/key.pem;
# Basic Authentication
auth_basic "Docker Registry UI";
auth_basic_user_file /path/to/.htpasswd;
location / {
proxy_pass http://127.0.0.1:3000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-User $remote_user;
}
}Caddy Configuration
registry-ui.example.com {
basicauth {
admin $2a$14$... # Use 'caddy hash-password' to generate
}
reverse_proxy 127.0.0.1:3000 {
header_up X-Forwarded-User {remote_user}
}
}Traefik Configuration (docker-compose.yml)
services:
registry-ui:
image: your-registry-ui:latest
environment:
- HOST=0.0.0.0 # Listen on all interfaces within container
- REGISTRY_URL=https://registry.example.com
labels:
- 'traefik.enable=true'
- 'traefik.http.routers.registry-ui.rule=Host(`registry-ui.example.com`)'
- 'traefik.http.routers.registry-ui.entrypoints=websecure'
- 'traefik.http.routers.registry-ui.tls.certresolver=letsencrypt'
- 'traefik.http.routers.registry-ui.middlewares=registry-ui-auth'
- 'traefik.http.middlewares.registry-ui-auth.basicauth.users=admin:$$apr1$$...'
networks:
- web
# NO ports exposed - only via Traefik
networks:
web:
external: trueDocker Compose Example
version: '3.8'
services:
registry-ui:
build: .
environment:
- HOST=0.0.0.0
- PORT=3000
- NODE_ENV=production
- REGISTRY_URL=https://registry.example.com
- REGISTRY_USERNAME=admin
- REGISTRY_PASSWORD=${REGISTRY_PASSWORD}
- REGISTRY_VERIFY_SSL=true
# NO ports exposed - use reverse proxy
restart: unless-stoppedBuilding Docker Image
# Build the image
docker build -t registry-ui:latest .
# Run with environment variables
docker run -d \
--name registry-ui \
-e HOST=0.0.0.0 \
-e REGISTRY_URL=https://registry.example.com \
-e REGISTRY_USERNAME=admin \
-e REGISTRY_PASSWORD=secret \
registry-ui:latest- External Authentication - Integrates with reverse proxy (Nginx, Caddy, Traefik) for Basic Auth/OAuth
- Security First - Must run behind authenticated reverse proxy, never exposed directly
- Stateless Design - No database required, all state managed through Registry API
- Type-Safe - Full TypeScript coverage with strict mode and Zod validation
- Mobile-First Design - Responsive UI optimized for all devices (mobile to desktop)
- Dark Mode - Automatic system preference detection with manual toggle
- Internationalization - Multi-language support (English, French)
- Accessibility - WCAG 2.1 AA compliant components with keyboard navigation
- Performance - Server-side rendering, optimized bundle (<500KB initial)
- Full V2 API Support - Complete compatibility with Docker Registry V2 API
- Smart Tag Deletion - Intelligent three-tier deletion strategy (OCI API → Dummy Manifest → Digest fallback)
- Repository Management - Browse, search, and manage repositories and tags
- Image Metadata - View architecture, OS, size, and creation dates
Authentication failures
- Verify
REGISTRY_USERNAMEandREGISTRY_PASSWORDare correct - Check if registry requires authentication (some allow anonymous read)
- Ensure bearer token authentication is supported by your registry
Cannot delete images
- Docker Registry must have
REGISTRY_STORAGE_DELETE_ENABLED=true - Ensure your registry version supports deletion
- Check user has write permissions on the registry
Tag Deletion Strategies:
This application uses an intelligent three-tier approach to delete Docker tags:
- OCI Tag Delete API (Future-proof) - Uses official OCI Distribution Spec v1.0+ endpoint
- Dummy Manifest Workaround (Current solution) - Proven approach used by professional tools like
regctl - Digest Deletion (Last resort) - Traditional deletion with warning about affecting all tags
Get started with local development:
# Clone the repository
git clone https://github.com/chichi13/registry-ui.git
cd registry-ui
# Install dependencies
bun install
# Configure environment
cp .env.example .env
# Edit .env with your Docker Registry URL (http://localhost:5000 for local testing)
# Start development server
bun run devThe application will be available at http://localhost:3000.
# Development
bun run dev # Start development server
# Build
bun run build # Build for production
bun run start # Start production server
# Code Quality
bun run lint # Lint code
bun run prettier:fix # Fix code formatting- ESLint - Security rules, import order, TypeScript best practices
- Prettier - Consistent code formatting (single quotes, no semicolons)
- TypeScript - Strict mode with additional checks
- Git Hooks - Pre-commit linting, formatting, and type-checking
- Conventional Commits - Standardized commit message format
We welcome contributions! Whether it's bug reports, feature requests, or code contributions, every contribution makes a difference.
Want to suggest a feature? Join the discussion on GitHub Discussions!
How to Contribute:
- Fork the repository
- Create a feature branch (
git checkout -b feat/amazing-feature) - Commit your changes using Conventional Commits
- Push to your branch
- Open a Pull Request
Read our Contributing Guidelines for more details.
- Nuxt 4 - The Intuitive Vue Framework
- Reka UI - Accessible, unstyled components
- Tailwind CSS - Utility-first CSS framework
- Zod - TypeScript-first schema validation
- GitHub Discussions - Ask questions, share ideas
- GitHub Issues - Report bugs and request features
Security is a top priority for Docker Registry UI. If you discover a security vulnerability, please follow our Security Policy.
Important:
- Never open a public issue for security vulnerabilities
- Do not disclose the vulnerability publicly before it's fixed
- Report security issues via private security advisory on GitHub
This project is licensed under the MIT License - see the LICENSE file for details.
What this means:
- Free to use, modify, and distribute
- Can be used in commercial projects
- No warranty provided
- Attribution required
An AI assistant was used for this project (Claude Code / Cursor).
⭐ If you find Docker Registry UI useful, please consider giving it a star on GitHub!
GitHub • Discussions • Issues

