Skip to content

RPM

NORA serves RPM repositories for yum / dnf. Each {repo} under /rpm/ is an independent repository of one of two kinds:

  • Hosted — you publish packages. PUT a .rpm and NORA parses the package header server-side (no createrepo_c needed) and regenerates the repository’s repodata/: repomd.xml plus sha256-named primary, filelists and other indexes, signed with the instance key.
  • Pull-through proxy — a repo name mapped to one upstream yum repository in [rpm.proxies]. Read-only; see Upstream proxy.

Create a .repo file (e.g. /etc/yum.repos.d/nora.repo):

[nora]
name=NORA
baseurl=http://nora.example.com:4000/rpm/myrepo
enabled=1
gpgcheck=0
repo_gpgcheck=1
gpgkey=http://nora.example.com:4000/rpm/myrepo/repodata/repomd.xml.key

Then install as usual:

Terminal window
dnf install mypackage

repo_gpgcheck=1 verifies the signed repodata against the key at gpgkey=. Keep gpgcheck=0: NORA signs the repository metadata, not the packages, so with gpgcheck=1 dnf refuses any package that was not signed by whoever built it (“The package is not signed”). If your packages are signed by their vendor, set gpgcheck=1 and add the vendor key to gpgkey=. With signing disabled (NORA_SIGNING_ENABLED=false), set repo_gpgcheck=0.

Upload a package to a hosted repo with PUT; the repodata regenerates automatically:

Terminal window
curl -u user:pass -T mypackage-1.0-1.x86_64.rpm \
http://nora.example.com:4000/rpm/myrepo/mypackage-1.0-1.x86_64.rpm

DELETE the same path removes the package and regenerates the indexes. Invalid RPMs are rejected.

If packages were added to or removed from storage out of band, POST /rpm/{repo}/-/reindex reconciles the repo: it drops orphan metadata, adopts added packages, and rebuilds and re-signs the repodata.

Map a local repo name to an upstream yum repository (the directory that contains repodata/):

[rpm]
enabled = true
[rpm.proxies]
fedora = "https://dl.fedoraproject.org/pub/fedora/linux/releases/42/Everything/x86_64/os"
epel = { url = "https://mirror.internal.example.com/epel/9/Everything/x86_64", auth = "user:pass" }

or NORA_RPM_PROXIES="fedora=https://…/os,epel=https://…/x86_64|user:pass". Clients point baseurl at http://nora.example.com:4000/rpm/fedora.

  • A proxied repo is read-only: PUT, DELETE and reindex answer 409.
  • Upstream metadata — repodata/, including the upstream’s own signature and key — is served verbatim and refreshed after metadata_ttl seconds (default 300). Verify it with the upstream’s key in gpgkey=, not NORA’s.
  • Packages are cached forever on first download.
  • When the upstream is down, a stale cached copy is served with x-nora-stale: true.

nora mirror rpm fetches every package of a proxied repo through NORA, so air-gapped clients can install without the upstream:

Terminal window
nora mirror --registry http://nora.example.com:4000 rpm --repo fedora --arch x86_64,noarch

config.toml:

[rpm]
enabled = true
max_file_size = 1073741824 # 1 GiB
changelog_limit = 10 # changelog entries per package in other.xml
proxy_timeout = 30
metadata_ttl = 300

Environment variables:

VariableDescriptionDefault
NORA_RPM_ENABLEDEnable the RPM registryfalse
NORA_RPM_MAX_FILE_SIZEMax .rpm upload size in bytes1073741824 (1 GiB)
NORA_RPM_CHANGELOG_LIMITChangelog entries per package in other.xml10
NORA_RPM_PROXIESPull-through repos: name=url[|user:pass],…—
NORA_RPM_PROXY_TIMEOUTUpstream timeout in seconds30
NORA_RPM_METADATA_TTLSeconds upstream metadata stays fresh (0 or less = revalidate every pull)300

Hosted repodata is GPG-signed on every regeneration (repodata/repomd.xml.asc). With local storage the instance key (Ed25519) is generated at first boot under <storage>/.signing/nora.key; the armored public key is served at repodata/repomd.xml.key. The same key signs Debian/APT indexes.

VariableDescriptionDefault
NORA_SIGNING_ENABLEDSign RPM and Debian repository indexestrue
NORA_SIGNING_KEY_PATHArmored OpenPGP secret key. Required on S3/GCS storage<storage>/.signing/nora.key

On S3/GCS storage, without NORA_SIGNING_KEY_PATH signing is disabled with a startup warning. Mount the same key on every replica.

FeatureStatusNotes
Package upload (PUT)FullHeader parsed and validated; repodata regenerated
Package download (GET)FullByte-identical
Delete (DELETE)FullRepodata regenerated
repodata/ generationFullrepomd.xml + primary / filelists / other (.xml.gz)
Signed repodata (repomd.xml.asc)FullVerify with repo_gpgcheck=1
Public key (repomd.xml.key)FullFor gpgkey=
Reconcile (POST {repo}/-/reindex)FullHeals out-of-band storage changes
Upstream proxyFull[rpm.proxies], read-only, stale-on-error
Offline mirrorFullnora mirror rpm
Package signatures (gpgcheck=1)—NORA signs metadata, not packages
sqlite metadata (*_db)—XML metadata only
Delta RPMs, modules.yaml—Not generated
  • NORA does not sign packages. Use gpgcheck=0 unless the packages carry their vendor’s signature.
  • Disabled by default. Set NORA_RPM_ENABLED=true to activate.
  • A proxied repo maps to exactly one upstream repository; it cannot be published to.