Part of https://github.com/pnpm/tasks/issues/191. Wrong claims: - cli: drop the nonexistent `add-user --password` flag and document the terminal/stdin password read; `oci-gc --min-age` and `cache-gc --max-age` are the flags (the `-secs` forms are aliases); `--from` defaults to the `storage` key, not an internal field; `info` and `http` log the same access records; only global and server options have PNPR_* variables. - configuration: `packumentTtl` defaults to 5m; the minimal config now sets `auth.htpasswd.file`, and the auth section says accounts live in memory without it or a backend; grouped hosted registries default their org to `<ecosystem>~<name>`; the handshake is served for any surface; the pipeline surface also satisfies "something must be served"; add `package.update_maintainers` to the audit list. - tls-and-reverse-proxy: remove the invalid `publicUrl:` YAML key and the nonexistent `rate_limiting` setting. - backup-and-restore: `pnpr verify` hashes by default (`--check-hashes` does not exist, `--skip-hashes` skips only the hash comparison); `migrate-storage --verify` compares bytes. - webhooks: audit events do not cover publishes or token creation; the example uses a real action and the `actor` field. - cli: the `RUST_LOG` example keeps `pnpr::audit=info`. - install-acceleration: the `--public-url` host is exempt from the private-address refusal. - shared-side-effects-cache: `pnpm pipeline` publishes workspace-task artifacts. Missing facts: `routes.allowedPrivateNetworks`, the upstream `search` key and canonical `maxAge`, built-in `npm.jsr.io` route, relative path resolution, `log` defaults and `type`, `${VAR:-default}` substitution and the full secret-field list, `oci` defaults, `artifacts.quota` bounds, `migrate-storage` destination rules, `--osv false`, `--packument-ttl` default, S3 `forcePathStyle`/`allowHttp` defaults, grouped org layout, OIDC key table, container image section, `backend:` ignoring the htpasswd and token files. Duplicates and links: health probe bodies, reload procedure, and the resolver allowlist now link to their one home; broken `#secret` anchor fixed; links into the pnpm docs use absolute pnpm.io URLs. Stale history: drop "pnpr v1" and the per-paragraph "Since alpha.N" / "Since pnpm 12.x" prefixes, and the contributor-only extensibility text. Also corrects the `as_filter_directive` doc comment, which claimed `http` quiets the rest of the crate.
13 KiB
id, title
| id | title |
|---|---|
| cli | CLI reference |
pnpr runs the registry server when no subcommand is given. The other
subcommands are offline maintenance tools.
pnpr [serve] [OPTIONS]
pnpr config check
pnpr verify [OPTIONS]
pnpr export --out <dir> [OPTIONS]
pnpr migrate-storage [OPTIONS]
pnpr upgrade-storage [--dry-run]
pnpr import-htpasswd --source <path> [OPTIONS]
pnpr add-user <username>
pnpr oci-gc --registry <name> [OPTIONS]
pnpr cache-gc [OPTIONS]
Options
Server options apply to pnpr serve (and bare pnpr). Global path options (-c, --storage, --cache) apply across subcommands.
| Flag | Description |
|---|---|
-c, --config <path> |
Path to a YAML config. When omitted, the global config.yaml in pnpr's config dir is used if it exists, otherwise the bundled default config. |
--listen <addr> |
Address to bind to. Defaults to 127.0.0.1:7677. |
--storage <path> |
Override the storage directory from the loaded config. This directory is the source of truth for hosted packages. |
--cache <path> |
Override the disposable cache directory (the mirror of upstream registries, resolver cache, and local shared-artifact store). Defaults to a .pnpr-cache subdirectory of the storage path. |
--public-url <url> |
URL clients should use to reach the server, used when rewriting dist.tarball URLs in served packuments. Defaults to http://<listen>. |
--packument-ttl <interval> |
Duration before a cached packument is considered stale and refetched (e.g. 5m, 300s, or bare seconds). Defaults to packumentTtl, which defaults to 5m. Alias: --packument-ttl-secs. A registry's maxAge overrides it for that registry. |
--osv [<bool>] |
Enable local OSV npm vulnerability checks. Requires a local OSV npm database zip at --osv-db or <cache>/osv/npm/all.zip. --osv false turns off checks that the config enables. |
--osv-db <path> |
Path to the local OSV npm database zip or extracted JSON directory. |
--disable-registry |
Disable the npm registry surface (packument and tarball reads, publish, unpublish, dist-tags, and search) that is otherwise served whenever the config declares at least one registry. The health and login/token endpoints stay available. |
--disable-resolver |
Disable the install-accelerator surface: GET /-/pnpr, POST /-/pnpr/v0/resolve, and POST /-/pnpr/v0/verify-lockfile. Overrides resolver.enabled. |
--disable-artifacts |
Disable the signed shared-artifact surface. Overrides artifacts.enabled independently of the resolver. |
--disable-pipeline |
Disable the pipeline run-record surface: /-/pnpr/v0/pipeline. Overrides pipeline.enabled. |
-h, --help |
Print help. |
-V, --version |
Print version. |
Environment variables
pnpr reads every option in the Options table, except --help and
--version, from an environment variable when the flag is omitted. The variable is the flag's name with a
PNPR_ prefix, so --config becomes PNPR_CONFIG, --storage becomes
PNPR_STORAGE, --cache becomes PNPR_CACHE, --public-url becomes
PNPR_PUBLIC_URL, and --disable-resolver becomes PNPR_DISABLE_RESOLVER.
The flags of the maintenance subcommands have no environment variable. A flag
given on the command line wins over its variable. Boolean flags accept true, 1, yes, on, false, 0, no,
and off.
PNPR_LISTEN=0.0.0.0:7677 PNPR_PUBLIC_URL=https://registry.example.com pnpr
Subcommands
config check
Validates the YAML configuration file and prints diagnostic details, including configured registries, upstreams, hosted storage, cache directory, auth backends, and enabled surface toggles (registry, resolver, artifacts).
pnpr config check
# or using the hyphenated alias
pnpr config-check
verify
Audits hosted package documents (package.json) against stored blobs. Inspects declared versions, resolves referenced tarballs and attestation blobs, checks for missing or corrupted files, and discovers orphaned blobs not referenced by any version.
# Full checksum verification (SHA-1 and Subresource Integrity)
pnpr verify
# Check that every blob exists, without comparing hashes
pnpr verify --skip-hashes
# Prune unreferenced blobs left behind by interrupted operations (older than 24h)
pnpr verify --prune-orphans
# Prune immediately without age guard
pnpr verify --prune-orphans --min-age-secs 0
| Flag | Description |
|---|---|
--skip-hashes |
Skip recomputing and verifying tarball checksums (cryptographic hashes are verified by default). Alias: --no-check-hashes. |
--prune-orphans |
Automatically delete orphaned blobs not referenced by any hosted package version. Recommended when registry writers are stopped. |
--min-age <interval> |
Minimum age before an unreferenced blob is considered for pruning (e.g. 1d, 86400s, or bare seconds; defaults to 1d). Alias: --min-age-secs. |
export
Exports hosted packages, packuments, and tarball blobs to a local directory.
pnpr export --out /mnt/backups/pnpr-export --include-auth
| Flag | Description |
|---|---|
--out <dir> |
Destination directory for exported packages and files. Required. |
--include-auth |
Include configured auth files (htpasswd, tokens.db) in the output directory (excluded by default). Files are created with restricted (0600) permissions. |
migrate-storage
Migrates hosted packages and blobs from local filesystem storage to an S3-compatible object store.
# Preview packages and blobs that would be transferred
pnpr migrate-storage --to-bucket my-bucket --dry-run
# Transfer and verify blob content on the destination
pnpr migrate-storage --to-bucket my-bucket --verify
| Flag | Description |
|---|---|
--from <dir> |
Source hosted storage directory. Defaults to the configured storage directory (--storage). |
--to-bucket <name> |
Destination S3 bucket name. |
--to-region <region> |
Destination S3 AWS region (e.g. us-east-1). |
--to-endpoint <url> |
Custom S3 endpoint URL (for MinIO, Cloudflare R2, etc.). |
--to-prefix <prefix> |
Destination key prefix within the bucket. |
--dry-run |
Report packages and blobs to migrate without uploading. |
--verify |
Read back and verify content of uploaded blobs after transfer. |
Without --to-bucket, the command migrates into the bucket of the config's
s3: block. With --to-bucket, only the --to-* flags
describe the destination. The region, endpoint, and prefix are not read from
the config, credentials come only from AWS_ACCESS_KEY_ID and
AWS_SECRET_ACCESS_KEY, and forcePathStyle and allowHttp cannot be set.
To reach a plain-HTTP MinIO, configure the s3: block instead:
pnpr -c ./pnpr-s3.yaml migrate-storage --from ./storage --verify
upgrade-storage
Converts the hosted store to the current storage layout.
Back the store up and stop every pnpr process that uses it first. The org of
each configured hosted registry decides which top-level directories are org
namespaces, so run it with the configuration the store was written with.
It refuses what the earlier layout cannot tell apart from the new one: an org
named default, a top-level directory that is both an org and a package, and
a repository whose name starts with default/packages/ or orgs/.
In-progress image uploads are discarded. Files that belong to no package are
reported and left where they are. An interrupted conversion can be run again.
pnpr upgrade-storage --dry-run
pnpr upgrade-storage
| Flag | Description |
|---|---|
--dry-run |
Report what would move without changing anything. |
import-htpasswd
Imports users from an Apache or Verdaccio htpasswd file into pnpr's user store. Supports standard bcrypt hashes ($2a$, $2b$, $2y$) as well as legacy {SHA} hashes (which are upgraded to bcrypt upon first login).
Run this command as an offline maintenance step while pnpr is stopped, or specify an unshared --target path.
# Preview users that would be imported
pnpr import-htpasswd --source /path/to/old/htpasswd --dry-run
# Import and merge with pnpr's configured htpasswd file
pnpr import-htpasswd --source /path/to/old/htpasswd
| Flag | Description |
|---|---|
--source <path> |
Path to the source htpasswd file to import. Required. |
--target <path> |
Path to destination htpasswd file. Defaults to auth.htpasswd.file from config. |
--dry-run |
Preview imported user counts without writing to target file. |
--overwrite |
Overwrite conflicting credentials for existing users in destination file (skipped by default). |
add-user
Creates a user account, or changes the password of an existing one. Use it to create admin accounts, which cannot self-register. Creating an account revokes any tokens left under that username.
The command needs auth.htpasswd.file or a database backend. With the
htpasswd file, run it while pnpr is stopped. A running pnpr does not see the
new account, and its next account change overwrites the file.
# Prompts for the password
pnpr add-user alice
# Reads the password from one line of stdin
printf '%s\n' "$PASSWORD" | pnpr add-user alice
The password is read from the terminal, or from one line of stdin when stdin is not a terminal. It cannot be passed as a flag.
oci-gc
Added in: v0.1.0-alpha.11
Reclaims container image blobs that no retained manifest references. Every writer sharing the store must be stopped for the whole run.
| Flag | Description |
|---|---|
--registry <name> |
The concrete hosted OCI registry to collect, by its config name. Required. |
--dry-run |
Report the candidates without deleting anything. |
--min-age <interval> |
Keep blobs younger than this (e.g. 1d, 86400s, or bare seconds). Defaults to 1d, so an interrupted push can still resume. 0 collects every unreferenced blob. Alias: --min-age-secs. |
cache-gc
Added in: v0.1.0-alpha.16
Reclaims cached upstream tarballs and packuments, prunes orphaned namespaces left behind by per-process secrets or changed configurations, and enforces cache size and age limits.
| Flag | Description |
|---|---|
--dry-run |
Report the candidates without deleting anything. |
--max-size <size> |
Maximum total cache size to retain (e.g. 10GB, 500MB, or raw bytes). Evicts oldest files first (LRU). Overrides the config value. |
--max-age <interval> |
Maximum file age (e.g. 30d, 1h, or bare seconds). Entries older than this are deleted. Overrides the config value. Alias: --max-age-secs. |
--orphans-only |
Only prune orphaned upstream namespaces without evicting active cache entries. |
Logging
The log level is controlled with the standard RUST_LOG environment variable,
which always wins over the level set in the config file:
RUST_LOG=debug pnpr
The config log.level accepts trace, debug, http, info, warn, and
error. info (the default) and http both log one access record per request,
and warn and error drop them. To keep access records while quieting the
rest, set
RUST_LOG=warn,pnpr::access=info,pnpr::audit=info. A RUST_LOG value that
omits pnpr::audit=info drops the audit records below warn.
Examples
Bind to all interfaces and tell clients to reach the server through a public hostname:
pnpr --listen 0.0.0.0:7677 --public-url https://registry.example.com
Run with a custom config and a separate, ephemeral cache volume:
pnpr -c ./pnpr.yaml --cache /mnt/ephemeral/pnpr-cache
Run only the pnpr resolver endpoints, without exposing an npm registry surface:
pnpr --disable-registry
Signals and graceful shutdown
pnpr handles SIGINT (Ctrl-C) and Unix SIGTERM:
- Ceases new connections: The server stops accepting new incoming TCP connections on its listen address.
- Drains in-flight requests: Active requests and ongoing package transfers are allowed to complete cleanly before the process exits.
Configuration changes are applied via process restart rather than in-process reloading (such as SIGHUP). In container orchestrators (such as Kubernetes or Docker Swarm), use rolling deployments so the new replica's readiness probe (GET /-/ready) passes before the old replica receives SIGTERM and drains.
Exit codes
pnpr uses standard exit codes:
| Code | Meaning | Description |
|---|---|---|
0 |
Success | The command completed successfully. For the server, indicates clean termination after SIGINT or SIGTERM. For a maintenance subcommand, indicates all checks and transfers succeeded. |
1 |
Error | The command failed. Causes include invalid CLI flags, YAML configuration errors, address binding conflicts (port already in use), missing storage/auth files, or integrity audit failures (such as pnpr verify finding missing or corrupted blobs). |
In Unix shells, if an external supervisor kills the process before the graceful shutdown handler finishes, the exit status will reflect the signal number (for example, 130 for SIGINT or 143 for SIGTERM).