Skip to content

imansprn/registry

Docker Registry with Authentication

License: MIT Docker

A secure private Docker registry with basic authentication and CORS support. Easy to deploy locally or to any cloud platform.

Overview

This project provides a Docker registry setup using the official Docker Registry image with htpasswd-based authentication. It's configured with CORS headers to support browser-based UIs and can be easily deployed to any container platform.

Perfect for:

  • Private Docker image hosting
  • CI/CD pipelines
  • Development teams needing a local registry
  • Cloud deployments (AWS, GCP, Azure, and others)

Features

  • ✅ Latest Docker Registry version (registry:2)
  • ✅ Basic authentication via htpasswd
  • ✅ CORS support for web UIs
  • ✅ Easy to deploy and configure
  • ✅ Production-ready with security best practices

Prerequisites

  • Docker installed and running
  • htpasswd utility (or use Docker to generate passwords)

Quick Links

Quick Start

1. Generate htpasswd File

Option A: Using Docker (Recommended)

# Create htpasswd file from example
cp htpasswd.example htpasswd

# Generate a new user entry with bcrypt
docker run --rm --entrypoint htpasswd httpd:2 -Bbn username your_secure_password >> htpasswd

# Or with cost factor 12 explicitly (more secure)
docker run --rm --entrypoint htpasswd httpd:2 -Bbn -C 12 username your_secure_password >> htpasswd

Option B: Using system htpasswd

# Install apache2-utils if needed
# macOS: brew install httpd
# Ubuntu/Debian: sudo apt-get install apache2-utils

# Copy example and generate entry
cp htpasswd.example htpasswd
htpasswd -Bbn username your_secure_password >> htpasswd

2. Build the Image

Option A: Using htpasswd file (Local Development)

docker build -t my-registry .

Option B: Using build arguments (Recommended for CI/CD/Cloud deployments)

docker build \
  --build-arg USERNAME=admin \
  --build-arg PASSWORD=your_secure_password \
  -t my-registry .

Important: The .dockerignore file excludes htpasswd by default to support build arguments.

When using build arguments (recommended for cloud): No action needed - htpasswd is already excluded.

When using htpasswd file: Comment out the htpasswd line in .dockerignore:

# In .dockerignore, comment out this line:
# htpasswd

Note: You must provide either:

  • Build arguments (USERNAME and PASSWORD), OR
  • An htpasswd file in the build context (comment out htpasswd in .dockerignore)

If neither is provided, the build will fail with a clear error message.

3. Run the Registry

docker run -d \
  --name registry \
  --restart=always \
  -p 5050:5000 \
  -v registry-data:/var/lib/registry \
  -e REGISTRY_HTTP_SECRET=$(openssl rand -hex 32) \
  my-registry

Note:

  • The htpasswd file is baked into the image during build if build args are provided
  • If credentials are provided via runtime environment variables (REGISTRY_USERNAME/REGISTRY_PASSWORD), they are generated at container startup
  • To update credentials, either rebuild the image with new build args or restart with new environment variables

4. Test the Registry

# Login to the registry
docker login localhost:5050
# Enter your username and password

# Tag and push an image
docker tag myimage:latest localhost:5050/myimage:latest
docker push localhost:5050/myimage:latest

# Pull the image
docker pull localhost:5050/myimage:latest

Architecture

This registry uses a two-component architecture:

  1. Docker Registry - Runs internally on 127.0.0.1:5001 with authentication enabled
  2. Nginx Proxy - Runs on port 5000 and proxies requests to the registry, adding CORS headers

The entrypoint script (docker-entrypoint.sh) handles:

  • Credential validation and htpasswd generation (if not provided at build time)
  • Starting the registry in the background
  • Waiting for the registry to be ready
  • Starting Nginx as the foreground process

This architecture allows the registry to work seamlessly with browser-based UIs while maintaining security.

Configuration

CORS Headers

The registry is pre-configured with permissive CORS headers handled by an Nginx proxy. This allows it to work with browser-based UIs out of the box.

