logo
Back
Share
Share to LinkedIn
Share to Facebook
Share to Twitter
Share to Hacker News
Share to Telegram
Table of Contents
DevOpsDockerBackendDocker Compose

Seft host docker registry on VPS - Part 1

May 27, 2025
6 min read
18 views
Seft host docker registry on VPS - Part 1

While you're working with registries, you might hear the terms registry and repository as if they're interchangeable. Even though they're related, they're not quite the same thing. A registry is a centralized location that stores and manages container images, whereas a repository is a collection of related container images within a registry. Think of it as a folder where you organize your images based on projects. Each repository contains one or more container images.

The first, we need to know what, why we use docker registry.

What is a Docker Registry?

A Docker registry is a service that stores and distributes Docker images. It is an essential component in the Docker ecosystem, providing a centralized location to manage and share container images.

Is is a storage and content delivery system that holds named Docker images, available in different tagged versions. Users can push images to the registry and pull images from the registry.

Why Use a Docker Registry?

1.Centralized Image Management:

A Docker registry provides a centralized location to store and manage Docker images. This makes it easier to organize, version, and share images across different environments and teams.

2.Efficient Image Distribution:

Docker registries enable efficient distribution of Docker images. Instead of manually transferring images between systems, you can push images to the registry and pull them from any location with network access.

3.Version Control:

Docker registries support versioning of images through tags. This allows you to maintain multiple versions of an image, making it easier to roll back to previous versions if needed.

4.Collaboration

A Docker registry facilitates collaboration among development teams. Team members can push their images to the registry and share them with others, ensuring consistency and reproducibility across different environments.

5.Deployment Automation

Docker registries are often integrated into CI/CD pipelines. This allows for automated building, testing, and deployment of Docker images, streamlining the development and deployment process.

6.Security

Using a private Docker registry allows you to control access to your images. You can implement authentication and authorization mechanisms to ensure that only authorized users can push or pull images.

Benefits of Using a Docker Registry:

Centralized Storage: Keeps Docker images in one place, making them easy to find and manage.

Efficient Sharing: Simplifies sharing images between teams or environments without manual file transfers.

Version Management: Tracks different image versions using tags for easy updates or rollbacks.

Collaboration: Enables teams to work together seamlessly by accessing shared images in the registry.

CI/CD Integration: Automates image building, testing, and deployment in development pipelines.

Enhanced Security: Restricts image access with authentication and authorization controls.

Simple Example:

Imagine a software team developing a web app.

1.Without a Docker Registry:

Each developer has to manually share their Docker images via email or external drives, leading to confusion about which version is the latest and wasting time.

2.With a Docker Registry:

• Developer A builds a new app image and tags it webapp:v2.0.

• They push the image to the registry.

• Developer B pulls webapp:v2.0 from the registry and runs it without needing extra steps.

• Later, the CI/CD pipeline automatically deploys webapp:v2.0 to production, ensuring everyone uses the same version.

This streamlines collaboration, ensures consistency, and integrates smoothly with deployment workflows.

Hope that your guys have some info about docker registry so how to use docker registry?

Here are some popular Docker registries, both public and private, that you can use to store and manage your Docker image

Docker Hub

Description: Docker Hub is the default public registry provided by Docker. It hosts a vast collection of public images and allows users to create private repositories as well. It is widely used and integrated with Docker CLI by default.
Rate Limits:
Anonymous users: 100 pulls per 6 hours per IP address.
Authenticated users: 200 pulls per 6 hours per user.
Storage Limits:
Free plan: Limited to one private repository.
Paid plans: Higher storage limits and more private repositories.
Retention Policy:
Free plan: Inactive images (not pulled in 6 months) are subject to deletion.
Paid plans: No retention limits.

GitHub Container Registry

URL: github.com/features/packages
Description: GitHub Container Registry is part of GitHub Packages and allows you to host Docker images alongside your source code. It supports both public and private repositories.
Storage Limits:
Free plan: 500 MB of storage per repository.
Paid plans: Higher storage limits based on the GitHub plan.
Bandwidth Limits:
Free plan: 1 GB of data transfer per month.
Paid plans: Higher data transfer limits based on the GitHub plan.
Retention Policy:
No specific retention policy, but subject to GitHub's overall usage limits.

Google Container Registry (GCR)

URL: cloud.google.com/container-registry
Description: Google Container Registry is a private Docker registry provided by Google Cloud. It integrates with Google Cloud services and supports both public and private images.
Storage Limits:
No specific storage limits, but charges apply based on the amount of storage used.
Bandwidth Limits:
No specific bandwidth limits, but charges apply based on data transfer.
Retention Policy:
No specific retention policy, but charges apply based on storage duration.

