close
Share feedback
Answers are generated based on the documentation.

Mirror a Docker Hardened Image repository

Subscription: Docker Hardened Images Select or Enterprise

Mirroring requires a DHI Select or Enterprise subscription. Without a subscription, you can pull Docker Hardened Images directly from dhi.io without mirroring. With a DHI Select or Enterprise subscription, you must mirror to your organization to get:

  • Compliance variants (FIPS-enabled or STIG-ready images)
  • Extended Lifecycle Support (ELS) variants (requires add-on)
  • Image or Helm chart customization
  • Air-gapped or restricted network environments
  • SLA-backed security updates

How to mirror

This topic covers two types of mirroring for Docker Hardened Image (DHI) repositories:

Mirror a DHI repository to your organization

You must be an organization owner or editor to mirror repositories.

  • Image repositories: Mirroring lets you customize images by adding packages, OCI artifacts (such as custom certificates or additional tools), environment variables, labels, and other configuration settings. For more details, see Customize a Docker Hardened Image.

  • Chart repositories: Mirroring lets you customize image references within the chart. This is particularly useful when using customized images or when you've mirrored images to a third-party registry and need the chart to reference those custom locations. For more details, see Customize a Docker Hardened Helm chart.

  1. Go to Docker Hub and sign in.
  2. Select My Hub.
  3. In the namespace drop-down, select your organization.
  4. Select Hardened Images > Catalog.
  5. Select a DHI repository to view its details.
  6. Mirror the repository:
    • To mirror an image repository, select Use this image > Mirror repository, and then follow the on-screen instructions. If you have the ELS add-on, you can also select Enable support for end-of-life versions.
    • To mirror a Helm chart repository, select Get Helm chart, and then follow the on-screen instructions.

It may take a few minutes for all the tags to finish mirroring.

Authenticate with docker login using your Docker credentials or a personal access token (PAT) with Read & Write permissions. Organization access tokens (OATs) are not supported.

Use the docker dhi mirror command:

$ docker dhi mirror start --org my-org \
  -r dhi/golang,my-org/dhi-golang \
  -r dhi/nginx,my-org/dhi-nginx \
  -r dhi/prometheus-chart,my-org/dhi-prometheus-chart

Mirror with dependencies:

$ docker dhi mirror start --org my-org -r dhi/golang,my-org/dhi-golang --dependencies

List mirrored images in your organization:

$ docker dhi mirror list --org my-org

Filter mirrored images by name or type:

$ docker dhi mirror list --org my-org --filter python
$ docker dhi mirror list --org my-org --type image
$ docker dhi mirror list --org my-org --type helm-chart

You can manage DHI mirrors as infrastructure-as-code using the DHI Terraform provider.

First, install and configure the provider:

terraform {
  required_providers {
    dhi = {
      source = "docker-hardened-images/dhi"
    }
  }
}

provider "dhi" {
  docker_hub_username = var.docker_username
  docker_hub_password = var.docker_password
  organization        = var.org_name
}
Note

Instead of specifying credentials in the provider block, you can set the DOCKER_USERNAME, DOCKER_PASSWORD, and DHI_ORG environment variables.

Then, define a dhi_mirror resource for each repository you want to mirror:

resource "dhi_mirror" "golang" {
  source_namespace = "dhi"
  source_name      = "golang"
  destination_name = "dhi-golang"
}

resource "dhi_mirror" "nginx" {
  source_namespace = "dhi"
  source_name      = "nginx"
  destination_name = "dhi-nginx"
}

To enable Extended Lifecycle Support (ELS) variants, set the els attribute:

resource "dhi_mirror" "golang" {
  source_namespace = "dhi"
  source_name      = "golang"
  destination_name = "dhi-golang"
  els              = true
}

Run terraform apply to create the mirrors.

For the full list of resource attributes, see the Terraform Registry documentation.

After mirroring, the repository appears in your organization's repository list, prefixed by dhi-, and continues to receive updated images. It behaves like any other Docker Hub repository, so you can manage access and permissions, configure webhooks, and use other standard Hub features. See Docker Hub repositories for details.

Stop mirroring a repository

After you stop mirroring, the repository remains, but it no longer receives updates. You can still use the last images or charts that were mirrored.

