Configuration Reference
NORA uses a layered configuration model with three levels of priority:
- Environment variables (highest priority)
- config.toml file
- Built-in defaults (lowest priority)
Config file resolution order:
NORA_CONFIG_PATHenv var (fatal error if set but file not found)config.tomlin the current working directory (optional)- Built-in defaults if no file is found
Environment Variables
Section titled “Environment Variables”Server
Section titled “Server”| Variable | Default | Description |
|---|---|---|
NORA_HOST | 127.0.0.1 | Bind address |
NORA_PORT | 4000 | Listen port |
NORA_PUBLIC_URL | (none) | Public URL for generated download links (e.g., https://registry.example.com). Required when NORA_HOST is 0.0.0.0 or when behind a reverse proxy, otherwise clients receive unreachable URLs in Cargo, PyPI, npm, NuGet, and Terraform responses. |
NORA_BODY_LIMIT_MB | 2048 | Maximum request body size in MB |
NORA_CONFIG_PATH | (none) | Path to config.toml file |
NORA_TRUST_UPSTREAM_DATES | false | Trust upstream Last-Modified/Date headers for cached-artifact freshness. Default off — NORA stamps its own fetch time |
NORA_TLS_CA_CERT | (none) | Path to a PEM CA certificate added as a trusted root for NORA’s outbound TLS to upstreams (e.g. a corporate TLS-inspecting proxy or a private registry with an internal CA) |
Storage
Section titled “Storage”| Variable | Default | Description |
|---|---|---|
NORA_STORAGE_MODE | local | Storage backend: local or s3 |
NORA_STORAGE_PATH | data/storage | Local storage directory |
NORA_STORAGE_S3_URL | http://127.0.0.1:9000 | S3-compatible endpoint URL |
NORA_STORAGE_BUCKET | registry | S3 bucket name |
NORA_STORAGE_S3_ACCESS_KEY | (none) | S3 access key |
NORA_STORAGE_S3_SECRET_KEY | (none) | S3 secret key |
NORA_STORAGE_S3_REGION | us-east-1 | S3 region |
Authentication
Section titled “Authentication”| Variable | Default | Description |
|---|---|---|
NORA_AUTH_ENABLED | false | Enable authentication |
NORA_AUTH_ANONYMOUS_READ | false | Allow unauthenticated read (pull) access |
NORA_AUTH_HTPASSWD_FILE | users.htpasswd | Path to htpasswd file |
NORA_AUTH_TOKEN_STORAGE | data/tokens | Directory for API token storage |
NORA_AUTH_DOCKER_ANON_PULL | false | Allow unauthenticated docker pull (separate fail-closed switch — NORA_AUTH_ANONYMOUS_READ does not open Docker) |
NORA_AUTH_ADMIN_USERS | (none) | Comma-separated usernames granted the admin role (bootstrap fallback; see Authentication) |
NORA_AUTH_TOKEN_CACHE_TTL | 300 | API-token validation cache TTL in seconds |
NORA_AUTH_TRUSTED_PROXIES | 127.0.0.1,::1 | Comma-separated IPs/CIDRs whose X-Forwarded-For header is trusted |
Registry Enable/Disable
Section titled “Registry Enable/Disable”NORA_REGISTRIES_ENABLE selects registries in one shot (e.g. docker,npm,pypi, or all); when set it overrides the individual NORA_*_ENABLED flags below.
| Variable | Default | Description |
|---|---|---|
NORA_DOCKER_ENABLED | true | Enable Docker (OCI) registry |
NORA_MAVEN_ENABLED | true | Enable Maven registry |
NORA_NPM_ENABLED | true | Enable npm registry |
NORA_CARGO_ENABLED | true | Enable Cargo (Rust) registry |
NORA_PYPI_ENABLED | true | Enable PyPI (Python) registry |
NORA_GO_ENABLED | true | Enable Go module proxy |
NORA_RAW_ENABLED | true | Enable raw file storage |
NORA_GEMS_ENABLED | false | Enable RubyGems registry |
NORA_TF_ENABLED | false | Enable Terraform provider registry |
NORA_ANSIBLE_ENABLED | false | Enable Ansible Galaxy registry |
NORA_NUGET_ENABLED | false | Enable NuGet registry |
NORA_PUB_ENABLED | false | Enable Dart/Flutter pub registry |
NORA_CONAN_ENABLED | false | Enable Conan (C/C++) registry |
| Variable | Default | Description |
|---|---|---|
NORA_MAVEN_PROXIES | https://repo1.maven.org/maven2 | Upstream proxies. Format: url1,url2 or url1|auth1,url2|auth2 |
NORA_MAVEN_PROXY_TIMEOUT | 30 | Proxy timeout in seconds |
NORA_MAVEN_CHECKSUM_VERIFY | true | Verify uploaded checksums against server-computed values |
NORA_MAVEN_IMMUTABLE_RELEASES | true | Prevent overwriting released (non-SNAPSHOT) artifacts |
NORA_MAVEN_METADATA_TTL | 300 | Metadata cache TTL in seconds (0 = cache forever) |
| Variable | Default | Description |
|---|---|---|
NORA_NPM_PROXY | https://registry.npmjs.org | Upstream npm registry |
NORA_NPM_PROXY_AUTH | (none) | Upstream auth (user:pass) |
NORA_NPM_PROXY_TIMEOUT | 30 | Proxy timeout in seconds |
NORA_NPM_METADATA_TTL | 300 | Metadata cache TTL in seconds (0 = cache forever) |
NORA_NPM_SERVE_STALE | true | Serve stale cached metadata when the upstream is unreachable |
NORA_NPM_REVALIDATE | true | Send conditional (304) revalidation upstream before serving cached metadata |
| Variable | Default | Description |
|---|---|---|
NORA_PYPI_PROXY | https://pypi.org/simple/ | Upstream PyPI registry |
NORA_PYPI_PROXY_AUTH | (none) | Upstream auth (user:pass) |
NORA_PYPI_PROXY_TIMEOUT | 30 | Proxy timeout in seconds |
NORA_PYPI_PROXIES | (none) | Multiple upstreams (comma-separated url or url|auth); takes precedence over NORA_PYPI_PROXY |
Docker
Section titled “Docker”| Variable | Default | Description |
|---|---|---|
NORA_DOCKER_PROXIES | https://registry-1.docker.io | Upstream registries. Format: url1,url2 or url1|auth1,url2|auth2 |
NORA_DOCKER_PROXY_TIMEOUT | 300 | Proxy timeout in seconds |
NORA_DOCKER_DEFAULT_ACTION | allow | Action for repositories with no explicit rule: allow (proxy upstream) or deny |
Docker also honors NORA_DOCKER_METADATA_TTL, NORA_DOCKER_SERVE_STALE, and NORA_DOCKER_READ_TIMEOUT — see Docker Proxy.
| Variable | Default | Description |
|---|---|---|
NORA_GO_PROXY | https://proxy.golang.org | Upstream Go module proxy |
NORA_GO_PROXY_AUTH | (none) | Upstream auth (user:pass) |
NORA_GO_PROXY_TIMEOUT | 30 | Proxy timeout in seconds |
NORA_GO_PROXY_TIMEOUT_ZIP | 120 | Timeout for .zip downloads in seconds |
NORA_GO_MAX_ZIP_SIZE | 104857600 | Maximum module zip size in bytes (default 100MB) |
NORA_GO_METADATA_TTL | 300 | Metadata cache TTL in seconds (0 = cache forever) |
| Variable | Default | Description |
|---|---|---|
NORA_CARGO_PROXY | https://crates.io | Upstream Cargo registry |
NORA_CARGO_PROXY_AUTH | (none) | Upstream auth (user:pass) |
NORA_CARGO_PROXY_TIMEOUT | 30 | Proxy timeout in seconds |
NORA_CARGO_METADATA_TTL | 300 | Metadata cache TTL in seconds (0 = cache forever) |
| Variable | Default | Description |
|---|---|---|
NORA_RAW_MAX_FILE_SIZE | 104857600 | Maximum file size in bytes (default 100MB) |
NORA_RAW_CACHE_CONTROL | no-cache | Cache-Control header for GET/HEAD responses |
RubyGems
Section titled “RubyGems”| Variable | Default | Description |
|---|---|---|
NORA_GEMS_PROXY | https://rubygems.org | Upstream RubyGems registry |
NORA_GEMS_PROXY_AUTH | (none) | Upstream auth (user:pass) |
NORA_GEMS_PROXY_TIMEOUT | 30 | Proxy timeout in seconds |
NORA_GEMS_METADATA_TTL | 300 | Metadata cache TTL in seconds |
NORA_GEMS_SERVE_STALE | true | Serve stale cached metadata when the upstream is unreachable |
NORA_GEMS_REVALIDATE | true | Send conditional (304) revalidation upstream before serving cached metadata |
Terraform
Section titled “Terraform”| Variable | Default | Description |
|---|---|---|
NORA_TF_PROXY | https://registry.terraform.io | Upstream Terraform registry |
NORA_TF_PROXY_AUTH | (none) | Upstream auth (user:pass) |
NORA_TF_PROXY_TIMEOUT | 30 | Proxy timeout in seconds |
NORA_TF_PROXY_TIMEOUT_DL | 120 | Timeout for binary downloads in seconds |
NORA_TF_SERVE_STALE | true | Serve stale cached metadata when the upstream is unreachable |
Ansible Galaxy
Section titled “Ansible Galaxy”| Variable | Default | Description |
|---|---|---|
NORA_ANSIBLE_PROXY | https://galaxy.ansible.com | Upstream Galaxy server |
NORA_ANSIBLE_PROXY_AUTH | (none) | Upstream auth (user:pass) |
NORA_ANSIBLE_PROXY_TIMEOUT | 30 | Proxy timeout in seconds |
NORA_ANSIBLE_METADATA_TTL | 300 | Metadata cache TTL in seconds (0 = cache forever) |
NORA_ANSIBLE_SERVE_STALE | true | Serve stale cached metadata when the upstream is unreachable |
NORA_ANSIBLE_REVALIDATE | true | Send conditional (304) revalidation upstream before serving cached metadata |
| Variable | Default | Description |
|---|---|---|
NORA_NUGET_PROXY | https://api.nuget.org | Upstream NuGet API |
NORA_NUGET_PROXY_AUTH | (none) | Upstream auth (user:pass) |
NORA_NUGET_PROXY_TIMEOUT | 30 | Proxy timeout in seconds |
NORA_NUGET_METADATA_TTL | 300 | Metadata cache TTL in seconds |
NORA_NUGET_METADATA_TIMEOUT | 2 | Timeout in seconds for upstream service-index/metadata lookups |
NORA_NUGET_SEARCH_SERVICE | https://azuresearch-usnc.nuget.org/query | Upstream search service URL |
NORA_NUGET_AUTOCOMPLETE | https://azuresearch-usnc.nuget.org/autocomplete | Upstream autocomplete service URL |
NORA_NUGET_SERVE_STALE | true | Serve stale cached metadata when the upstream is unreachable |
NORA_NUGET_REVALIDATE | true | Send conditional (304) revalidation upstream before serving cached metadata |
Pub (Dart/Flutter)
Section titled “Pub (Dart/Flutter)”| Variable | Default | Description |
|---|---|---|
NORA_PUB_PROXY | https://pub.dev | Upstream pub registry |
NORA_PUB_PROXY_AUTH | (none) | Upstream auth (user:pass) |
NORA_PUB_PROXY_TIMEOUT | 30 | Proxy timeout in seconds |
NORA_PUB_METADATA_TTL | 300 | Metadata cache TTL in seconds (0 = cache forever) |
NORA_PUB_SERVE_STALE | true | Serve stale cached metadata when the upstream is unreachable |
NORA_PUB_REVALIDATE | true | Send conditional (304) revalidation upstream before serving cached metadata |
Conan (C/C++)
Section titled “Conan (C/C++)”| Variable | Default | Description |
|---|---|---|
NORA_CONAN_PROXY | https://center2.conan.io | Upstream Conan registry |
NORA_CONAN_PROXY_AUTH | (none) | Upstream auth (user:pass) |
NORA_CONAN_PROXY_TIMEOUT | 30 | Proxy timeout in seconds |
NORA_CONAN_PROXY_TIMEOUT_DL | 120 | Timeout for binary downloads in seconds |
NORA_CONAN_METADATA_TTL | 300 | Metadata cache TTL in seconds |
NORA_CONAN_SERVE_STALE | true | Serve stale cached metadata when the upstream is unreachable |
NORA_CONAN_REVALIDATE | true | Send conditional (304) revalidation upstream before serving cached metadata |
Rate Limiting
Section titled “Rate Limiting”| Variable | Default | Description |
|---|---|---|
NORA_RATE_LIMIT_ENABLED | true | Enable rate limiting |
NORA_RATE_LIMIT_AUTH_RPS | 1 | Auth endpoint requests per second |
NORA_RATE_LIMIT_AUTH_BURST | 5 | Auth endpoint burst size |
NORA_RATE_LIMIT_UPLOAD_RPS | 200 | Upload requests per second |
NORA_RATE_LIMIT_UPLOAD_BURST | 500 | Upload burst size |
NORA_RATE_LIMIT_GENERAL_RPS | 100 | General requests per second |
NORA_RATE_LIMIT_GENERAL_BURST | 200 | General burst size |
Garbage Collection
Section titled “Garbage Collection”| Variable | Default | Description |
|---|---|---|
NORA_GC_ENABLED | false | Enable background GC |
NORA_GC_INTERVAL | 86400 | Interval in seconds between GC runs (default 24h) |
NORA_GC_DRY_RUN | false | Only report orphans without deleting |
NORA_GC_GRACE | 604800 | Grace period in seconds before an orphan blob is eligible for deletion (default 7d; must exceed the slowest blob→manifest push gap) |
Retention
Section titled “Retention”| Variable | Default | Description |
|---|---|---|
NORA_RETENTION_ENABLED | false | Enable background retention |
NORA_RETENTION_INTERVAL | 86400 | Interval in seconds between runs (default 24h) |
NORA_RETENTION_DRY_RUN | false | Only report what would be deleted |
Curation
Section titled “Curation”| Variable | Default | Description |
|---|---|---|
NORA_CURATION_MODE | off | Curation mode: off, audit, enforce |
NORA_CURATION_ON_FAILURE | closed | Behavior on filter error: closed (block) or open (allow) |
NORA_CURATION_ALLOWLIST_PATH | (none) | Path to allowlist JSON file |
NORA_CURATION_BLOCKLIST_PATH | (none) | Path to blocklist JSON file |
NORA_CURATION_BYPASS_TOKEN | (none) | Token to bypass curation checks |
NORA_CURATION_REQUIRE_INTEGRITY | false | Require integrity metadata in allowlist entries |
NORA_CURATION_INTERNAL_NS | (none) | Comma-separated glob patterns for internal namespaces |
NORA_CURATION_MIN_RELEASE_AGE | (none) | Global min release age (7d, 12h, 2w) |
NORA_CURATION_NPM_MIN_RELEASE_AGE | (none) | npm-specific min release age override |
NORA_CURATION_PYPI_MIN_RELEASE_AGE | (none) | PyPI-specific min release age override |
NORA_CURATION_CARGO_MIN_RELEASE_AGE | (none) | Cargo-specific min release age override |
NORA_CURATION_GO_MIN_RELEASE_AGE | (none) | Go-specific min release age override |
NORA_CURATION_DOCKER_MIN_RELEASE_AGE | (none) | Docker-specific min release age override |
NORA_CURATION_QUARANTINE | off | Digest-quarantine mode for proxied artifacts: off, observe (record + log), enforce (block unknown/pending digests) |
NORA_CURATION_QUARANTINE_TTL | (none) | Quarantine hold duration (7d, 12h) before a proxied digest is released |
NORA_CURATION_DOCKER_QUARANTINE | (none) | Docker-specific quarantine mode override |
NORA_CURATION_DOCKER_QUARANTINE_TTL | (none) | Docker-specific quarantine TTL override |
Secrets
Section titled “Secrets”| Variable | Default | Description |
|---|---|---|
NORA_SECRETS_PROVIDER | env | Secrets provider: env, aws-secrets, vault, k8s |
NORA_SECRETS_CLEAR_ENV | false | Clear env vars after reading (env provider) |
config.toml Reference
Section titled “config.toml Reference”Below is a complete config.toml with all sections and their default values.
# =============================================================================# Server# =============================================================================[server]host = "127.0.0.1"port = 4000# public_url = "https://registry.example.com" # Required when host = 0.0.0.0 or behind reverse proxybody_limit_mb = 2048
# =============================================================================# Storage# =============================================================================[storage]mode = "local" # "local" or "s3"path = "data/storage"
# S3 settings (used when mode = "s3")s3_url = "http://127.0.0.1:9000"bucket = "registry"# s3_access_key = ""# s3_secret_key = ""s3_region = "us-east-1"
# =============================================================================# Authentication# =============================================================================[auth]enabled = falseanonymous_read = falsehtpasswd_file = "users.htpasswd"token_storage = "data/tokens"
# =============================================================================# Secrets# =============================================================================[secrets]provider = "env" # "env", "aws-secrets", "vault", "k8s"clear_env = false
# =============================================================================# Rate Limiting# =============================================================================[rate_limit]enabled = trueauth_rps = 1auth_burst = 5upload_rps = 200upload_burst = 500general_rps = 100general_burst = 200
# =============================================================================# Docker (OCI) Registry# =============================================================================[docker]enabled = trueproxy_timeout = 300
[[docker.upstreams]]url = "https://registry-1.docker.io"# auth = "user:pass"
# =============================================================================# Maven Registry# =============================================================================[maven]enabled = trueproxy_timeout = 30checksum_verify = trueimmutable_releases = trueproxies = ["https://repo1.maven.org/maven2"]
# Authenticated upstream example:# [[maven.proxies]]# url = "https://private.repo.com/maven2"# auth = "user:pass"
# =============================================================================# npm Registry# =============================================================================[npm]enabled = trueproxy = "https://registry.npmjs.org"# proxy_auth = "user:pass"proxy_timeout = 30metadata_ttl = 300
# =============================================================================# Cargo (Rust) Registry# =============================================================================[cargo]enabled = trueproxy = "https://crates.io"# proxy_auth = "user:pass"proxy_timeout = 30
# =============================================================================# PyPI (Python) Registry# =============================================================================[pypi]enabled = trueproxy = "https://pypi.org/simple/"# proxy_auth = "user:pass"proxy_timeout = 30
# =============================================================================# Go Module Proxy# =============================================================================[go]enabled = trueproxy = "https://proxy.golang.org"# proxy_auth = "user:pass"proxy_timeout = 30proxy_timeout_zip = 120max_zip_size = 104857600 # 100MB
# =============================================================================# Raw File Storage# =============================================================================[raw]enabled = truemax_file_size = 104857600 # 100MBcache_control = "no-cache"
# =============================================================================# RubyGems Registry# =============================================================================[gems]enabled = falseproxy = "https://rubygems.org"# proxy_auth = "user:pass"proxy_timeout = 30index_ttl = 300
# =============================================================================# Terraform Provider Registry# =============================================================================[terraform]enabled = falseproxy = "https://registry.terraform.io"# proxy_auth = "user:pass"proxy_timeout = 30proxy_timeout_dl = 120
# =============================================================================# Ansible Galaxy Registry# =============================================================================[ansible]enabled = falseproxy = "https://galaxy.ansible.com"# proxy_auth = "user:pass"proxy_timeout = 30
# =============================================================================# NuGet Registry# =============================================================================[nuget]enabled = falseproxy = "https://api.nuget.org"# proxy_auth = "user:pass"proxy_timeout = 30metadata_ttl = 300
# =============================================================================# Dart/Flutter Pub Registry# =============================================================================[pub_dart]enabled = falseproxy = "https://pub.dev"# proxy_auth = "user:pass"proxy_timeout = 30
# =============================================================================# Conan (C/C++) Registry# =============================================================================[conan]enabled = falseproxy = "https://center2.conan.io"# proxy_auth = "user:pass"proxy_timeout = 30proxy_timeout_dl = 120metadata_ttl = 300
# =============================================================================# Garbage Collection# =============================================================================[gc]enabled = falseinterval = 86400 # 24 hoursdry_run = false
# =============================================================================# Retention Policies# =============================================================================[retention]enabled = falseinterval = 86400 # 24 hoursdry_run = false
# Retention rules: registry = "*" applies to all formats# [[retention.rules]]# registry = "docker"# keep_last = 10# older_than_days = 90# exclude_tags = ["latest", "v*"]
# [[retention.rules]]# registry = "*"# older_than_days = 180
# =============================================================================# Curation (Package Access Control)# =============================================================================[curation]mode = "off" # "off", "audit", "enforce"on_failure = "closed" # "closed" (fail-safe) or "open" (fail-open)# allowlist_path = "/etc/nora/allowlist.json"# blocklist_path = "/etc/nora/blocklist.json"# bypass_token = "" # prefer NORA_CURATION_BYPASS_TOKEN env varrequire_integrity = falseinternal_namespaces = [] # e.g., ["@mycompany/**", "com.mycompany.**"]Configuration Priority
Section titled “Configuration Priority”When the same setting is specified in multiple places, the highest-priority source wins:
ENV variable > config.toml > built-in defaultFor example, if config.toml sets port = 8080 but NORA_PORT=4000 is also set, NORA will listen on port 4000.
Credential Security
Section titled “Credential Security”NORA warns at startup if credentials (proxy auth, S3 keys) are found in config.toml in plaintext. Best practice is to pass credentials via environment variables or a secrets provider:
# Use env vars for credentialsexport NORA_STORAGE_S3_ACCESS_KEY="your-key"export NORA_STORAGE_S3_SECRET_KEY="your-secret"export NORA_DOCKER_PROXIES="https://registry-1.docker.io|user:pass"In Kubernetes, mount credentials from a Secret into the container environment instead of storing them in config.toml.
See Also
Section titled “See Also”- Authentication — user management and API tokens
- Curation — package access control
- Rate Limits — rate limiting tuning
- Production Deployment — production deployment guide