Amazon Elastic Container Registry (ECR)

URL: aws.amazon.com/ecr
Description: Amazon ECR is a fully managed Docker container registry provided by AWS. It integrates with other AWS services and supports both public and private repositories.
Storage Limits:
Charges apply based on the amount of storage used.
Bandwidth Limits:
No specific bandwidth limits, but charges apply based on data transfer.
Retention Policy:
No specific retention policy, but charges apply based on storage duration.

Azure Container Registry (ACR)

URL: azure.microsoft.com/services/container-registry
Description: Azure Container Registry is a managed Docker registry service provided by Microsoft Azure. It integrates with Azure services and supports both public and private repositories.
Storage Limits:
Basic tier: 10 GB.
Standard tier: 100 GB.
Premium tier: 500 GB.
Bandwidth Limits:
No specific bandwidth limits, but charges apply based on data transfer.
Retention Policy:
No specific retention policy, but charges apply based on storage duration.

Each Docker registry has its own set of limits and considerations and special those have fee. The docker hub do have limit but we need to public the image but there are situations where you will not want your image to be publicly available. Images typically contain all the code necessary to run an application, so using a private registry is preferable when using proprietary software. This is reason I written this blogs.

In this tutorial, you will set up and secure your own private Docker Registry. You will use docker compose to define configurations to run your Docker containers and Nginx to forward server traffic from the internet to the running Docker container. Once we completed this tutorial, we will be able to push a custom Docker image to owner private registry and pull the image securely from a remote server.

What stuff do we need to have:

One VPS server (EC2 or sth else)
Domain name (we can use IP but I prefer to use domain)
Server config such as Nginx, SSL - We can use free SSL (certbot)

In the server, create folder to setup docker compose for docker registry

Code
1mkdir ~/docker-registry

Create and open a file called docker-compose.yml by running:

Code
1nano docker-compose.yml //OR sudo vim docker-compose.yml

Add config for ~/docker-registry/docker-compose.yml, which define a basic instance of a Docker Registry:

Code
1version: "3" 2 3services: 4 registry: 5 container_name: asta-registry # Name of the service 6 image: registry:2 # Image of the service 7 ports: 8 - "5500:5000" # Port mapping => host:container 9 environment: 10 REGISTRY_STORAGE_FILESYSTEM_ROOTDIRECTORY: /var/lib/registry 11 volumes: 12 - registry-data:/var/lib/registry # Volume mapping => host:container 13 14volumes: 15 registry-data:

Run docker compose

Code
1docker-compose up -d

Output:

Code
1~/docker-registry# docker compose up 2 3WARN[0000] /root/docker-registry/docker-compose.yml: the attribute version is obsolete.. 4[+] Running 6/6 5✔ registry Pulled 32.1s 6✔ dc0decf4841d Pull complete 12.1s 7✔ 6cb0aa443e23 Pull complete 12.4s 8✔ 813676e291ef Pull complete 12.7s 9✔ dc2fb7dcec61 Pull complete 17.5s 10✔ 916205650bfe Pull complete 17.5s 11[+] Running 3/3 12Network docker-registry_default Created 0.1s 13Volume "docker-registry_registry-data" C... 0.0s 14Container docker-registry-registry-1 Cre... 0.2s 15....

Verify the Registry is Running:

You can verify that the registry is running by accessing it in your web browser or using

Code
1curl http://<your-vps-ip>:5500/v2/

or on check directly on server

Code
1curl 127.0.0.1:5500/v2/

Output logs:

Code
1~/docker-registry# docker logs asta-registry --tail 100 2[02/Dec/2024:04:50:30 +0000] "GET /v2 HTTP/1.1" 301 39 "" "curl/7.81.0"

Setup basic authentication:

Install apache2-utils

Code
1sudo apt-get update && sudo apt-get install apache2-utils

Create the .htpasswd file and add a user - admin

Code
1sudo sh -c "echo -n 'admin:' >> /etc/nginx/basic-auth/.htpasswd"

Config password

Code
1sudo sh -c "openssl passwd -apr1 >> /etc/nginx/basic-auth/.htpasswd"
You will be prompted to enter and confirm a password - confirm password for the user admin.

Check config account after run cli above:

Code
1cat /etc/nginx/basic-auth/.htpasswd

Output

