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.
PUTa.rpmand NORA parses the package header server-side (nocreaterepo_cneeded) and regenerates the repository’srepodata/:repomd.xmlplus sha256-namedprimary,filelistsandotherindexes, 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.
Client Configuration
Section titled “Client Configuration”Create a .repo file (e.g. /etc/yum.repos.d/nora.repo):
[nora]name=NORAbaseurl=http://nora.example.com:4000/rpm/myrepoenabled=1gpgcheck=0repo_gpgcheck=1gpgkey=http://nora.example.com:4000/rpm/myrepo/repodata/repomd.xml.keyThen install as usual:
dnf install mypackagerepo_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.
Publishing
Section titled “Publishing”Upload a package to a hosted repo with PUT; the repodata regenerates automatically:
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.rpmDELETE 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.
Upstream Proxy
Section titled “Upstream Proxy”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,DELETEand reindex answer409. - Upstream metadata —
repodata/, including the upstream’s own signature and key — is served verbatim and refreshed aftermetadata_ttlseconds (default300). Verify it with the upstream’s key ingpgkey=, 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.
Offline mirror
Section titled “Offline mirror”nora mirror rpm fetches every package of a proxied repo through NORA, so air-gapped clients can install without the upstream:
nora mirror --registry http://nora.example.com:4000 rpm --repo fedora --arch x86_64,noarchConfiguration
Section titled “Configuration”config.toml:
[rpm]enabled = truemax_file_size = 1073741824 # 1 GiBchangelog_limit = 10 # changelog entries per package in other.xmlproxy_timeout = 30metadata_ttl = 300Environment variables:
| Variable | Description | Default |
|---|---|---|
NORA_RPM_ENABLED | Enable the RPM registry | false |
NORA_RPM_MAX_FILE_SIZE | Max .rpm upload size in bytes | 1073741824 (1 GiB) |
NORA_RPM_CHANGELOG_LIMIT | Changelog entries per package in other.xml | 10 |
NORA_RPM_PROXIES | Pull-through repos: name=url[|user:pass],… | — |
NORA_RPM_PROXY_TIMEOUT | Upstream timeout in seconds | 30 |
NORA_RPM_METADATA_TTL | Seconds upstream metadata stays fresh (0 or less = revalidate every pull) | 300 |
Signing
Section titled “Signing”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.
| Variable | Description | Default |
|---|---|---|
NORA_SIGNING_ENABLED | Sign RPM and Debian repository indexes | true |
NORA_SIGNING_KEY_PATH | Armored 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.
Features
Section titled “Features”| Feature | Status | Notes |
|---|---|---|
Package upload (PUT) | Full | Header parsed and validated; repodata regenerated |
Package download (GET) | Full | Byte-identical |
Delete (DELETE) | Full | Repodata regenerated |
repodata/ generation | Full | repomd.xml + primary / filelists / other (.xml.gz) |
Signed repodata (repomd.xml.asc) | Full | Verify with repo_gpgcheck=1 |
Public key (repomd.xml.key) | Full | For gpgkey= |
Reconcile (POST {repo}/-/reindex) | Full | Heals out-of-band storage changes |
| Upstream proxy | Full | [rpm.proxies], read-only, stale-on-error |
| Offline mirror | Full | nora mirror rpm |
Package signatures (gpgcheck=1) | — | NORA signs metadata, not packages |
sqlite metadata (*_db) | — | XML metadata only |
Delta RPMs, modules.yaml | — | Not generated |
Known Limitations
Section titled “Known Limitations”- NORA does not sign packages. Use
gpgcheck=0unless the packages carry their vendor’s signature. - Disabled by default. Set
NORA_RPM_ENABLED=trueto activate. - A proxied repo maps to exactly one upstream repository; it cannot be published to.