By default, Nginx will:

  • Reflect the Origin header if present (allowing credentials)
  • Default to * if no Origin is present
  • Force these headers on all responses (including errors)
  • Handle CORS preflight (OPTIONS) requests
  • Support large blob uploads with extended timeouts (900s)

Customizing CORS

Since CORS is handled by Nginx, the Registry's internal CORS environment variables (REGISTRY_HTTP_HEADERS_...) will be ignored.

To customize the CORS configuration (e.g., to restrict to specific domains), you can mount a custom nginx.conf file:

docker run -d \
  --name registry \
  -p 5050:5000 \
  -v $(pwd)/my-nginx.conf:/etc/nginx/nginx.conf:ro \
  my-registry

You can use the default nginx.conf as a starting point.

Health Check

The registry includes a health check endpoint at /health that returns 200 OK. This is used by Docker's healthcheck mechanism and can be accessed directly:

curl http://localhost:5050/health

The health check verifies that both Nginx and the registry are responsive.

HTTP Secret

For production deployments, especially with load balancers, set a fixed HTTP secret:

# Generate a secret
openssl rand -hex 32

# Use it when running
docker run -d \
  --name registry \
  -p 5050:5000 \
  -e REGISTRY_HTTP_SECRET=your_generated_secret_here \
  my-registry

Cloud Deployment

The registry supports credentials via build arguments (ARG) or environment variables (ENV):

Option 1: Build Arguments (Recommended for CI/CD)

Configure these build arguments in your platform's build settings:

  • USERNAME - Registry username (default: admin)
  • PASSWORD - Registry password

Credentials are generated at build time and baked into the image.

Option 2: Environment Variables (Runtime)

Set these environment variables when running the container:

  • REGISTRY_USERNAME - Registry username (default: admin)
  • REGISTRY_PASSWORD - Registry password

Credentials are generated at container startup if not provided at build time.

Other Environment Variables

Set these runtime environment variables in your deployment platform:

  • REGISTRY_HTTP_SECRET - Generate with: openssl rand -hex 32

    • Required for load-balanced setups
    • Set the same value for all instances in a multi-instance deployment
    • Used for session token signing
  • REGISTRY_STORAGE_DELETE_ENABLED - Set to true to enable deletion of images and manifests

    • Default: true (enabled by default in this image)
    • Allows DELETE requests to remove images, tags, and manifests from the registry
  • REGISTRY_AUTH_HTPASSWD_REALM - Authentication realm name

    • Default: "Registry Realm"
    • This is the realm name shown in authentication challenges
    • Can be customized for branding or security purposes
  • REGISTRY_HTTP_TLS_CERTIFICATE - Path to TLS certificate file

    • Use with REGISTRY_HTTP_TLS_PRIVATE_KEY to enable TLS
    • Example: /auth/domain.crt
  • REGISTRY_HTTP_TLS_PRIVATE_KEY - Path to TLS private key file

    • Use with REGISTRY_HTTP_TLS_CERTIFICATE to enable TLS
    • Example: /auth/domain.key

Example Configurations

Using Build Arguments:

docker build \
  --build-arg USERNAME=admin \
  --build-arg PASSWORD=your_secure_password \
  -t my-registry .

Using Environment Variables:

docker run -d \
  --name registry \
  -p 5050:5000 \
  -e REGISTRY_USERNAME=admin \
  -e REGISTRY_PASSWORD=your_secure_password \
  -e REGISTRY_HTTP_SECRET=$(openssl rand -hex 32) \
  my-registry

Note: Docker may show security warnings about using ARG PASSWORD. This is expected - the password is only used during build to generate a hash and is not stored in the final image. Only the hashed password is included in the image.

Security Best Practices

1. Use Strong Passwords

  • Generate passwords with at least 16 characters
  • Use a password manager
  • Consider using multiple users for different purposes
  • Regularly rotate passwords

2. Enable TLS (Recommended for Production)

For production use, you should enable TLS encryption:

