Because every other name was already taken. - A unified CLI tool for offline repository mirroring.
A Python-based CLI tool for offline repository mirroring, inspired by pulp-admin, reposync, and aptly.
The Problem: Enterprise environments need offline mirrors of RPM/APT repositories with version control, efficient storage, RHEL subscription support, and simple management. Existing tools either:
- Support only one repository type (
reposyncfor RPM,apt-mirrorfor APT) - Require complex infrastructure (Pulp needs Celery, RabbitMQ, Redis, PostgreSQL)
- Lack proper snapshot and deduplication features
The Solution: One simple CLI tool. No daemons, no message queues, no complex setup. Just sync repositories, create snapshots, and publish static files. Works with any webserver (Apache, NGINX) - because it's just files.
- π Unified Mirroring - Multiple repository types in one tool (RPM, DEB/APT, Helm, Alpine APK)
- π¦ Deduplication - Content-addressed storage (SHA256), packages stored once
- πΈ Snapshots - Immutable point-in-time repository states for patch management
- π Views - Virtual repositories combining multiple repos (e.g., BaseOS + AppStream + EPEL)
- π Modular - Plugin architecture for repository types
- π« No Daemons - Simple CLI tool (optional scheduler for future automation)
- π Static Output - Serve with any webserver (Apache, NGINX)
- π RHEL CDN Support - Client certificate authentication for Red Hat repos
- π― Smart Filtering - Pattern-based package filtering with post-processing
- πͺ Mirror & Filtered Modes - Full metadata mirroring or filtered repos with regenerated metadata
- β‘ Fast Updates - Check for updates without downloading (like
dnf check-update) - π Metadata Caching - SHA256-based cache for RPM metadata (90-95% faster syncs for RHEL)
Supported Repository Types:
- β RPM/DNF/YUM (RHEL, CentOS, Fedora, Rocky, AlmaLinux, EPEL)
- β DEB/APT (Debian, Ubuntu)
- β Helm Charts (Kubernetes, Bitnami, AWS EKS, Prometheus, GitLab)
- β Alpine APK (Alpine Linux, container base images)
Option 1: Container (Recommended)
# Pull from GitHub Container Registry
docker pull ghcr.io/slauger/chantal:latest
# Run
docker run --rm \
-v $(pwd)/config:/etc/chantal:ro \
-v $(pwd)/data:/var/lib/chantal \
-v $(pwd)/repos:/var/www/repos \
ghcr.io/slauger/chantal:latest --helpOption 2: Python Package
git clone https://github.com/slauger/chantal.git
cd chantal
pip install -e .Requirements: Python 3.10+, PostgreSQL or SQLite
# 1. Initialize database schema
chantal db init
# 2. Configure repositories (see docs for examples)
vim /etc/chantal/config.yaml
# 3. Sync repository (RPM, Helm, or APK)
chantal repo sync --repo-id epel9-latest
# 4. Create snapshot
chantal snapshot create --repo-id epel9-latest --name 2025-01
# 5. Publish
chantal publish snapshot --snapshot epel9-latest-2025-01Result: Published repository in /var/www/repos/ ready to serve with Apache/NGINX.
Chantal uses Alembic for database schema migrations:
# Initialize database schema (first-time setup)
chantal db init
# Check current schema version
chantal db current
# Check schema status and pending migrations
chantal db status
# Upgrade to latest schema version
chantal db upgrade
# View migration history
chantal db history
# Database statistics and verification
chantal db stats
chantal db verifyNote: Storage directories are created automatically when needed. The db init command only initializes the database schema.
- SHA256-based deduplication (2-level directory:
ab/cd/sha256_file.rpm) - Packages stored once, shared across all repositories
- Typical deduplication: 60-80% across RHEL variants
- Point-in-time freezes for patch management
- Compare snapshots (
chantal snapshot diff) - Rollback to previous states
- Atomic view snapshots (freeze all repos simultaneously)
- Combine multiple repos into one:
BaseOS + AppStream + CRB - Mixed repos:
RHEL + EPELin single repository - Stack-specific views: web server, monitoring, etc.
filters:
patterns:
include: ["^nginx-.*", "^httpd-.*"]
exclude: [".*-debug.*"]
metadata:
architectures:
include: ["x86_64", "noarch"]
post_processing:
only_latest_version: true- Hardlinks (not copies) to published directories
- Instant publishing (milliseconds for thousands of packages)
- Atomic metadata updates
/var/lib/chantal/pool/ # Content-addressed storage (SHA256)
βββ ab/cd/sha256_package.rpm
βββ ...
/var/www/repos/ # Published repositories (hardlinks)
βββ rhel9-baseos/
β βββ latest/ # Current state
β βββ snapshots/2025-01/ # Immutable snapshot
βββ views/
βββ rhel9-complete/ # Virtual repository
βββ latest/
Database: PostgreSQL or SQLite (SQLAlchemy models) Plugins: Extensible architecture for repository types (RPM, DEB/APT, Helm, APK)
π Full Documentation: https://slauger.github.io/chantal/
- Installation Guide
- Quick Start
- CLI Commands
- Configuration
- Views (Virtual Repositories)
- Architecture
- Plugin Development
# Monthly cycle
chantal repo sync --all
chantal snapshot create --repo-id rhel9-baseos --name 2025-02
chantal snapshot diff --repo-id rhel9-baseos 2025-01 2025-02
chantal publish snapshot --snapshot rhel9-baseos-2025-02repositories:
- id: rhel9-baseos
feed: https://cdn.redhat.com/content/dist/rhel9/9/x86_64/baseos/os
ssl:
client_cert: /etc/pki/entitlement/1234567890.pem
client_key: /etc/pki/entitlement/1234567890-key.pem# Online system
chantal repo sync --all
tar czf export.tar.gz /var/lib/chantal /etc/chantal
# Offline system
tar xzf export.tar.gz
chantal publish repo --allSee Workflows Documentation for more examples.
Contributions welcome! See GitHub Issues for planned features and improvements.
1. Clone and Setup Virtual Environment:
git clone https://github.com/slauger/chantal.git
cd chantal
# Create virtual environment
make venv
# OR manually: python3 -m venv venv
# Activate virtual environment
source venv/bin/activate
# Install dependencies
make install-dev
# OR manually: pip install -e ".[dev]"2. Run Local Tests (CI/CD Checks):
# IMPORTANT: Always use the Makefile targets to ensure correct venv usage!
# Run all linters (same as CI/CD)
make lint
# Run all checks (linters + tests)
make check
# Individual checks
make ruff # Linting
make black # Code formatting check
make yamllint # YAML linting
make mypy # Type checking
make pytest # Unit tests
# Auto-format code
make format3. Development Notes:
β οΈ Always activate the venv before running tests (source venv/bin/activate)- β
Use
make lintinstead of running tools directly - ensures venv usage - β
CI/CD runs the same checks as
make lint- local = CI/CD - π§ All linters are pinned to specific versions for consistency
- π See
Makefilefor all available targets
Read the Architecture Documentation before contributing.
MIT License - See LICENSE file for details.
Developed by Simon Lauger
Inspired by: pulp-admin, reposync, aptly, apt-mirror, bandersnatch
π¦ Container Images: ghcr.io/slauger/chantal:latest
π Documentation: https://slauger.github.io/chantal/
π Issues: https://github.com/slauger/chantal/issues