Upgrade Guide
1.4.2 to 1.4.3
Section titled “1.4.2 to 1.4.3”1.4.3 reads 1.4.2 storage as is, on local disk and on S3, and 1.4.2 reads what 1.4.3 stores. 1.4.3 fixes the issues in GHSA-54qr-w49h-mgfq.
Before you upgrade
Section titled “Before you upgrade”An OIDC provider in [[auth.oidc.providers]] without audience stops the start on 1.4.3 (exit status 78, which the packaged systemd units do not restart into), with an error naming the provider; a SIGHUP reload that brings one in is refused. Give every enabled provider the audience its CI jobs request (core.getIDToken('nora'), GitLab id_tokens: … aud:), or set any_audience = true where no nameable aud exists: it accepts any aud and warns at every start.
What changed
Section titled “What changed”| Change | Impact | Action required |
|---|---|---|
OIDC provider without audience | Refused at start and on reload (see above) | Set audience, or any_audience = true |
nora import of PyPI and NuGet | Imported as hosted: the index, versions and dates come from what NORA holds, and no upstream is asked for the name. An imported PyPI project serves only the files imported or uploaded to it | Run the import again: a PyPI or NuGet repository that 1.4.2 or older marked finished is walked again. Upload again a file that 1.4.2 or older uploaded under an imported project’s name |
/health | 503 with failing_task when a background task keeps panicking, or when the maintenance loop finishes no tick for server.maintenance_stall_secs (300 s). A handler panic answers 500 and the server keeps serving; a panic of the audit writer ends the process with exit status 70 | Kubernetes restarts on the liveness probe. Under Docker without Swarm, or systemd, a 503 restarts nothing by itself: add an autoheal watcher, or a timer running nora healthcheck || systemctl restart nora |
/ready | 503 when the store does not answer by the maintenance tick’s deadline, without a restart | None |
Connection limits: server.header_read_timeout (30 s), server.keep_alive_timeout (120 s), server.max_connections (4096) | Connections without a request head, and idle ones, are closed; HTTP/2 is closed with GOAWAY | Keep keep_alive_timeout above the idle timeout of a reverse proxy in front (90 s or less starts with a warning), and max_connections above the number of keep-alive connections that proxy holds open |
| Token lifetimes | At most 3650 days on every mint route; a token minted by an OIDC identity lives no longer than its provider’s max_token_lifetime_secs or what is left of its JWT. The answer carries expires_in_secs | None |
| Password lockout | Counted per username at an address; an address is still held for every username after ten accounts’ worth of wrong passwords | None |
Client address on NORA_HOST=:: (the image default) | An IPv4 peer is read as IPv4, so trusted_proxies and the rate limit see it | None |
| npm tarballs | Fetched only for a version the upstream’s packument lists, at its link. A redirect to another origin is followed without the upstream’s credential; metadata of a proxies entry bound to scopes comes only from its own origin | None |
| Cache hits | Cost more CPU: p95 of a large npm packument such as react about 16 ms (was about 10 ms) | None |
Rollback
Section titled “Rollback”Stop 1.4.3, start 1.4.2 on the same storage. 1.4.2 does not know server.header_read_timeout, server.keep_alive_timeout, server.max_connections, server.maintenance_stall_secs and any_audience: it warns and ignores them, but under NORA_CONFIG_STRICT=true it refuses to start (exit status 78). Remove them from config.toml before the rollback, or set the [server] ones through their environment variables (NORA_HEADER_READ_TIMEOUT and the others), which 1.4.2 does not read.
1.3.6 to 1.4.0
Section titled “1.3.6 to 1.4.0”1.4.0 reads 1.3.6 storage as is, on local disk and on S3. It adds keys of its own that 1.3.6 does not read: Cargo spelling records under cargo/_names/, a Cargo upstream’s index under a key of its own, and npm upstream copies under npm/<name>/upstream/. 1.4.0 fixes the issues in GHSA-5pr2-xx8w-79jc and GHSA-pg2g-wvgf-cxpp.
Before you upgrade
Section titled “Before you upgrade”Some configurations that start on 1.3.6 stop on 1.4.0, each with a message naming the key:
- a
min_release_agefor rpm, deb or cpan — those downloads carry no name check or release date to hold; - a per-registry
min_release_ageon an enabled proxy registry without a quarantine of that registry (curation.<registry>.quarantineor the globalcuration.quarantine); - a global
min_release_agewithout a quarantine while the enable-set mounts proxy registries whose own flags are off, or with Hugging Face mounted byall,hf; curation.require_integritywithoutcuration.allowlist_path;- any
[curation.hf]setting orNORA_CURATION_HF_*variable — Hugging Face models are held by repository and commit in the allowlist and blocklist.
What changed
Section titled “What changed”| Change | Impact | Action required |
|---|---|---|
| Cargo: a crate published to NORA is served only from its own entries | No upstream is asked for it; a download of a version it does not have is 404 and nothing is fetched or stored | A first cargo publish over a stored index an older release left without per-version entries is refused with 409 naming the key: delete the key if it is a cached upstream crate, or set NORA_CARGO_IMPORT_EMBEDDED=<name> if it is your own |
Cargo: - and _ name one crate, as on crates.io | Another spelling of a published crate is 404 (naming the published spelling) and never fetched; publishing it is 409 | None. The first start writes spelling records for crates published before 1.4.0 before it accepts requests (one listing of the published entries) |
| Cargo: copies of unknown versions an older release stored beside a published crate | Not served for names with - or _; still listed in the UI and counted by keep_last | Delete them by hand (#1163) |
| Cargo retention and GC | Per-version index entries and .crate files of one- and two-letter names are no longer deleted | None |
| Docker: a pushed tag | Answered by the pushed manifest only, also after a pull through the proxy; curation dates it by the push | A tag pushed before 1.4.0 over a tag that was already proxied stays shadowed by the proxied copy until it is pushed again |
| Docker: a manifest by digest | An upstream answer with another digest counts as a failed upstream; a push by digest with other bytes is 400 DIGEST_INVALID | None |
Docker: tags ending in .meta or .stats | 400 on every manifest route | Rename such tags |
| Docker: a delete that cannot read the manifest metadata | 500, nothing removed (was 202) | None |
| Docker: a curation refusal | docker pull and skopeo print denied: blocked by policy: … | None |
| npm: a package published to NORA | Its packument, version manifests and dist-tags are answered from its own keys and never ask an upstream | A publish over a packument of unknown origin on a package with no published versions is 409 naming the key: delete it if it is a cache, or set NORA_NPM_IMPORT_EMBEDDED=<name> if it is your package |
npm: npm search and other metadata paths | Answered by the upstream, not cached | None |
| An empty upstream setting for gems, NuGet, Conan, Terraform, Ansible, CPAN | The format answers from storage alone (was: the public default upstream) | None, if you meant “no upstream” |
| PyPI: an upstream’s credential | Sent only to that upstream, not to file hosts it links to | None |
curation.mode left at its default with proxy registries enabled | A warning on every start and nora_config_deprecated{reason="curation_mode_implicit"} 1; 1.5.0 will stop at startup | Set curation.mode (NORA_CURATION_MODE) to off, audit or enforce |
| Client address behind a reverse proxy | Read from the right of X-Forwarded-For, past the trusted proxies | Check NORA_AUTH_TRUSTED_PROXIES if NORA sits behind more than one proxy |
| Hugging Face Hub proxy | New, opt-in (NORA_HF_ENABLED=true) | None |
Rollback
Section titled “Rollback”Stop 1.4.0, start 1.3.6 on the same storage. Published Cargo crates, npm packages and Docker images keep working. 1.3.6 ignores the spelling records and the upstream copies 1.4.0 keeps under keys of its own, so it fetches those upstream packages again. An npm packument an older release cached for an unpublished package is never rewritten by 1.4.0, so 1.3.6 still finds it.
1.3.3 to 1.3.4
Section titled “1.3.3 to 1.3.4”1.3.4 reads 1.3.3 storage as is, on local disk and on S3. No migration is needed.
What changed
Section titled “What changed”| Change | Impact | Action required |
|---|---|---|
npm: several upstreams by scope (npm.proxies) | New, opt-in | None. See npm |
| npm: an unreachable upstream on a cold miss | 502 instead of 404 | None. Clients report a gateway error instead of a missing package |
| npm audit with owned scopes or an internal namespace | A request NORA cannot strip of those names gets 4xx with the reason, instead of being forwarded | Use npm 7+ (bulk audit) or yarn npm audit |
| Circuit breaker for Docker, PyPI, npm | One breaker per configured upstream; metric label registry="<format>:<url>" | Update dashboards and alerts that match registry="pypi" etc. to registry=~"pypi(:.*)?" |
circuit_breaker.overrides.docker | Now applied (was ignored) | Check the values you set |
| Unknown keys in config.toml | Logged as a warning that names them | Optionally set NORA_CONFIG_STRICT=true to refuse them |
| Local storage writes | Staged in .nora-staging/ under the storage root; a restart removes what a crashed instance left there | None |
| Logs | URL credentials (user:pass@) are masked | None |
Rollback
Section titled “Rollback”Stop 1.3.4, start 1.3.3 on the same storage. 1.3.3 serves everything 1.3.4 stored, and its retention and GC do not see the records 1.3.4 keeps under .nora-origins/ and .nora-staging/.
v0.8 to v0.9
Section titled “v0.8 to v0.9”v0.9 is backward-compatible for all features and storage. The only action required is updating renamed environment variables if you use any of the renamed names listed below.
What changed
Section titled “What changed”| Feature | Impact | Action required |
|---|---|---|
| Docker namespace isolation | Storage layout adds namespace prefix | None — lazy migration is automatic |
| Circuit breaker | New feature, disabled by default | None |
| Docker metadata TTL + stale-while-error | New feature, opt-in | None |
| Streaming read_timeout | New feature, opt-in | None |
| SIGHUP hot reload for curation | New capability | None |
| linux/arm64 binary | New platform | None |
Docker namespace migration
Section titled “Docker namespace migration”v0.9 introduces per-upstream namespace prefixes for Docker storage keys to isolate data from different upstream registries.
Old layout (v0.8):
docker/{name}/blobs/{digest}docker/{name}/manifests/{ref}.jsonNew layout (v0.9):
docker/{namespace}/{name}/blobs/{digest}docker/{namespace}/{name}/manifests/{ref}.jsonThe namespace is derived from the upstream URL (e.g., registry-1.docker.io becomes docker.io) or set explicitly via the namespace field in [[docker.upstreams]].
Migration is automatic and lazy:
- When NORA serves a request, it first checks the namespaced path.
- If not found, it falls back to the legacy flat path.
- No background migration runs at startup.
- Existing cached data continues to be served without interruption.
Upgrade steps
Section titled “Upgrade steps”- Stop the running NORA instance.
- Replace the binary or update the container image to v0.9.
- Start NORA with your existing configuration.
# Binary upgradecurl -fsSL https://github.com/getnora-io/nora/releases/latest/download/nora-linux-amd64 -o norachmod +x nora./noraNo data migration scripts are needed.
Rollback
Section titled “Rollback”To roll back from v0.9 to v0.8:
- Stop the v0.9 instance.
- Replace the binary or image with v0.8.
- Start NORA.
New environment variables
Section titled “New environment variables”v0.9 adds these optional variables (all disabled or inactive by default):
| Variable | Default | Description |
|---|---|---|
NORA_CB_ENABLED | false | Enable circuit breaker |
NORA_CB_THRESHOLD | 5 | Failures before opening |
NORA_CB_RESET_TIMEOUT | 30 | Seconds before probing |
NORA_DOCKER_READ_TIMEOUT | 60 | Per-chunk read timeout (seconds) |
NORA_DOCKER_METADATA_TTL | -1 | Metadata cache TTL in seconds |
NORA_DOCKER_SERVE_STALE | true | Serve cached manifests when upstream is down |
See Settings for the full reference.
Renamed environment variables
Section titled “Renamed environment variables”v0.9 shortens several variable names to follow the NORA_{SECTION}_{FIELD} convention (under 30 characters):
| Old name | New name |
|---|---|
NORA_TF_ENABLED | NORA_TF_ENABLED |
NORA_TF_PROXY | NORA_TF_PROXY |
NORA_TF_PROXY_TIMEOUT | NORA_TF_PROXY_TIMEOUT |
NORA_TF_METADATA_TTL | NORA_TF_METADATA_TTL |
NORA_TF_PROXY_TIMEOUT_DL | NORA_TF_PROXY_TIMEOUT_DL |
NORA_CONAN_PROXY_TIMEOUT_DL | NORA_CONAN_PROXY_TIMEOUT_DL |
NORA_CURATION_INTERNAL_NS | NORA_CURATION_INTERNAL_NS |
The old names are no longer recognized. Update your configuration if you use any of these.
See Also
Section titled “See Also”- Settings — full environment variable reference
- Circuit Breaker — new in v0.9
- Docker Proxy — namespace isolation details