Skip to main content

Docker Registry

What is Docker Registry?​

Docker Registry (also called Distribution) is the official open-source server for storing and distributing Docker images. Running your own instance lets you push and pull images without relying on Docker Hub or a paid registry service, useful for private images, air-gapped environments, or CI pipelines that need a local cache. Laradock builds it from the official registry:2 image.

Start Docker Registry​

./laradock start docker-registry

Stop Docker Registry​

Stopping just pauses the container; your images on disk are safe:

./laradock stop docker-registry

To delete the container entirely (the data on disk is untouched, it lives under DATA_PATH_HOST/docker-registry):

./laradock remove docker-registry

Configuration​

All settings live in docker-registry/defaults.env and can be overridden by adding the same line to your own .env:

VariableDefaultWhat it does
DOCKER_REGISTRY_PORT5000Host-side port the registry's HTTP API is published on (host:5000).

That's the only variable Laradock exposes; everything else is the stock registry:2 image behavior, tunable by adding an environment: block to docker-registry/compose.yml (see Secure the registry with authentication and Enable image deletion and garbage collection below).

Push and pull images​

The registry stores image data under DATA_PATH_HOST/docker-registry on your host (mounted to /var/lib/registry in the container), so images survive container restarts and rebuilds.

From your host machine (registry reachable on localhost:5000 by default):

docker tag your-image:latest localhost:5000/your-image:latest
docker push localhost:5000/your-image:latest
docker pull localhost:5000/your-image:latest

From another container on Laradock's backend network, use the container name instead of localhost: docker-registry:5000.

Browse what's stored (the catalog API)​

The registry has no built-in web UI, but it exposes its contents over its own HTTP API. List every repository:

curl http://localhost:5000/v2/_catalog

List the tags pushed for one repository:

curl http://localhost:5000/v2/your-image/tags/list

Backup and restore​

Back up every image by archiving the data folder on your host (stop the container first so nothing is mid-write):

./laradock stop docker-registry
tar -czf docker-registry-backup.tar.gz -C "${DATA_PATH_HOST:-~/.laradock/data}/docker-registry" .

Restore by extracting that archive back into the data folder before starting the container again:

mkdir -p "${DATA_PATH_HOST:-~/.laradock/data}/docker-registry"
tar -xzf docker-registry-backup.tar.gz -C "${DATA_PATH_HOST:-~/.laradock/data}/docker-registry"

This is a plain filesystem copy, no special export/import tool is needed since the registry's storage driver is just files on disk.

Start completely fresh (wipe all data)​

To throw away every pushed image and start from a clean, empty registry (this permanently deletes everything in it, back up first if you need anything):

./laradock stop docker-registry
./laradock remove docker-registry
rm -rf "${DATA_PATH_HOST:-~/.laradock/data}/docker-registry"
./laradock start docker-registry

DATA_PATH_HOST is whatever you have set in .env (~/.laradock/data by default), so the folder above is where every pushed image actually lives on your machine.

Enable image deletion and garbage collection​

By default the registry accepts pushes but refuses DELETE requests, so old tags pile up forever. To allow deleting image manifests, add an environment: block to the docker-registry service in docker-registry/compose.yml:

environment:
- REGISTRY_STORAGE_DELETE_ENABLED=true

Then rebuild:

./laradock restart docker-registry

Deleting a manifest only unlinks it, it doesn't reclaim disk space right away. Run the registry's own garbage collector afterward to actually free it up:

./laradock enter docker-registry
registry garbage-collect /etc/docker/registry/config.yml

Secure the registry with authentication​

Out of the box the registry has no authentication, anyone who can reach DOCKER_REGISTRY_PORT can push and pull. That's fine on a machine only you can reach, but worth locking down if the port is ever exposed beyond your own host. The stock registry:2 image supports HTTP Basic auth via an htpasswd file: generate one, mount it, and point the registry at it with an environment:/volumes: block in docker-registry/compose.yml:

environment:
- REGISTRY_AUTH=htpasswd
- REGISTRY_AUTH_HTPASSWD_REALM=Registry Realm
- REGISTRY_AUTH_HTPASSWD_PATH=/auth/htpasswd
volumes:
- ./docker-registry/auth:/auth

Generate the htpasswd file with htpasswd (from the apache2-utils/httpd-tools package) before starting:

htpasswd -Bc docker-registry/auth/htpasswd your-username

After that, docker login localhost:5000 is required before any push/pull against this registry.

Common issues​

  • http: server gave HTTP response to HTTPS client. The stock registry image serves plain HTTP, not HTTPS. Docker's client refuses to push/pull over HTTP to a registry it doesn't consider localhost by default. If you're hitting it from another machine or a non-localhost hostname, add it to your Docker daemon's insecure-registries list.
  • Port already in use on your host. Another local registry (or another Laradock project) is already bound to 5000. Change DOCKER_REGISTRY_PORT in .env and restart: ./laradock restart docker-registry.
  • Pushed images disappear after a rebuild. Confirm DATA_PATH_HOST didn't change between runs. The registry's storage is bind-mounted from your host, so a different DATA_PATH_HOST means a different (empty) image store.
  • Two Laradock projects overwrite each other's images. Running more than one Laradock on the same machine? Set both COMPOSE_PROJECT_NAME and DATA_PATH_HOST to unique values per project, otherwise they share the same registry data on disk.
  • DELETE requests return 405 Method Not Allowed. Image deletion is off by default, see Enable image deletion and garbage collection above.

Need to build and run Docker-in-Docker for CI-style workflows? See Docker in Docker. New to Laradock? Start at Getting Started.