Code
1# cat /etc/nginx/basic-auth/.htpasswd 2admin:$apr1$yakYFrZz$9o/Pr1OoQzMhzqG3OJWE51

Note: Setting up basic authentication for your Docker registry is important to secure access to your registry. Without authentication, anyone who knows the address of your registry can push or pull images, which can lead to unauthorized access and potential security risks

Configure Nginx:

Edit your Nginx configuration file (e.g., /etc/nginx/sites-available/default) to include the following configuration

Code
1server { 2 listen 80; 3 server_name your-domain.com; # Change this to your domain - e.g. registry.astalife.co 4 return 301 https://$host$request_uri; 5} 6 7server { 8 listen 443 ssl; 9 server_name your-domain.com; 10 11 ssl_certificate /etc/nginx/certs/cert.crt; # Change this to your SSL certificate 12 ssl_certificate_key /etc/nginx/certs/cert.key; # Change this to your SSL certificate key 13 14 location / { 15 auth_basic "Private Docker Registry"; 16 auth_basic_user_file /etc/nginx/basic-auth/.htpasswd; 17 18 proxy_pass http://localhost:5500; # change correct port config in docker compose 19 proxy_set_header Host $host; 20 proxy_set_header X-Real-IP $remote_addr; 21 proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 22 proxy_set_header X-Forwarded-Proto $scheme; 23 } 24}
Replace your-domain.com with your actual domain name.
Ensure the paths to the SSL certificate and key files are correct. (you can try to use Certbot generate SSL)

Restart Nginx to apply the changes:

Code
1sudo systemctl restart nginx

Now you can verify the Registry is Running:

Code
1curl https://your-domain/v2

Response should be returned {}

Public image

Now that your Docker Registry server is up and running, and accepting large file sizes, you can try pushing an image to it. Since you don’t have any images readily available, you’ll use the ubuntu image from Docker Hub, a public Docker Registry, to test.

From server create test image

Code
1root@84737:~# docker commit $(docker ps -lq) test-image

Check the image

Code
1root@84737:~# docker image ls 2REPOSITORY TAG IMAGE ID CREATED SIZE 3test-image latest 40e310570178 About a minute ago 25.4MB

The new image is now available locally, and you’ll push it to your new container registry. First, you have to log in:

Code
1docker login https://your_domain

In my case, I use ~ docker login https://registry.astalife.co. Then enter user name and password that we configured above

Code
1root@84737:~# docker login https://registry.astalife.co 2Username: admin 3Password: 4WARNING! Your password will be stored unencrypted in /root/.docker/config.json. 5Configure a credential helper to remove this warning. See 6https://docs.docker.com/engine/reference/commandline/login/#credential-stores 7 8Login Succeeded

Once we’re logged in, tag the created image:

Code
1docker tag test-image your_domain/test-image 2#(example in my case) docker tag test-image registry.astalife.co/test-image

Finally, push the newly tagged image to your registry:

Code
1docker push your_domain/test-image

Output:

Code
1root@84737:~# docker push registry.astalife.co/test-image 2Using default tag: latest 3The push refers to repository [registry.astalife.co/test-image] 4a29d2590f411: Pushed 57827cbf539f4: Pushed 6.... 7latest: digest: sha256:f11fb5228b787b42fa6553a2ba....e9dee size: 1570

Open https://registry.astalife.co/v2/_catalog to check iamge pushed

Output:

Code
1{"repositories":["test-image"]}

Pull image from private registry from client:

Now that we’ve pushed an image to your private registry, we can pull from it.

On the client, log in with the username and password you set up previously:

Code
1docker login https://your_domain

Pulling the test-image by running:

Code
1docker pull your_domain/test-image 2Using default tag: latest 3latest: Pulling from test-image 4dc0decf4841d: Pull complete 56cb0aa443e23: Pull complete 6.... 7Status: Downloaded newer image for registry.astalife.co/test-image:latest 8registry.astalife.co/test-image:latest

Check docker image

Code
1docker images 2REPOSITORY TAG IMAGE ID CREATED SIZE 3registry.astalife.co/test-image latest 40e310570178 28 minutes ago 25.4MB

Now you can use this image from the client to.

Conclusion

In this post we set up our own private Docker Registry, and published a Docker image to it. By Docker containers in your workflow, you can ensure that the image containing the code will result in the same behavior on any machine, whether in production or in development and avoid some limit such as Bandwidth, Storage.

Get more code setup: https://github.com/AstaDK/private-docker-registry/tree/feat/private-registry-ss1

Tags

DevOpsDockerBackendDocker Compose