Repository Configuration

This page explains how to configure repositories in Chantal.

Basic Repository Configuration

Minimum required configuration:

repositories:
  - id: epel9-latest
    name: EPEL 9 - Latest
    type: rpm
    feed: https://dl.fedoraproject.org/pub/epel/9/Everything/x86_64/
    enabled: true

Required Fields:

  • id: Unique identifier (alphanumeric, hyphens, underscores)

  • type: Repository type (rpm, apt, helm, apk)

Optional Fields:

  • name: Human-readable name (falls back to id if unset)

  • feed: Upstream repository URL. Defaults to "" and is required for mode: mirror and mode: filtered, but optional (and unused) for mode: hosted.

  • enabled: Whether to include in --all operations (defaults to true)

  • mode: Repository operation mode (mirror, filtered, hosted) - RPM and APT, defaults to filtered

Repository Types

RPM Repositories

For DNF/YUM-based distributions (RHEL, CentOS, Fedora, Rocky, Alma):

repositories:
  # Filtered mode (default) - filters packages and regenerates metadata
  - id: epel9-webservers
    name: EPEL 9 - Web Servers
    type: rpm
    feed: https://dl.fedoraproject.org/pub/epel/9/Everything/x86_64/
    enabled: true
    mode: filtered  # Default
    filters:
      patterns:
        include: ["^nginx-.*", "^httpd-.*"]
      post_processing:
        only_latest_version: true

  # Mirror mode - full metadata mirroring, no filtering
  - id: rhel9-baseos
    name: RHEL 9 BaseOS (Full Mirror)
    type: rpm
    feed: https://cdn.redhat.com/content/dist/rhel9/9/x86_64/baseos/os
    enabled: true
    mode: mirror

Feed URL Requirements:

  • Must point to a directory containing repodata/repomd.xml

  • Supports HTTP and HTTPS

  • Supports file:// URLs for local mirrors

Repository Modes (RPM and APT):

  • filtered (default): Filters packages based on patterns/rules, regenerates metadata to match. Updateinfo filtered to include only relevant errata.

  • mirror: Full mirror of upstream repository. All metadata types downloaded and published unchanged. No filtering applied (using filters with mode: mirror is a validation error).

  • hosted: Upload-only repository with no upstream feed. Packages are added with chantal package upload and published like any other repo. sync is a no-op for hosted repos, and feed is not required.

See RPM Plugin Documentation - Repository Modes for detailed mode explanations.

Helm Repositories

For Kubernetes Helm chart repositories:

repositories:
  - id: ingress-nginx
    name: Ingress NGINX Helm Charts
    type: helm
    feed: https://kubernetes.github.io/ingress-nginx
    enabled: true

Feed URL Requirements:

  • Must point to a directory containing index.yaml

  • Supports HTTP and HTTPS

  • May require authentication for private chart repositories

Alpine APK Repositories

For Alpine Linux package repositories:

repositories:
  - id: alpine-v3.19-main
    name: Alpine 3.19 Main
    type: apk
    feed: https://dl-cdn.alpinelinux.org/alpine/
    enabled: true
    apk:
      branch: v3.19
      repository: main
      architecture: x86_64

Required APK Configuration:

  • apk.branch: Alpine branch (v3.19, v3.18, edge, etc.)

  • apk.repository: Repository type (main, community, testing)

  • apk.architecture: Architecture (x86_64, aarch64, armhf, armv7, x86)