# Generate self-signed certificates (for testing)
mkdir -p auth
openssl req -newkey rsa:4096 -nodes -sha256 \
  -keyout auth/domain.key -x509 -days 365 \
  -out auth/domain.crt \
  -subj "/CN=registry.example.com"

# Run with TLS
docker run -d \
  --name registry \
  -p 5050:5000 \
  -v "$(pwd)"/auth:/auth:ro \
  -v registry-data:/var/lib/registry \
  -e REGISTRY_HTTP_TLS_CERTIFICATE=/auth/domain.crt \
  -e REGISTRY_HTTP_TLS_PRIVATE_KEY=/auth/domain.key \
  my-registry

3. Network Security

  • Restrict access using firewall rules
  • Use VPN or private network
  • Consider using reverse proxy (nginx/traefik) with additional security layers
  • Limit access to specific IP ranges

4. Regular Updates

  • Keep the registry image updated
  • Monitor for security advisories
  • Regularly rotate passwords and secrets

Troubleshooting

Cannot login

  • Verify the htpasswd file exists and is readable
  • Check file permissions (should be readable)
  • Ensure the volume mount is correct
  • Verify username and password are correct

Connection refused

  • Verify the registry is running: docker ps
  • Check if port 5050 is available (or the port you mapped with -p)
  • Review logs: docker logs registry
  • Check if the registry started successfully: Look for "Registry is ready" in logs
  • Verify Nginx started: Look for "Starting Nginx proxy" in logs

Credential errors

  • If using runtime environment variables, ensure REGISTRY_PASSWORD is set
  • If using build args, ensure PASSWORD was provided during build
  • Check entrypoint logs for credential generation messages
  • Verify htpasswd file exists: docker exec registry ls -la /auth/htpasswd

CORS errors in browser

  • Verify CORS headers are set correctly
  • Check that the allowed origin matches your UI domain
  • Ensure the registry is accessible from the browser's origin

File Structure

registry/
├── .github/            # GitHub templates and workflows
│   ├── ISSUE_TEMPLATE.md
│   └── PULL_REQUEST_TEMPLATE.md
├── Dockerfile          # Multi-stage build: generates htpasswd and sets up registry
├── docker-entrypoint.sh # Entrypoint script: handles credential generation and starts services
├── nginx.conf          # Nginx CORS proxy configuration (proxies port 5000 -> 5001)
├── .dockerignore       # Prevents sensitive files in image
├── .gitignore          # Git ignore patterns
├── LICENSE             # MIT License
├── README.md           # This file
├── CHANGELOG.md        # Project version history and changes
├── CONTRIBUTING.md     # Contribution guidelines
├── CODE_OF_CONDUCT.md  # Code of conduct for contributors
├── SECURITY.md         # Security policy and vulnerability reporting
└── htpasswd.example    # Example htpasswd template

Key Files Explained

  • Dockerfile: Multi-stage build that generates htpasswd credentials and sets up the registry with Nginx
  • docker-entrypoint.sh: Handles runtime credential generation (if not provided at build), starts the registry on port 5001, and then starts Nginx on port 5000
  • nginx.conf: Configures Nginx as a reverse proxy with CORS support, handling preflight requests and large blob uploads

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

For detailed guidelines, see CONTRIBUTING.md.

Quick start:

  1. Fork the repository
  2. Create your feature branch (git checkout -b feature/amazing-feature)
  3. Commit your changes (git commit -m 'Add some amazing feature')
  4. Push to the branch (git push origin feature/amazing-feature)
  5. Open a Pull Request

License

This project is licensed under the MIT License - see the LICENSE file for details.

Additional Resources

Important Notes

  • ⚠️ Never commit htpasswd or sensitive files to version control
  • ⚠️ Use TLS in production environments
  • ⚠️ Keep registry image updated for security patches
  • ⚠️ Set a fixed REGISTRY_HTTP_SECRET for load-balanced setups

About

A secure Docker registry with authentication and CORS support for cloud deployments

Resources

License

Code of conduct

Contributing

Security policy

Stars

Watchers

Forks

Packages

No packages published