Skip to content

Example: Set up a registry mirror


  • Increase speed of pulls and builds by caching images on Actuated Servers
  • Reduce failed builds due to rate-limiting

If you use Docker in your self-hosted builds, there is a chance that you'll run into the rather conservative rate-limits.

See also: Download rate limit

The Docker Hub allows for 100 image pulls within a 6 hour period, but this can be extended to 200 by logging in, or to 5000 by paying for a Pro license.

A registry mirror / pull-through cache running on an actuated agent is significantly faster than pulling from a remote server.

We will create a mirror that:

  • Has no authentication, to keep the changes to your build to a minimum
  • Cannot support PUSH / PUT / DELETE events
  • Only has access to pull images from the Docker Hub
  • Is not exposed to the Internet, but only to Actuated VMs
  • When unavailable for any reason, the build continues without error
  • Works on both Intel/AMD and ARM64 hosts

This tutorial shows you how to set up what was previously known as "Docker's Open Source Registry" and is now a CNCF project called distribution.

Certified for:

  • x86_64
  • arm64

Create a Docker Hub Access token

Create a Docker Hub Access token with "Public repos only" scope, and save it as ~/hub.txt on the Actuated Server.

Settings for a public token

Settings for an authorization token, with read-only permissions to public repositories

Set up the registry on an actuated agent

curl -sLS | sudo sh

sudo arkade system install registry

sudo mkdir -p /etc/registry
sudo mkdir -p /var/lib/registry

Create a config file to make the registry only available on the Linux bridge for Actuated VMs:

export TOKEN=$(cat ~/hub.txt)
export USERNAME=""

cat >> /tmp/registry.yml <<EOF
version: 0.1
    disabled: true
  level: warn
  formatter: text

    rootdirectory: /var/lib/registry

  username: $USERNAME

  # A Docker Hub Personal Access token created with "Public repos only" scope
  password: $TOKEN

  relativeurls: false
  draintimeout: 60s

sudo mv /tmp/registry.yml /etc/registry/config.yml

Install and start the registry with a systemd unit file:

cat >> /tmp/registry.service <<EOF

ExecStart=/usr/local/bin/registry serve /etc/registry/config.yml


sudo mv /tmp/registry.service /etc/systemd/system/registry.service
sudo systemctl daemon-reload
sudo systemctl enable registry --now

Check the status with:

sudo journalctl -u registry

Use the registry within a workflow

Create a new registry in your organisation, along with a: .github/workspaces/build.yml file and commit it to the repository.

name: CI

      - '*'
      - master
      - main

        runs-on: [actuated]

        - name: Setup mirror
          uses: self-actuated/hub-mirror@master

        - name: Checkout
            uses: actions/checkout@v2

        - name: Pull image using cache
            run: |
            docker pull alpine:latest

Checking if it worked

You'll see the build run, and cached artifacts appearing in: /var/lib/registry/.

find /var/lib/registry/ -name "alpine"


You can also use the registry's API to query which images are available:

curl -i

HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
Docker-Distribution-Api-Version: registry/2.0
Date: Wed, 16 Nov 2022 09:41:18 GMT
Content-Length: 52


You can check the status of the mirror at any time with:

sudo journalctl -u registry --since today

Further reading