Note

If you only want to stop mirroring ELS versions, you can clear the ELS option in the mirrored repository's Settings tab.

  1. Go to Docker Hub and sign in.
  2. Select My Hub.
  3. In the namespace drop-down, select your organization that has access to DHI.
  4. Select Hardened Images > Manage.
  5. Select the Mirrored Images or Mirrored Helm charts tab.
  6. In the far right column of the repository you want to stop mirroring, select the menu icon.
  7. Select Stop mirroring.

Authenticate with docker login using your Docker credentials or a personal access token (PAT) with Read & Write permissions. Organization access tokens (OATs) are not supported.

Use the docker dhi mirror command:

$ docker dhi mirror stop --org my-org dhi-golang

To stop mirroring, remove the dhi_mirror resource from your Terraform configuration and run terraform apply. The repository remains in your organization but no longer receives updates.

Mirror a DHI repository to a third-party registry

After mirroring a DHI repository to your organization on Docker Hub, you can optionally mirror it to another container registry, such as Amazon ECR, Google Artifact Registry, GitHub Container Registry, or a private Harbor instance.

You can use any standard workflow to mirror the image, such as the Docker CLI, Docker Hub Registry API, third-party registry tools, or CI/CD automation.

However, to preserve the full security context, including attestations, you must also mirror its associated OCI artifacts. DHI repositories store the image layers on dhi.io (or docker.io for customized images) and the signed attestations in a separate registry (registry.scout.docker.com).

To copy both, you can use regctl, an OCI-aware CLI that supports mirroring images along with attached artifacts such as SBOMs, vulnerability reports, and SLSA provenance. For ongoing synchronization, you can use regsync.

Automate syncing with webhooks

To keep external registries or systems in sync with your mirrored Docker Hardened Images, and to receive notifications when updates occur, you can configure a webhook on the mirrored repository in Docker Hub. A webhook sends a POST request to a URL you define whenever a new image tag is pushed or updated.

For example, you might configure a webhook to call a CI/CD system at https://ci.example.com/hooks/dhi-sync whenever a new tag is mirrored. The automation triggered by this webhook can pull the updated image from Docker Hub and push it to an internal registry such as Amazon ECR, Google Artifact Registry, or GitHub Container Registry.

Other common webhook use cases include:

  • Triggering validation or vulnerability scanning workflows
  • Signing or promoting images
  • Sending notifications to downstream systems

Example webhook payload

When a webhook is triggered, Docker Hub sends a JSON payload like the following:

{
  "callback_url": "https://registry.hub.docker.com/u/exampleorg/dhi-python/hook/abc123/",
  "push_data": {
    "pushed_at": 1712345678,
    "pusher": "trustedbuilder",
    "tag": "3.13-alpine3.21"
  },
  "repository": {
    "name": "dhi-python",
    "namespace": "exampleorg",
    "repo_name": "exampleorg/dhi-python",
    "repo_url": "https://hub.docker.com/r/exampleorg/dhi-python",
    "is_private": true,
    "status": "Active",
    ...
  }
}

Example mirroring with regctl

The following example shows how to mirror a specific tag of a Docker Hardened Image from Docker Hub to another registry, along with its associated attestations using regctl. You must install regctl first.

