Docker Hub is the default place to store Docker images. But it has its limitations — and there's a better way, especially if you already have your own infrastructure.
Docker Hub on the free plan:
hub.docker.com/u/yourname/app doesn't feel like your own infrastructureGitLab Community Edition has a built-in Container Registry. After setting up your own GitLab, you immediately get a registry under your own domain — no extra configuration needed.
Example from my project minio-dash — a MinIO admin panel written in Python/Flask. The image lives on my own registry:
# Pull from own registry
docker pull registry.racis.dev/marceliracis/minio-dash:latest
# Run
docker run -d \
--name minio-dash \
--restart unless-stopped \
-p 7474:7474 \
-e MINIO_ENDPOINT=https://s3.example.com \
-e SECRET_KEY=changeme \
registry.racis.dev/marceliracis/minio-dash:latest
Instead of hub.docker.com/u/marceliracis/minio-dash I have registry.racis.dev/marceliracis/minio-dash — under my own domain, on my own server.
Integration with code — repo and images in one place. A CI/CD pipeline builds the image and immediately pushes it to the registry without leaving your own infrastructure. In minio-dash I have a .gitlab-ci.yml that automatically builds and pushes the image on every commit.
No pull limits — your server can pull images as many times as it wants, no throttling. With frequent deploys, this matters.
Privacy — images are only accessible to people with access to your GitLab.
Deploy tokens — you can create a read-only registry token for the production server, without giving it full access to the code.
Multi-arch in one place — I build images for both amd64 and arm64 simultaneously and push to my own registry:
docker buildx build \
--platform linux/amd64,linux/arm64 \
-t registry.racis.dev/marceliracis/minio-dash:latest \
--push \
.
# Log in to the registry
docker login registry.racis.dev
# Build and push in one command (buildx)
docker buildx build \
--platform linux/amd64,linux/arm64 \
-t registry.racis.dev/project/app:v1 \
-t registry.racis.dev/project/app:latest \
--push \
.
A self-hosted registry is a natural extension of self-hosted GitLab. Code, pipelines, and images in one place, under your own domain, without limits and without dependency on external services. If you already have a self-hosted GitLab — you get the registry for free.