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.