Hello! Welcome to your next lesson in the "Advanced Image and Runtime Management" module.
In our last session, we mastered the art of tagging images with semantic versioning and pushing them to public registries like Docker Hub and GitHub Container Registry. This is perfect for open-source projects and public applications. However, in a corporate or secure environment, you need a private, controlled space for your proprietary images.
Today, we'll tackle exactly that. Your learning outcome is to authenticate with, use, and run a private container registry for secure image distribution. As a DevOps engineer with an interest in cybersecurity, you'll find this skill fundamental for building secure software supply chains and maintaining control over your organization's intellectual property. We will set up a local, secure registry, a common task for establishing development and testing environments.
1. Why Use a Private Registry?
While public registries are convenient, they aren't always suitable. Companies need private registries for several key reasons:
- Security: To store proprietary or sensitive application images that should not be publicly accessible.
- Control: To manage access control, deciding who can push (write) and pull (read) images.
- Performance: To have a registry on the local network, reducing latency and reliance on internet bandwidth for CI/CD pipelines and deployments.
- Cost & Rate Limits: To avoid potential costs and rate-limiting imposed by public registries on high-volume usage.
Real-Time Custom Private Docker Registry With SSL | DevOps | Docker
To start, let's watch the introduction of this video from DevOps Shack. It clearly explains the business and technical motivations for setting up a custom private registry instead of relying on public or even cloud-provider options.
Watch the first minute and 19 seconds (00:00 - 01:19). Focus on the comparison between public Docker Hub, cloud-managed registries (like AWS ECR), and a self-hosted custom registry.
2. The Anatomy of a Secure Private Registry
A secure private registry has two essential components:
- Authentication: A mechanism to verify the identity of users trying to log in, push, or pull images. We'll use basic HTTP authentication with a username and password file generated by
htpasswd. - Encryption (TLS/SSL): A protocol to encrypt the communication between the Docker client and the registry. This prevents image data and, more importantly, your login credentials from being sent over the network in plaintext.
The official Docker registry:2 image provides the core functionality. We will configure it to use our own authentication credentials and SSL certificates.
3. Hands-On: Building Your Secure Registry with Docker Compose
While you can run a registry with a long docker run command, a more maintainable and professional approach—especially for a DevOps role—is to define it as a service in a docker-compose.yml file. This makes the configuration declarative and easy to manage.
We will set up a registry that is accessible on your local machine at registry.local:5000.
Step 1: Create the Project Structure and Certificates
First, we need to create a directory structure and generate a self-signed SSL certificate. This is common for local development environments. For a real production server, you would use a trusted authority like Let's Encrypt, as shown in the DevOps Shack video.
Open your terminal and run the following commands:
# Create the main project directory
mkdir my-secure-registry
cd my-secure-registry
# Create subdirectories for data, auth, and certs
mkdir -p data auth certs
# Generate a self-signed SSL certificate and private key
openssl req \
-newkey rsa:4096 -nodes -sha256 -keyout certs/domain.key \
-x509 -days 365 -out certs/domain.crt \
-subj "/CN=registry.local"
This openssl command creates a certificate (domain.crt) and a private key (domain.key) valid for 365 days for the domain name registry.local.
Step 2: Create Authentication Credentials
Next, we'll create a user and password for our registry using htpasswd. You may need to install this utility first (sudo apt install apache2-utils on Debian/Ubuntu or sudo yum install httpd-tools on CentOS/RHEL).
# Create a user named 'admin' (you will be prompted to enter a password)
htpasswd -Bc auth/htpasswd admin
This command creates a file named htpasswd in the auth directory containing the encrypted credentials for the user admin.
Step 3: Create the Docker Compose File
Now, let's define our registry service. Create a file named docker-compose.yml in the my-secure-registry directory with the following content:
version: '3.8'
services:
registry:
image: registry:2
container_name: docker-registry
restart: always
ports:
- "5000:5000"
environment:
REGISTRY_AUTH: htpasswd
REGISTRY_AUTH_HTPASSWD_REALM: Registry Realm
REGISTRY_AUTH_HTPASSWD_PATH: /auth/htpasswd
REGISTRY_HTTP_TLS_CERTIFICATE: /certs/domain.crt
REGISTRY_HTTP_TLS_KEY: /certs/domain.key
volumes:
- ./data:/var/lib/registry
- ./auth:/auth
- ./certs:/certs
Let's break down the environment variables:
REGISTRY_AUTH: Specifies the authentication scheme (htpasswd).REGISTRY_AUTH_HTPASSWD_PATH: Tells the registry where to find the password file inside the container.REGISTRY_HTTP_TLS_CERTIFICATE®ISTRY_HTTP_TLS_KEY: Point to the SSL certificate and key files.
The code for these steps is consolidated in the article below.
How to Set Up a Private Docker Registry on Ubuntu
This guide from OneUptime provides a clear, text-based walkthrough of setting up a production-style private registry. We have just followed its core steps for setting up certificates, authentication, and the Docker Compose file.
Review the sections 'Production Setup' -> 'Create Directory Structure', 'Generate SSL Certificates' (specifically the 'For self-signed certificates' part), 'Configure Authentication', and 'Create Docker Compose File'. This will reinforce what we've just done.
Step 4: Configure Your Host Machine
Since we are using a self-signed certificate, we need to tell our system (and the Docker daemon) to trust it. We also need to map our custom domain registry.local to our local machine.
-
Edit your hosts file to resolve
registry.localto127.0.0.1.- On Linux/macOS:
sudo nano /etc/hosts - On Windows:
C:\Windows\System32\drivers\etc\hosts(as Administrator) - Add this line and save:
127.0.0.1 registry.local
- On Linux/macOS:
-
Configure the Docker daemon to trust your certificate. This is the most critical step.
# Create a directory for your registry's certificate sudo mkdir -p /etc/docker/certs.d/registry.local:5000 # Copy your public certificate to that directory sudo cp certs/domain.crt /etc/docker/certs.d/registry.local:5000/ca.crt # Restart the Docker daemon to apply the changes sudo systemctl restart dockerThis process is also detailed in the OneUptime article under the "Configure Docker Clients" section.
4. Run and Use Your Secure Registry
Everything is now in place! Let's start the registry and push an image to it.
-
Start the registry:
docker compose up -d -
Log in to your private registry:
docker login registry.local:5000Enter the username (
admin) and the password you created earlier. You should seeLogin Succeeded. -
Tag an image and push it:
Let's use a simple image likenginx.# Pull a public image to work with docker pull nginx:latest # Tag it for your private registry docker tag nginx:latest registry.local:5000/my-nginx:1.0 # Push it to your private registry docker push registry.local:5000/my-nginx:1.0 -
Verify the push:
You can verify the image exists in your registry via the API.curl --cacert certs/domain.crt -u admin:<your_password> https://registry.local:5000/v2/_catalogThis should return
{"repositories":["my-nginx"]}.
Test your understanding!
You have a local image named webapp:3.5-beta. What are the two docker commands you need to run to push this image to your newly created private registry at registry.local:5000? Assume you are already logged in.
Show answer
- Tag the image with the private registry's URL:
docker tag webapp:3.5-beta registry.local:5000/webapp:3.5-beta - Push the newly tagged image:
docker push registry.local:5000/webapp:3.5-beta
5. Beyond the Basics: Enterprise-Grade Registries
The registry:2 image is excellent for many use cases, but for large-scale enterprise needs, you might use a more feature-rich solution like Harbor. Harbor is an open-source registry that includes features your cybersecurity interest will appreciate, such as:
- Role-Based Access Control (RBAC)
- Vulnerability scanning for images
- Image signing
- A rich web UI for administration
Harbor is often deployed on Kubernetes, which directly connects to your existing experience.
Harbor Private Container Registry for Docker and Kubernetes
To see what an enterprise-grade solution looks like, watch this brief overview of Harbor. It will give you a sense of the additional capabilities available and how it fits into a Kubernetes ecosystem.
Watch from 00:46 to 01:52. This section introduces Harbor and explains why you would choose it for a CI/CD and Kubernetes environment, highlighting features like vulnerability scanning and policy control.
Conclusion
Congratulations! You've successfully set up, secured, and used a private Docker registry. This is a crucial piece of infrastructure for any professional DevOps environment, enabling secure and efficient distribution of container images.
Key Takeaways:
- Private registries are essential for security, control, and performance.
- A secure registry requires both authentication (e.g.,
htpasswd) and encryption (TLS/SSL). - Using Docker Compose provides a clean, declarative way to manage your registry configuration.
- Docker clients must be configured to trust the registry's SSL certificate, especially if it's self-signed.
- The workflow (
login,tag,push) is the same as for public registries; only the registry URL in the tag is different. - For advanced needs, enterprise solutions like Harbor offer features like vulnerability scanning and RBAC.
In our next lesson, we will dive deeper into the images you've just pushed. You will learn to inspect image layers and container configurations using docker inspect, allowing you to analyze and debug your containerized applications with precision.