The example assumes you have mirrored the DHI repository to your organization's namespace on Docker Hub as described in the previous section. You can apply the same steps to a non-mirrored image by updating the SRC_ATT_REPO and SRC_REPO variables accordingly.

  1. Set environment variables for your specific environment. Replace the placeholders with your actual values.

    In this example, you use a Docker username to represent a member of the Docker Hub organization that the DHI repositories are mirrored in. Prepare a personal access token (PAT) for the user with read only access. Alternatively, you can use your organization name and an organization access token (OAT) to authenticate with docker.io. Note that OATs are not supported for registry.scout.docker.com. If your workflow requires authenticating to the Scout registry, use a personal access token (PAT) for that step.

    Warning

    The following examples export credentials directly on the command line for demonstration purposes. This exposes sensitive tokens in your shell history and process list. In production environments, use secure methods such as reading from files with restricted permissions, environment files loaded at runtime, or secret management tools.

    $ export DOCKER_USERNAME="YOUR_DOCKER_USERNAME"
    $ export DOCKER_PAT="YOUR_DOCKER_PAT"
    $ export DOCKER_ORG="YOUR_DOCKER_ORG"
    $ export DEST_REG="registry.example.com"
    $ export DEST_REPO="mirror/dhi-python"
    $ export DEST_REG_USERNAME="YOUR_DESTINATION_REGISTRY_USERNAME"
    $ export DEST_REG_TOKEN="YOUR_DESTINATION_REGISTRY_TOKEN"
    $ export SRC_REPO="docker.io/${DOCKER_ORG}/dhi-python"
    $ export SRC_ATT_REPO="registry.scout.docker.com/${DOCKER_ORG}/dhi-python"
    $ export TAG="3.13-alpine3.21"
    
  2. Sign in via regctl to Docker Hub, the Scout registry that contains the attestations, and your destination registry.

    $ echo $DOCKER_PAT | regctl registry login -u "$DOCKER_USERNAME" --pass-stdin docker.io
    $ echo $DOCKER_PAT | regctl registry login -u "$DOCKER_USERNAME" --pass-stdin registry.scout.docker.com
    $ echo $DEST_REG_TOKEN | regctl registry login -u "$DEST_REG_USERNAME" --pass-stdin "$DEST_REG"
    
  3. Mirror the image and attestations using --referrers and referrer endpoints:

    $ regctl image copy \
         "${SRC_REPO}:${TAG}" \
         "${DEST_REG}/${DEST_REPO}:${TAG}" \
         --referrers \
         --referrers-src "${SRC_ATT_REPO}" \
         --referrers-tgt "${DEST_REG}/${DEST_REPO}" \
         --force-recursive
    
  4. Verify that artifacts were preserved.

    First, get a digest for a specific tag and platform. For example, linux/amd64.

    DIGEST="$(regctl manifest head "${DEST_REG}/${DEST_REPO}:${TAG}" --platform linux/amd64)"
    

    List attached artifacts (SBOM, provenance, VEX, vulnerability reports).

    $ regctl artifact list "${DEST_REG}/${DEST_REPO}@${DIGEST}"
    

    Or, list attached artifacts with docker scout.

    $ docker scout attest list "registry://${DEST_REG}/${DEST_REPO}@${DIGEST}"
    

Example ongoing mirroring with regsync

regsync automates pulling from your organizations mirrored DHI repositories on Docker Hub and pushing to your external registry including attestations. It reads a YAML configuration file and can filter tags.

The following example uses a regsync.yaml file that syncs Node 24 and Python 3.12 Debian 13 variants, excluding Alpine and Debian 12.

regsync.yaml
version: 1
# Optional: inline creds if not relying on prior CLI logins
# creds:
#   - registry: docker.io
#     user: <your-docker-username>
#     pass: "{{file \"/run/secrets/docker_token\"}}"
#   - registry: registry.scout.docker.com
#     user: <your-docker-username>
#     pass: "{{file \"/run/secrets/docker_token\"}}"
#   - registry: registry.example.com
#     user: <service-user>
#     pass: "{{file \"/run/secrets/dest_token\"}}"

sync:
  - source: docker.io/<your-org>/dhi-node
    target: registry.example.com/mirror/dhi-node
    type: repository
    fastCopy: true
    referrers: true
    referrerSource: registry.scout.docker.com/<your-org>/dhi-node
    referrerTarget: registry.example.com/mirror/dhi-node
    tags:
      allow: [ "24.*" ]
      deny: [ ".*alpine.*", ".*debian12.*" ]

  - source: docker.io/<your-org>/dhi-python
    target: registry.example.com/mirror/dhi-python
    type: repository
    fastCopy: true
    referrers: true
    referrerSource: registry.scout.docker.com/<your-org>/dhi-python
    referrerTarget: registry.example.com/mirror/dhi-python
    tags:
      allow: [ "3.12.*" ]
      deny: [ ".*alpine.*", ".*debian12.*" ]

To do a dry run with the configuration file, you can run the following command. You must install regsync first.

$ regsync check -c regsync.yaml

To run the sync with the configuration file:

$ regsync once -c regsync.yaml

What next

After mirroring, see Pull a DHI to learn how to pull and use mirrored images.