Mirror container images via OCI tarballs
Project description
regmirror
Mirror container images through OCI tarballs to a private registry.
regmirror uses skopeo to pull images from any public or private registry, store them as OCI archive tarballs on disk, and re-push them to a private registry with automatic domain path rewriting.
Why?
Air-gapped or restricted environments often can't reach public registries directly. regmirror lets you:
- Pull images on a machine with internet access
- Transfer the tarballs to the restricted environment (USB, S3, SCP, etc.)
- Push them to an internal registry with predictable, collision-free names
Requirements
- Python 3.10+
skopeoinstalled and on$PATH
Installation
uv tool install regmirror
Or run without installing:
uvx regmirror
Alternatively with pipx/pip:
pipx install regmirror
# or
pip install regmirror
Usage
Download images to tarballs
./regmirror.py download -f images.txt -o ./tarballs
Upload tarballs to a private registry
./regmirror.py upload -d ./tarballs -r my.registry.tld
Download and upload in one step
./regmirror.py sync -f images.txt -o ./tarballs -r my.registry.tld
Preview the manifest and upload targets
./regmirror.py list -d ./tarballs -r my.registry.tld
Image list file
The -f / --file argument points to a plain text file with one image reference per line. Lines starting with # are ignored.
# Example images.txt
nginx:1.25
docker.io/library/redis:7
gcr.io/google-containers/pause:3.9
quay.io/prometheus/prometheus:v2.51.0
Name rewriting
Source registry domains are flattened into a path prefix to avoid conflicts:
| Source | Target |
|---|---|
docker.io/library/nginx:1.25 |
my.registry.tld/dockerio/library/nginx:1.25 |
gcr.io/project/app:v1 |
my.registry.tld/gcrio/project/app:v1 |
quay.io/prometheus/prometheus:v2.51.0 |
my.registry.tld/quayio/prometheus/prometheus:v2.51.0 |
manifest.json
Every download run writes a manifest.json into the tarball directory. This file maps each tarball filename back to its original image reference, making the conversion fully reversible without fragile filename encoding.
{
"nginx-1.25.tar": {
"original": "nginx:1.25",
"registry": "docker.io",
"image": "library/nginx",
"tag": "1.25",
"digest": "sha256:a484819eb60211f5299034ac80f6a681b06f89e476600f94c25bde91c7f7e88c"
}
}
After a successful download the resolved sha256: digest is stored alongside the tag. On subsequent runs regmirror uses this digest to detect whether the tag now points to a newer image — if it does, the tarball is re-downloaded automatically. Use --force to re-download unconditionally regardless of the stored digest.
The upload and list commands require this file to be present.
Command reference
download
| Flag | Default | Description |
|---|---|---|
-f, --file |
(required) | Text file with image references |
-o, --output |
./tarballs |
Directory to write tarballs and manifest |
--force |
false | Re-download tarballs unconditionally, ignoring stored digest |
--src-tls-verify BOOL |
— | Override TLS verification for the source registry |
--src-creds USER:PASS |
— | Credentials for the source registry |
--authfile FILE |
— | Path to a Docker-compatible auth.json |
--remove-signatures |
auto | Strip embedded image signatures; applied automatically when detected, or pass explicitly to always strip |
upload
| Flag | Default | Description |
|---|---|---|
-d, --dir |
./tarballs |
Directory containing tarballs and manifest |
-r, --registry |
(required) | Target registry (e.g. my.registry.tld) |
--dest-tls-verify BOOL |
— | Override TLS verification for the target registry |
--dest-creds USER:PASS |
— | Credentials for the target registry |
--authfile FILE |
— | Path to a Docker-compatible auth.json |
--remove-signatures |
false | Strip image signatures during push |
sync
Accepts all flags from both download and upload, plus:
| Flag | Default | Description |
|---|---|---|
--continue-on-error |
false | Continue with upload even if some downloads failed |
list
| Flag | Default | Description |
|---|---|---|
-d, --dir |
./tarballs |
Directory containing the manifest |
-r, --registry |
— | Preview what the upload targets would be |
Building the package
Install the build tools:
pip install build hatchling
Build both the wheel and source distribution:
python -m build
This outputs dist/regmirror-<version>-py3-none-any.whl and
dist/regmirror-<version>.tar.gz.
Install locally to test before publishing:
uv tool install dist/regmirror-*.whl
# or
pipx install dist/regmirror-*.whl
Publish to PyPI:
pip install twine
twine upload dist/*
Global flags
| Flag | Description |
|---|---|
--dry-run |
Print skopeo commands without executing them |
--version |
Print version and exit |
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file regmirror-1.2.1.tar.gz.
File metadata
- Download URL: regmirror-1.2.1.tar.gz
- Upload date:
- Size: 21.9 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
a122089e1bf24cf1972457ec15d0f8d5306254e7e9630482878484da2bfd1f5a
|
|
| MD5 |
0af87be22fb71af233f65569a530d448
|
|
| BLAKE2b-256 |
f78b029eba583ca79f078e6a700d2de5fdc08e46473aa744ce0bab468c4cac3d
|
Provenance
The following attestation bundles were made for regmirror-1.2.1.tar.gz:
Publisher:
publish.yml on WatskeBart/regmirror
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
regmirror-1.2.1.tar.gz -
Subject digest:
a122089e1bf24cf1972457ec15d0f8d5306254e7e9630482878484da2bfd1f5a - Sigstore transparency entry: 1019239284
- Sigstore integration time:
-
Permalink:
WatskeBart/regmirror@fc7d01981a9f5060a1f10866a04420fcf4ccffdd -
Branch / Tag:
refs/tags/1.2.1 - Owner: https://github.com/WatskeBart
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@fc7d01981a9f5060a1f10866a04420fcf4ccffdd -
Trigger Event:
push
-
Statement type:
File details
Details for the file regmirror-1.2.1-py3-none-any.whl.
File metadata
- Download URL: regmirror-1.2.1-py3-none-any.whl
- Upload date:
- Size: 21.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
3dd04005b57cf9e8b01879bdb3019aa84efd5577be3372b0514d6bc2285daa2d
|
|
| MD5 |
70bacb6d885b0c058dcd564271258df7
|
|
| BLAKE2b-256 |
69f865ca7eaa0418c2d39766320edd8c18ffe5ece1c30a51daca29c481985591
|
Provenance
The following attestation bundles were made for regmirror-1.2.1-py3-none-any.whl:
Publisher:
publish.yml on WatskeBart/regmirror
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
regmirror-1.2.1-py3-none-any.whl -
Subject digest:
3dd04005b57cf9e8b01879bdb3019aa84efd5577be3372b0514d6bc2285daa2d - Sigstore transparency entry: 1019239293
- Sigstore integration time:
-
Permalink:
WatskeBart/regmirror@fc7d01981a9f5060a1f10866a04420fcf4ccffdd -
Branch / Tag:
refs/tags/1.2.1 - Owner: https://github.com/WatskeBart
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@fc7d01981a9f5060a1f10866a04420fcf4ccffdd -
Trigger Event:
push
-
Statement type: