Pool-based content-addressable APT repository mirror sync with global deduplication via hardlinks.
Features
- Pool-based content-addressable storage: every unique file is stored once by SHA-256 hash
- Hardlink deduplication across all mirrored repositories
- HTTPS-based sync with automatic upstream failover
- Auto-discovery of distributions, architectures, and components via HTTP probing
- Snapshot/restore system for safe repository migrations
- Glob pattern support for distributions (e.g.
noble*,*/mongodb-org/7.0) - GPG key URL tracking in per-repo configuration
- Stale pool orphan detection and cleanup (
--sweep-pool)
Installation
Option 1: Debian/Ubuntu Package (Recommended)
Install from the MungerWare apt repository:
curl -fsSL https://apt.mungerware.com/key.asc \
| sudo gpg --dearmor -o /usr/share/keyrings/mungerware-archive-keyring.gpg
echo "deb [signed-by=/usr/share/keyrings/mungerware-archive-keyring.gpg] https://apt.mungerware.com noble main" \
| sudo tee /etc/apt/sources.list.d/mungerware.list
sudo apt update && sudo apt install mirror-dedupe
This includes systemd integration, man pages, nginx configuration, and proper package management.
Alternatively, download the latest .deb package from GitHub Releases:
curl -fsSL https://api.github.com/repos/munger/mirror-dedupe/releases/latest \
| grep browser_download_url | grep all.deb | head -1 | cut -d'"' -f4 \
| xargs wget
sudo dpkg -i mirror-dedupe_*.deb
Option 2: PyPI (All Linux Distributions)
pip install mirror-dedupe
Then install systemd files manually:
sudo ./install.sh --pip
Option 3: From Source
git clone https://github.com/munger/mirror-dedupe.git
cd mirror-dedupe
sudo ./install.sh
Configuration
Configuration files are located in /etc/mirror-dedupe/:
mirror-dedupe.conf— Global settings (mirror_root, concurrency, etc.)repos-available/— Available repository configurationsrepos-enabled/— Enabled repositories (symlinks to repos-available)
mirror_root is the single root for all mirror data. Repositories are stored
under <mirror_root>/repos and the deduplication pool under <mirror_root>/pool.
Both always share the same logical volume, which is required for hardlinks.
Adding a Repository
Use --scan to auto-generate configuration for a repository:
mirror-dedupe --scan --name grafana --out /etc/mirror-dedupe/repos-available https://apt.grafana.com
See config/repos-available/README.md for the full scan reference and
ready-made commands for all packaged example repositories.
Then test and enable it:
mirror-dedupe --test grafana
mirror-dedupe --activate grafana
Advanced: Alternative config directory
Override the default config directory with --config-dir:
mirror-dedupe --config-dir /tmp/mirror --test grafana
Pre-configured Repositories
The package includes pre-configured repository definitions in config/repos-available/.
Usage
# Sync all enabled mirrors
mirror-dedupe --sync
# Sync a specific mirror
mirror-dedupe --sync --mirror ubuntu
# Scan a repository and generate config (single release)
mirror-dedupe --scan --name ubuntu --release noble --out /etc/mirror-dedupe/repos-available http://archive.ubuntu.com/ubuntu
# Scan with all discovered architectures and distributions
mirror-dedupe --scan --name postgresql --no-filter --out /etc/mirror-dedupe/repos-available http://apt.postgresql.org/pub/repos/apt
# Scan without JSON snapshot
mirror-dedupe --scan --name grafana --out /etc/mirror-dedupe/repos-available https://apt.grafana.com
# Pool orphan sweep
mirror-dedupe --sweep-pool
# Create a hardlink snapshot of all repos
mirror-dedupe --snapshot
Systemd Integration
If installed via Debian package, systemd is already configured. Otherwise:
sudo systemctl enable --now mirror-dedupe.timer
sudo systemctl status mirror-dedupe.timer
View logs:
journalctl -u mirror-dedupe.service
Nginx Configuration
See nginx/mirror.conf for an example nginx configuration.
License
MIT License — see LICENSE file for details.
Author
Tim Hosking tim@mungerware.com
Release files for mirror-dedupe 1.2.4
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| mirror_dedupe-1.2.4.tar.gz | 176.1 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| mirror_dedupe-1.2.4-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 427.5 kB
Release files / mirror_dedupe-1.2.4.tar.gz
| Download URL | mirror_dedupe-1.2.4.tar.gz |
|---|---|
| Size | 176.1 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
ed54ff39d27555dfd83b57684ce66dbf466b61b5aced5bc95ebc9df3c3341124
|
|
BLAKE2b-256 checksum How to use checksums |
bf9573ddb9a13029c44a9630c3cf00d1a9a0e45961325bc5bfa162678b8bfde4
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.11.15
|
Release files / mirror_dedupe-1.2.4-py3-none-any.whl
| Download URL | mirror_dedupe-1.2.4-py3-none-any.whl |
|---|---|
| Size | 251.4 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
bebf17089632d773d6d0e347616293d9354831ecc62bb2238e879ca921939b31
|
|
BLAKE2b-256 checksum How to use checksums |
00a72db325ac59bf7c83ac586ca4f719d90b569efcaf6e205bd904bef14150ce
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.11.15
|