Feed URL Requirements:

  • Must point to base Alpine mirror (e.g., https://dl-cdn.alpinelinux.org/alpine/)

  • APKINDEX location is constructed as: {feed}/{branch}/{repository}/{architecture}/APKINDEX.tar.gz

APT Repositories

For Debian/Ubuntu-based distributions:

repositories:
  - id: ubuntu-jammy-main
    name: Ubuntu 22.04 - Main
    type: apt
    feed: http://archive.ubuntu.com/ubuntu
    enabled: true
    mode: mirror
    apt:
      distribution: jammy
      components:
        - main
        - restricted
        - universe
        - multiverse
      architectures:
        - amd64
        - arm64
      include_source_packages: false

Required APT Configuration:

  • apt.distribution: APT distribution/suite name (jammy, focal, bookworm, etc.)

  • apt.components: Repository components (main, contrib, non-free, etc.)

  • apt.architectures: Architectures to sync (amd64, arm64, armhf, i386, all)

Optional APT Configuration:

  • apt.include_source_packages: Whether to sync source packages (default: false)

  • mode: Repository mode (mirror, filtered, or hosted; defaults to filtered)

Feed URL Requirements:

  • Must point to APT repository base URL

  • Distribution Release file location: {feed}/dists/{distribution}/Release

See APT Plugin Documentation for detailed examples and configuration options.

Advanced Options

Version Retention Policy

Control which package versions to keep:

repositories:
  - id: rhel9-baseos
    type: rpm
    feed: https://...
    retention:
      policy: mirror  # mirror, newest-only, keep-all, keep-last-n
      # keep_count: 3  # Only when policy is keep-last-n

Retention Policies:

  • mirror: Mirror exactly what’s upstream (default)

  • newest-only: Keep only the latest version

  • keep-all: Keep all versions ever seen

  • keep-last-n: Keep last N versions

Repository Tags

Tag repositories for easier management:

repositories:
  - id: rhel9-baseos-production
    name: RHEL 9 BaseOS - Production
    type: rpm
    feed: https://...
    tags: ["production", "rhel9", "critical"]

Use tags to filter operations:

# Future feature
chantal repo sync --tag production
chantal repo list --tag rhel9

Custom Publishing Paths

Override default publishing paths:

repositories:
  - id: rhel9-baseos
    type: rpm
    feed: https://...
    latest_path: /var/www/repos/rhel9-baseos/latest
    snapshots_path: /var/www/repos/rhel9-baseos/snapshots

Per-Repository Settings

Metadata Cache Override

Override the global cache setting per repository (cache_enabled is a generic repository field; leaving it unset uses the global cache.enabled default):

# Global config - cache disabled by default
cache:
  enabled: false
  max_age_hours: 24

repositories:
  # Enable cache only for RHEL (large metadata files)
  - id: rhel9-baseos
    type: rpm
    feed: https://cdn.redhat.com/...
    cache_enabled: true  # Override global default

  # EPEL uses global default (disabled)
  - id: epel9-latest
    type: rpm
    feed: https://dl.fedoraproject.org/pub/epel/9/...
    # cache_enabled not set = uses global cache.enabled (false)

How it works:

  • Metadata files (primary.xml.gz, updateinfo.xml.gz, etc.) are cached by SHA256 checksum

  • Cache is validated via checksums from repomd.xml (always fetched fresh)

  • Deduplication: Same metadata files shared across repositories

  • TTL-based expiration with max_age_hours (optional)

Performance improvement:

  • Without cache: ~5-10s per sync (RHEL BaseOS)

  • With cache hit: ~0.5s per sync (90-95% faster)

Cache management:

chantal cache stats   # Show cache statistics
chantal cache clear   # Clear all cached files
chantal cache list    # List cached metadata

Proxy Override

Override global proxy settings:

repositories:
  - id: internal-repo
    type: rpm
    feed: https://internal.example.com/repo
    proxy:
      http_proxy: http://internal-proxy:3128
      https_proxy: http://internal-proxy:3128

SSL/TLS Override

Override global SSL settings:

repositories:
  - id: rhel9-baseos
    type: rpm
    feed: https://cdn.redhat.com/...
    ssl:
      ca_bundle: /etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem
      client_cert: /etc/pki/entitlement/1234567890.pem
      client_key: /etc/pki/entitlement/1234567890-key.pem
      verify: true

Custom HTTP Headers

Custom request headers are configured through the authentication block using auth.type: custom and an auth.headers mapping (there is no top-level http_headers field):

repositories:
  - id: custom-repo
    type: rpm
    feed: https://custom.example.com/repo
    auth:
      type: custom
      headers:
        User-Agent: "Chantal/1.0"
        X-Custom-Header: "value"

See SSL & Authentication for the full list of authentication types.

GPG Signing (gpg)

When a repository regenerates metadata (APT filtered mode), the published Release file can be re-signed so clients can verify it without [trusted=yes]. The signing key can come from an imported private key file, an existing key in the keyring, or a freshly generated keypair. A per-repository gpg block overrides the global gpg fallback.

repositories:
  - id: my-apt-repo
    type: apt
    feed: https://example.com/debian
    mode: filtered
    gpg:
      enabled: true            # default true; set false to disable signing
      generate_key: true       # generate a keypair if no key is provided
      # key_id: ABCD1234       # or use an existing key in the keyring
      # key_file: /etc/chantal/keys/signing-private.asc  # or import a private key
      key_name: "Chantal Repo"   # real name for a generated key
      key_email: "repo@example.com"  # email for a generated key
      public_key_name: key.gpg   # published public-key filename (default: key.gpg)
      # passphrase_file: /etc/chantal/keys/passphrase.txt  # preferred over inline
      # passphrase: "secret"     # inline passphrase (use passphrase_file instead)

At least one of key_file, key_id, or generate_key: true must be set when enabled is true. Other available keys: public_key_file (use an existing public key instead of exporting one) and gnupg_home (keyring directory; a temporary one is used if unset).

Upstream Signature Verification (verify)

Integrity (SHA256) is always checked during sync. verify adds authenticity checking - confirming the upstream metadata/packages were signed by a trusted key (analogous to dnf’s repo_gpgcheck/gpgcheck and apt’s Release signature check). A per-repository verify block overrides the global verify fallback.

repositories:
  - id: rhel9-baseos
    type: rpm
    feed: https://cdn.redhat.com/...
    verify:
      enabled: true            # default false
      repo_gpgcheck: true      # verify repository metadata signature (default true)
      gpgcheck: true           # verify individual package signatures (default true)
      key_files:               # trust anchors: public key file paths
        - /etc/pki/rpm-gpg/RPM-GPG-KEY-redhat-release
      # keys:                  # alternative: inline ASCII-armored public keys
      #   - |
      #     -----BEGIN PGP PUBLIC KEY BLOCK-----
      #     ...
      trusted_fingerprints:    # optional pinning allow-list of full fingerprints
        - "199E2F91FD431D51"
      client_key_name: "RPM-GPG-KEY-{repo_id}"  # published trusted key (empty disables)
      on_missing_signature: fail   # fail | warn | skip
      on_invalid_signature: fail   # fail | warn | skip

When enabled is true at least one of key_files or keys must be provided. gpgcheck requires repo_gpgcheck (the default has both enabled).

Repository Organization

Single File Configuration

Simple setup for few repositories:

# config.yaml
database:
  url: postgresql://chantal:password@localhost/chantal

storage:
  base_path: /var/lib/chantal

repositories:
  - id: epel9-latest
    name: EPEL 9
    type: rpm
    feed: https://dl.fedoraproject.org/pub/epel/9/Everything/x86_64/
    enabled: true

Multi-File Configuration

Recommended for many repositories:

config.yaml:

database:
  url: postgresql://chantal:password@localhost/chantal

storage:
  base_path: /var/lib/chantal

include: "conf.d/*.yaml"

conf.d/rhel9.yaml:

repositories:
  - id: rhel9-baseos
    name: RHEL 9 BaseOS
    type: rpm
    feed: https://cdn.redhat.com/...
    enabled: true

  - id: rhel9-appstream
    name: RHEL 9 AppStream
    type: rpm
    feed: https://cdn.redhat.com/...
    enabled: true

conf.d/epel9.yaml:

repositories:
  - id: epel9-main
    name: EPEL 9 - Main
    type: rpm
    feed: https://dl.fedoraproject.org/pub/epel/9/Everything/x86_64/
    enabled: true

Real-World Examples

RHEL 9 with Subscription

repositories:
  - id: rhel9-baseos
    name: RHEL 9 BaseOS
    type: rpm
    feed: https://cdn.redhat.com/content/dist/rhel9/9/x86_64/baseos/os
    enabled: true
    ssl:
      ca_bundle: /etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem
      client_cert: /etc/pki/entitlement/1234567890.pem
      client_key: /etc/pki/entitlement/1234567890-key.pem
      verify: true
    filters:
      metadata:
        architectures:
          include: ["x86_64", "noarch"]
      rpm:
        exclude_source_rpms: true

Rocky Linux 9

repositories:
  - id: rocky9-baseos
    name: Rocky Linux 9 - BaseOS
    type: rpm
    feed: https://dl.rockylinux.org/pub/rocky/9/BaseOS/x86_64/os/
    enabled: true

  - id: rocky9-appstream
    name: Rocky Linux 9 - AppStream
    type: rpm
    feed: https://dl.rockylinux.org/pub/rocky/9/AppStream/x86_64/os/
    enabled: true

EPEL 9 with Selective Mirroring

repositories:
  - id: epel9-monitoring
    name: EPEL 9 - Monitoring Tools
    type: rpm
    feed: https://dl.fedoraproject.org/pub/epel/9/Everything/x86_64/
    enabled: true
    filters:
      patterns:
        include:
          - "^nagios-.*"
          - "^prometheus-.*"
          - "^grafana-.*"
      post_processing:
        only_latest_version: true

CentOS Stream 9

repositories:
  - id: centos-stream-9-baseos
    name: CentOS Stream 9 - BaseOS
    type: rpm
    feed: https://mirrors.centos.org/mirrorlist?repo=centos-baseos-9-stream&arch=x86_64
    enabled: true
    # Note: mirrorlist URLs are not yet supported, use direct mirror URL

Helm Charts - Ingress NGINX

repositories:
  - id: ingress-nginx
    name: Ingress NGINX Helm Charts
    type: helm
    feed: https://kubernetes.github.io/ingress-nginx
    enabled: true

Helm Charts - Bitnami (Selective)

repositories:
  - id: bitnami-databases
    name: Bitnami Charts - Databases
    type: helm
    feed: https://charts.bitnami.com/bitnami
    enabled: true
    filters:
      patterns:
        include: ["^postgresql$", "^mysql$", "^mongodb$", "^redis$"]
      post_processing:
        only_latest_version: true

Helm Charts - Private Repository

repositories:
  - id: company-charts
    name: Company Internal Charts
    type: helm
    feed: https://charts.internal.company.com/
    enabled: true
    ssl:
      ca_bundle: /etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem
      client_cert: /etc/pki/helm/company-client.pem
      client_key: /etc/pki/helm/company-client-key.pem
      verify: true

Alpine Linux 3.19 (Main + Community)

repositories:
  - id: alpine-v3.19-main-x86_64
    name: Alpine 3.19 Main (x86_64)
    type: apk
    feed: https://dl-cdn.alpinelinux.org/alpine/
    enabled: true
    apk:
      branch: v3.19
      repository: main
      architecture: x86_64

  - id: alpine-v3.19-community-x86_64
    name: Alpine 3.19 Community (x86_64)
    type: apk
    feed: https://dl-cdn.alpinelinux.org/alpine/
    enabled: true
    apk:
      branch: v3.19
      repository: community
      architecture: x86_64

Alpine Linux Edge (Rolling Release)

repositories:
  - id: alpine-edge-main
    name: Alpine Edge Main
    type: apk
    feed: https://dl-cdn.alpinelinux.org/alpine/
    enabled: true
    apk:
      branch: edge
      repository: main
      architecture: x86_64

Alpine Linux - Container Base (Selective)

repositories:
  - id: alpine-v3.19-container-base
    name: Alpine 3.19 - Essential Packages
    type: apk
    feed: https://dl-cdn.alpinelinux.org/alpine/
    enabled: true
    apk:
      branch: v3.19
      repository: main
      architecture: x86_64
    filters:
      patterns:
        include:
          - "^alpine-base$"
          - "^busybox$"
          - "^musl$"
          - "^ca-certificates$"
      post_processing:
        only_latest_version: true

Validation

Chantal validates repository configuration at startup:

$ chantal repo list
Error: Configuration validation failed:
  - repositories[0].id: must match pattern ^[a-zA-Z0-9_-]+$
  - repositories[1].feed: invalid URL format
  - repositories[2].type: must be one of: rpm, apt, helm, apk

Best Practices

  1. Use descriptive IDs: rhel9-baseos instead of repo1

  2. Organize by distribution: Separate files for RHEL, EPEL, Rocky, etc.

  3. Document filters: Add comments explaining why filters are applied

  4. Version control: Keep repository configs in Git

  5. Test first: Use --dry-run or test environment before production

  6. Enable selectively: Set enabled: false for repos not in regular use