portunus-server
Every subcommand of the control-plane binary, grouped by purpose.
portunus-server is the control-plane binary. Most subcommands hit the
loopback HTTP API, so they require PORTUNUS_OPERATOR_TOKEN to be set.
export PORTUNUS_OPERATOR_TOKEN=<paste-token-here>Since v1.1.0, Web UI login uses local passwords and server-side session cookies.
PORTUNUS_OPERATOR_TOKEN is still for API/CLI automation only.
Run portunus-server --help (or portunus-server <subcommand> --help)
for the current authoritative flag surface — the tables below are a
high-level map.
Server lifecycle
| Subcommand | Purpose |
|---|---|
serve | Start the control plane (gRPC + operator HTTP + metrics) |
gen-token | Print a fresh URL-safe-base64 token to stdout |
bootstrap-superadmin --name <name> | Legacy one-shot superadmin API token mint; bearer printed once |
onboarding-token | Offline rotation of the first-run setup token for an unbootstrapped store |
portunus-server --data-dir ./srv serveIf you need non-default listeners or other overrides, place an optional
./srv/server.toml.
For normal first-run setup, start serve and use the setup token printed by the
running server to complete Web UI onboarding. onboarding-token opens the store
directly and serve rotates the token again on start, so it is mainly useful
for offline maintenance and tests.
Clients
| Subcommand | Purpose |
|---|---|
enroll-client <name> [--address <host>] [--ttl-secs <N>] | Print a short-lived portunus-client enroll ... command. --ttl-secs defaults to 600; --address overrides the host clients dial |
revoke <client_name> | Revoke a client's bearer; immediate disconnect |
list-clients [--format text|json] | Show connected status for every provisioned client |
Rules
| Subcommand | Purpose |
|---|---|
push-rule <client> <listen_port> <target> | Push a single-target TCP rule |
push-rule … --protocol udp | UDP variant |
push-rule … --target host:port@<priority> | Multi-target failover (repeat) |
push-rule … --sni <pattern> | TLS SNI routing |
push-rule … --bandwidth-in-bps <N> etc. | Rate-limit caps (v0.11+) |
push-rule <client> <start>-<end> <host>:<start>-<end> | Port-range rule |
push-rule … --prefer-ipv6 | DNS targets, AAAA-first |
remove-rule <rule_id> | Drain + remove a rule |
list-rules / list-rules --client <name> | List rules (filter by client) |
rule-stats <id> | Aggregate per-rule counters |
rule-stats <id> --per-port | Per-port detail (range rules) |
rule-stats <id> --per-target | Per-target detail (multi-target rules) |
Users (v0.5+)
| Subcommand | Purpose |
|---|---|
user-add <id> --display-name <name> [--role admin|user] | Add a user (--role defaults to user) |
user-list | List users |
user-get <id> | Show user details |
user-remove <id> | Remove user (cascades grants + rules) |
reset-password <user_id> [--temporary] [--password-stdin] [--keep-api-tokens] | Local password recovery against the data dir |
reset-password opens the SQLite store directly. Stop serve first if it is
running against the same --data-dir.
portunus-server --data-dir /var/lib/portunus \
reset-password admin --temporaryUse the actual superadmin user ID. For bootstrap-superadmin installs that ID
is _superadmin; for Web onboarding it is the ID chosen during setup.
Without --temporary, the command prompts twice without echo. --password-stdin
reads the new password from the first stdin line for automation. By default,
password reset revokes Web sessions and active API tokens for that user; use
--keep-api-tokens only when you are sure the reset is not incident response.
Credentials
| Subcommand | Purpose |
|---|---|
credential-issue <user_id> --label <label> | Issue a bearer token |
credential-list <user_id> | List credentials for a user |
credential-revoke <user_id> <credential_id> | Revoke a credential |
credential-rotate <user_id> <credential_id> | Rotate; old token 401s |
Grants
| Subcommand | Purpose |
|---|---|
grant-add --user-id <id> --client <name> --listen-port-start <N> --listen-port-end <N> --protocols <tcp,udp> | Add a grant |
grant-list | List grants |
grant-revoke <grant_id> | Revoke a grant (cascades dependent rules) |
Rate limiting (v0.11+)
| Subcommand | Purpose |
|---|---|
owner-cap set <client> <owner> [--bandwidth-in-bps …] | Set per-owner envelope |
owner-cap get <client> <owner> | Read per-owner envelope |
owner-cap list <client> | List all owner envelopes on a client |
owner-cap delete <client> <owner> | Remove an envelope |
Pre-flight rejects an empty set envelope with exit 3 +
validation.rate_limit_no_caps_provided.
Storage (v0.8+)
| Subcommand | Purpose |
|---|---|
backup --out <path> | Online SQLite backup (WAL-aware) |
restore --in <path> [--force] | Restore a backup; runs schema migrations |
reset --confirm | Wipe state.db + sidecar files |
audit prune --before <RFC3339> [--dry-run] | Prune the durable audit table |
Exit codes
| Code | Meaning |
|---|---|
| 0 | Success |
| 1 | Generic error (config, IO, …) |
| 2 | Validation error |
| 3 | Pre-flight validation (e.g. validation.rate_limit_no_caps_provided) |
| 4 | PORTUNUS_OPERATOR_TOKEN missing |
| 6 | Activation failed (e.g. port_in_use) |
| 8 | User not found for local password recovery |
| 75 | Store in use by another process |
| 78 | Schema-version too new (downgrade attempt) |
(See per-subcommand --help for the complete code table.)
Common environment variables
| Variable | Purpose |
|---|---|
PORTUNUS_OPERATOR_TOKEN | Bearer for every operator subcommand |
RUST_LOG | Standard tracing-subscriber env-filter |