Skip to content

registry-proxy init source ​

A pull-through cache for Docker Hub, as required by conventional/container-images.md. With it in front, builds and CI keep working when Docker Hub is down or throttling, and every image is fetched from Docker Hub once rather than once per job.

Contents ​

FileWhat it is
docker-compose.ymlThe proxy: registry:3.1.1 in proxy mode, pinned by digest

Deploying (host owner) ​

On the registry host (10.0.0.106):

  1. Copy this directory to the host.

  2. Optional: create .env next to docker-compose.yml with Docker Hub credentials, which raise the pull limit. Use a read-only access token, never a password, and never commit the file:

    REGISTRY_PROXY_USERNAME=<docker hub user>
    REGISTRY_PROXY_PASSWORD=<read-only access token>
  3. Start it:

    bash
    docker compose up -d
  4. Check that it answers for an official image. Official images live under library/; a bare postgres is not found:

    bash
    curl -s -o /dev/null -w '%{http_code}\n' \
      -H 'Accept: application/vnd.oci.image.index.v1+json' \
      http://10.0.0.106:5001/v2/library/postgres/manifests/18.6-trixie
    # 200

It is a second registry, next to the one on port 5000, because a registry in proxy mode refuses pushes: the same instance cannot be both our push target and a mirror.

Pointing a Docker host at it ​

On each workstation and on the CI runner - the integration jobs use the runner's own Docker daemon - add the proxy to /etc/docker/daemon.json, keeping whatever is already there:

json
{
  "registry-mirrors": ["http://10.0.0.106:5001"],
  "insecure-registries": ["10.0.0.106:5000", "10.0.0.106:5001"]
}

Then sudo systemctl restart docker, and check that docker info lists it under Registry Mirrors. Image names in the repositories do not change, and Docker falls back to Docker Hub when the proxy is down.

Confirming a pull went through it ​

A mirror that is configured but bypassed looks exactly like one that works, so check once per host:

bash
docker pull redis:8.8.2-trixie
curl -s http://10.0.0.106:5001/v2/_catalog
# {"repositories":["library/redis", ...]}

If the repository does not appear, the daemon went straight to Docker Hub - fix that before relying on the proxy.

Where the daemon cannot be configured ​

Docker-in-docker, or a runtime other than Docker: name the proxy in the image, with the library/ segment for official images:

registry:5001/library/postgres:18.6-trixie

For testcontainers, set the prefix and write official images with library/:

bash
export TESTCONTAINERS_HUB_IMAGE_NAME_PREFIX=registry:5001
go
Image: "library/postgres:18.6-trixie",

testcontainers adds the prefix only to Docker Hub names and never adds library/ itself, which is why the image has to carry it.