Guide · Updated May 2026

How to set up a
private RPM repository

A private RPM repository gives you full control over which packages reach your AlmaLinux, Rocky Linux, RHEL, Fedora, or openSUSE servers — with GPG verification, CVE screening, and a complete audit trail.

Why teams move away from public mirrors

Public RPM mirrors (dnf install, yum install) are convenient but create invisible risk for production infrastructure:

  • Uncontrolled updates. A dnf update on Monday can install a different version than the same command run on Friday. There is no snapshot isolation.
  • No vulnerability gate. Packages with active CVEs are served identically to clean ones. The EPSS score and CISA KEV status of what you are installing is unknown at install time.
  • Supply chain exposure. A compromised upstream maintainer account can push a malicious update to every server in your fleet via a standard dnf upgrade.
  • No compliance evidence. NIS2 Article 21 requires documented evidence of your software supply chain controls. A raw public mirror provides none.

How RepoD handles RPM repositories

RepoD uses createrepo_c to manage RPM metadata and applies a GPG detached signature on repomd.xml — the standard way for dnf clients to verify repository integrity.

Every .rpm file is validated with rpm -qip before acceptance, then scanned by ClamAV and Grype before the package is indexed.

The CVE enrichment pipeline uses Grype's RPM-aware PURL identifiers (pkg:rpm/) and maps vulnerabilities against the correct distro CPE — so almalinux:8 CVEs are not confused with fedora:42 ones.

Supported distributions

almalinux8
AlmaLinux 8
x86_64 · aarch64
almalinux9
AlmaLinux 9
x86_64 · aarch64
rocky8
Rocky Linux 8
x86_64 · aarch64
rocky9
Rocky Linux 9
x86_64 · aarch64
centos-stream9
CentOS Stream 9
x86_64 · aarch64
oraclelinux8
Oracle Linux 8
x86_64 · aarch64
fedora
Fedora 42
x86_64 · aarch64
opensuse-leap-15.6
openSUSE Leap 15.6
x86_64 · aarch64
opensuse-tumbleweed
openSUSE Tumbleweed
x86_64 · aarch64

Quick start

1 Deploy RepoD
git clone https://github.com/getautoflow/repod.git
cd repod
cp .env.example .env && cp backend.env.example backend.env
# Set JWT_SECRET_KEY and ADMIN_PASSWORD_HASH in backend.env
docker compose up -d
2 Upload an RPM package
# Get a token
TOKEN=$(curl -s -X POST http://localhost:8100/auth/token \
  -H 'Content-Type: application/json' \
  -d '{"username":"YOUR_ADMIN_USERNAME","password":"YOUR_ADMIN_PASSWORD"}' \
  | python3 -c "import sys,json; print(json.load(sys.stdin)['access_token'])")

# Upload
curl -X POST http://localhost:8100/upload/ \
  -H "Authorization: Bearer $TOKEN" \
  -F "file=@./nginx-1.27.3-1.x86_64.rpm" \
  -F "distribution=almalinux9"
3 Configure dnf clients
# /etc/yum.repos.d/repod.repo
[repod]
name=RepoD Private Repository
baseurl=http://your-repod-host/rpm/almalinux9/
enabled=1
gpgcheck=1
gpgkey=http://your-repod-host/rpm/almalinux9/repodata/repomd.xml.asc
4 Install from your private repo
sudo dnf makecache
sudo dnf install nginx

CVE scanning for RPM packages

Grype uses distribution-specific CPE mappings to match CVEs accurately for each RPM distro. EPSS scores are enriched from FIRST.org to indicate exploit probability, and the CISA KEV catalogue flags vulnerabilities that are actively exploited in the wild — giving your security team actionable priority signals beyond raw CVSS scores.

CVSS v3
Severity score from NVD — critical, high, medium, low
EPSS
Probability of exploitation in next 30 days (FIRST.org)
CISA KEV
Actively exploited in the wild right now

Air-gap operation

After initial setup, RepoD runs fully offline. CVE databases and EPSS scores are cached locally. For true air-gap environments, you can pre-populate the CVE database from a network-connected host and rsync it to your isolated RepoD instance — no direct internet access required at scan time.

This makes RepoD suitable for classified or regulated environments where outbound network connections are prohibited.

Last updated: May 2026 · ← Private APT repository guide