pcctl command reference
Every pcctl command, flag, default, environment variable and local file, with what each command needs (the admin certificate, --repo, or --repo or --via) and an example.
pcctl is the only way to manage a PowerCloud cluster: there is no shell or SSH on the nodes. This page lists every command pcctl has, with its exact synopsis, flags and defaults, what it needs to run, and an example. It includes commands that pcctl's own usage text leaves out.
For task-oriented guides, see Quickstart, Storage and Managing nodes. Terms such as cluster, repository, location and node are defined in Concepts. pcctl runs on Linux and macOS, on amd64 and arm64 (see Install a node); there is no Windows build.
Conventions
Command line shape
pcctl [GLOBAL OPTIONS] COMMAND [SUBCOMMAND] [FLAGS] [ARGUMENTS]
- Global options come before the command.
pcctl --repo LOC put a bworks;pcctl put a b --repo LOCdoes not. - A command's flags come before its positional arguments.
pcctl app rm --keep-data home-1 webworks; flags after the first positional argument are taken as arguments. The exceptions are noted in each entry (node peer-unlock,node rm --erase,node upgrade --commit,rotate finish --force). -flagand--flagare the same, and a value can be given as--flag valueor--flag=value. Boolean flags take no value (--dry-run), or--flag=false.- Repeatable flags (marked "repeatable") are given once per value:
--env A=1 --env B=2. pcctl -hprints the usage summary and global flags. Runningpcctlwith no command prints it and exits with status 2. Any other failure printspcctl:and the error on stderr and exits with status 1.
What a command needs
Each entry says what the command needs:
| Needs | Meaning |
|---|---|
| certificate | Only the admin certificate saved by login, and the node addresses in the local nodes.json. No passphrase, no storage access. --via is ignored. So is --repo, except by console (which then holds the keys) and the s3 subcommands (which then ask for the passphrase although only s3 enable and s3 key add use it). |
| --repo | The storage locations themselves, with their credentials, and the passphrase. --via is refused. These commands work on each location separately. |
| --repo or --via | The passphrase, and the storage either directly (--repo) or through a node that serves it (--via NAME, which also needs the admin certificate). |
Commands that need the passphrase unlock the cluster's keys on your machine. With --via, the node only relays encrypted blobs and never sees a key.
Global options
| Option | Environment | Default | What it does |
|---|---|---|---|
--repo LOC[,LOC...] |
POWERCLOUD_REPO |
none | The cluster's storage locations, comma-separated. Every write is replicated to all of them. See Location syntax. |
--via NODE |
POWERCLOUD_VIA |
none | Reach the storage through this node instead of --repo (the node must serve it; see node storage). A flag beats the other's environment variable: --via with POWERCLOUD_REPO set goes through the node, and --repo with POWERCLOUD_VIA set uses the locations. If both flags are given, --repo wins. |
--quorum N |
majority | How many locations must accept a write for it to succeed. node storage passes it to the node. |
The flag overrides the environment variable. For example:
export POWERCLOUD_REPO=/srv/pc,s3://my-bucket/pc
pcctl ls photos/
pcctl --via home-1 ls photos/
Location syntax
A location in --repo (and in node storage) is one of:
| Form | What it is |
|---|---|
/path/to/dir or ./dir |
A local directory. |
s3://BUCKET[/PREFIX][?OPTIONS] |
An S3-compatible bucket, optionally under a prefix. |
node://NAME |
A replica on an enrolled node's encrypted disk, reached with the admin certificate. |
ec:K:LOC;LOC;... |
Erasure coding over the listed locations: each blob is split into K data shards plus parity shards, one per location (1 <= K < number of locations <= 255). A write needs K+1 locations (or all, if fewer). The inner locations can be any of the forms above, but not another ec:. |
S3 options, joined with &:
| Option | Default | Meaning |
|---|---|---|
endpoint=URL |
AWS (https://s3.REGION.amazonaws.com) |
The provider's endpoint, http(s)://HOST[:PORT] with no path. Setting it turns on path-style requests. |
region=R |
us-east-1 |
The region to sign requests for (auto for Cloudflare R2). |
creds=NAME |
AWS |
Which credentials to read from the environment: NAME_ACCESS_KEY_ID, NAME_SECRET_ACCESS_KEY and, optionally, NAME_SESSION_TOKEN, with NAME upper-cased. |
path_style=BOOL |
false without endpoint, true with |
Path-style requests. A bucket name with dots needs path_style=true over HTTPS. |
Quote locations that contain & or ;:
export R2_ACCESS_KEY_ID=... R2_SECRET_ACCESS_KEY=...
pcctl --repo '/srv/pc,s3://pc?endpoint=https://ACCOUNT.r2.cloudflarestorage.com®ion=auto&creds=r2' ls
pcctl --repo 'ec:4:s3://a/pc;s3://b/pc;s3://c/pc;s3://d/pc;s3://e/pc;s3://f/pc' ls
The passphrase
Commands that need the cluster's keys read the passphrase from the terminal without echoing it, or from an environment variable for automation:
POWERCLOUD_PASSPHRASE: the cluster passphrase. With it,initalso skips the "Repeat passphrase" prompt.POWERCLOUD_RECOVERY_KEY: unlock with the recovery key thatinit(orrotate) printed, instead of the passphrase. When it is set, no passphrase is asked for.POWERCLOUD_NEW_PASSPHRASE: the new passphrase forrotate. Without it,rotateasks twice on the terminal.
Without a terminal and without these variables, the command fails with no terminal for passphrase.
Environment variables
Every variable pcctl reads:
| Variable | Used by | Meaning |
|---|---|---|
POWERCLOUD_REPO |
all --repo commands |
Default for --repo. |
POWERCLOUD_VIA |
all --via commands |
Default for --via. |
POWERCLOUD_PASSPHRASE |
commands that unlock the cluster | The cluster passphrase (new passphrase for init). |
POWERCLOUD_RECOVERY_KEY |
commands that unlock the cluster | Unlock with the recovery key instead. |
POWERCLOUD_NEW_PASSPHRASE |
rotate |
The new passphrase. |
POWERCLOUD_CONFIG |
everything | The local configuration directory (see Local files). |
POWERCLOUD_UPGRADE_WAIT |
node upgrade |
How long to wait for the node to come back on the new image, as a duration such as 20m. Default 10m. |
AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_SESSION_TOKEN |
S3 locations without creds= |
S3 credentials. |
NAME_ACCESS_KEY_ID, NAME_SECRET_ACCESS_KEY, NAME_SESSION_TOKEN |
S3 locations with creds=name |
S3 credentials for that location. node storage sends the ones its locations name to the node. |
DOCKER_CONFIG |
app deploy --image, cluster app deploy --image |
Directory holding the registry logins (config.json, as docker login writes it). Default ~/.docker. |
HTTPS_PROXY, HTTP_PROXY, NO_PROXY |
S3 locations, image pulls | The usual proxy settings. Connections to nodes never use a proxy. |
POWERCLOUD_TEST_NODE_CERT_LIFETIME |
node enroll, node provision, node renew |
A test hook that shortens node certificates (a duration). Don't set it on a real cluster: nodes drop out of the mesh when their certificates expire. |
Local files
pcctl keeps its state in $POWERCLOUD_CONFIG, or else in the user configuration directory plus powercloud: ~/.config/powercloud (or $XDG_CONFIG_HOME/powercloud) on Linux and ~/Library/Application Support/powercloud on macOS. The directory is mode 0700 and the files 0600.
| File | Written by | Contents |
|---|---|---|
admin.key, admin.crt |
login, renewed by any command that unlocks the cluster |
The admin certificate (30 days) and its key. |
ca.crt |
the same | The cluster CA certificate. |
nodes.json |
node enroll, node provision --addr, node addr; node rm removes entries |
Each known node's name, node ID and API address. Certificate-only commands find nodes here. |
amd-kds/ |
attestation checks | Cached AMD certificates for SEV-SNP verification. |
Cluster storage
init
pcctl --repo LOC[,LOC...] init
Creates a new cluster in the given locations: a new root key, protected by the passphrase you choose (asked twice) and by a recovery key, which it prints once. Write the recovery key down and store it offline. It refuses if a cluster already exists there, and also if any location can't be reached (it might hold an existing cluster).
Needs: --repo.
pcctl --repo /srv/pc,s3://my-bucket/pc init
Initialized cluster 92283421c94b924005629e1405c47c54
RECOVERY KEY (write it down and store it offline — it is shown only once):
PPXR-AHNU-ZWUQ-WODE-USI2-C2TZ-QI4N-7UFI
Without your passphrase or this recovery key, no one — including you — can read this data.
put
pcctl --repo LOC,... put NAME FILE
Encrypts FILE and stores it as object NAME, replicated to every location. Prints the size and chunk count.
Needs: --repo or --via.
pcctl --repo /srv/pc,s3://my-bucket/pc put photos/cat.jpg ./cat.jpg
stored photos/cat.jpg (48213 bytes, 1 chunks)
get
pcctl --repo LOC,... get NAME [FILE]
Reads and decrypts object NAME into FILE (created with mode 0600, replaced if it exists), or to standard output without FILE. Every chunk is authenticated; a tampered copy is an error, not altered data.
Needs: --repo or --via.
pcctl --via home-1 get photos/cat.jpg ./out.jpg
ls
pcctl --repo LOC,... ls [PREFIX]
Lists objects whose names start with PREFIX (all without it): size in bytes, modification time in local time, name.
Needs: --repo or --via.
pcctl --repo /srv/pc ls photos/
48213 2026-10-28 14:02 photos/cat.jpg
rm
pcctl --repo LOC,... rm NAME
Deletes object NAME. Its chunks stay until gc reclaims them.
Needs: --repo or --via.
pcctl --repo /srv/pc rm photos/cat.jpg
check
pcctl --repo LOC,... check [--verify]
Compares every location and reports, per location, its blobs and how many are missing, stale or corrupt. Changes nothing. Exits with an error if the locations differ (run 'pcctl repair') or if some object has data missing from every reachable location.
| Flag | Default | Meaning |
|---|---|---|
--verify |
off | Download and authenticate every copy of every chunk, instead of comparing listings. |
Needs: --repo.
pcctl --repo /srv/pc,s3://my-bucket/pc check --verify
1 objects, 0 deleted, 1 chunks in use, 0 unreferenced (reclaimed by gc)
LOCATION BLOBS MISSING STALE CORRUPT REPAIRED STATUS
/srv/pc 3 0 0 0 0 ok
s3://my-bucket/pc 3 0 0 0 0 ok
repair
pcctl --repo LOC,... repair [--verify]
Brings every location up to date: copies missing blobs, and replaces stale or corrupt copies with a good one. Erasure-coded locations first rebuild missing shards from their own other shards. Use it after a provider was down, or after adding a location. Same flag as check.
Needs: --repo.
pcctl --repo /srv/pc,s3://my-bucket/pc,node://home-1 repair
gc
pcctl --repo LOC,... gc [--grace 24h] [--dry-run]
Deletes chunks that no object references any more, from every location, once they have been unreferenced for the grace period.
| Flag | Default | Meaning |
|---|---|---|
--grace DURATION |
24h |
How long a chunk must stay unreferenced before it is deleted. |
--dry-run |
off | Report what would be deleted, delete nothing. |
Needs: --repo.
pcctl --repo /srv/pc,s3://my-bucket/pc gc --dry-run
1 chunks in use, would delete 0, 0 unreferenced waiting out the 24h0m0s grace period
Nodes
See Enroll a node, Unlocking nodes after a reboot, Upgrades and releases and Managing nodes for the tasks behind these commands.
status
pcctl status
Asks every node in nodes.json about itself, in parallel (10 seconds each), and prints one line per node (state, architecture, version, uptime, CPU, memory, mesh peers reached, apps running, storage locations served, days left on its certificate), then a needs attention list or all nodes healthy.
Needs: certificate.
pcctl status
console
pcctl console [--port N] [--listen ADDR [--host NAME]...] [--no-open]
pcctl --repo LOC,... console [flags]
Serves the web console on this machine and opens a browser at its one-time link: live status, node details, app logs, and deploying, restarting and removing apps. Started with --repo, it holds the cluster's keys and can also publish and remove cluster apps. Runs until Ctrl-C.
| Flag | Default | Meaning |
|---|---|---|
--port N |
any free port | Port to listen on. |
--listen ADDR |
127.0.0.1 |
IP address to listen on. Another than loopback lets other machines in, over plain HTTP; 0.0.0.0 is every address. |
--host NAME |
with --listen: this machine's name and addresses |
A name or address other machines reach the console by. Repeatable. |
--no-open |
off | Don't open a browser; just print the link. |
Needs: certificate; with --repo, also the passphrase. Given --via (and no --repo), it runs without the keys, as if neither were given.
pcctl console --port 8080 --no-open
node ls
pcctl node ls
Lists the nodes in this machine's nodes.json (name, node ID, API address) without contacting them.
Needs: certificate (reads only the local file).
pcctl node ls
node info
pcctl node info NAME
Shows one node's details: IDs, architecture, kernel, boot and lockdown, state volume, certificate expiry, cluster CA, confidential computing, image and release, storage served and last sync, TPM and peer unlock, membership and revocation list serials, and its mesh peers with endpoint, handshake age and API round-trip time.
Needs: certificate.
pcctl node info home-1
node enroll
pcctl --repo LOC,... node enroll HOST[:PORT] CODE NAME
Joins a new node to the cluster with the enrollment code shown on its console, gives it the key for its encrypted state volume, records it in the cluster registry and in nodes.json, and publishes a new membership list to every node. PORT defaults to 7443. The node's mesh endpoint is set to the same host on port 51820 (unless the host is localhost). Writes an admin certificate if none is saved. Fails if a node named NAME is already enrolled.
Needs: --repo or --via.
pcctl --repo /srv/pc,s3://my-bucket/pc node enroll 192.0.2.10 XXXX-XXXX-XXXX-XXXX-XXXX-XXXX-XXXX-XXXX home-1
node provision
pcctl --repo LOC,... node provision [--addr HOST[:PORT]] [--endpoint IP:PORT] NAME FILE
Creates a node's whole identity ahead of time and writes it to FILE as a join bundle, for a machine that joins at first boot with nobody at its console (cloud user data, or a QEMU fw_cfg file). Registers the node and publishes a membership list that includes it. FILE must not exist. The bundle holds the node's private keys and disk key: delete it once the node is up. Prints how to pass it to AWS, Google Cloud, Azure and QEMU.
| Flag | Default | Meaning |
|---|---|---|
--addr HOST[:PORT] |
none | Where pcctl reaches the node's API, if known. Without it, run node addr once the node is up. |
--endpoint IP:PORT |
none | Where peers reach the node's WireGuard port, if it is public. HOST:PORT is accepted too. |
Needs: --repo or --via.
pcctl --repo /srv/pc,s3://my-bucket/pc node provision web-1 web-1.join
node addr
pcctl --repo LOC,... node addr NAME HOST[:PORT]
Records where pcctl reaches a node's API (PORT defaults to 7443), in the registry and in nodes.json. If the node's mesh endpoint was empty or derived from its old address, it is set to the new host on port 51820 and a new membership list is published. Also the way to add an existing node to nodes.json on another admin machine.
Needs: --repo or --via.
pcctl --repo /srv/pc,s3://my-bucket/pc node addr cloud-1 203.0.113.50
node unlock
pcctl --repo LOC,... node unlock NAME CODE [HOST[:PORT]]
Unlocks a rebooted node's encrypted state volume with the unlock code shown on its console. pcctl pins the node's temporary key from the code, checks the node and volume IDs against the registry, verifies a SEV-SNP attestation if the node offers one (and requires one if the node was attested before), and only then sends the key. HOST[:PORT] reaches the node at another address for this unlock only. During a key rotation, a node not yet moved is unlocked with the previous keys.
Needs: --repo or --via.
pcctl --repo /srv/pc,s3://my-bucket/pc node unlock home-1 XXXX-XXXX-XXXX-XXXX # the code from the node's console
node tpm
pcctl --repo LOC,... node tpm NAME on|off
Turns unattended unlock with the node's TPM on or off. With Secure Boot and a TPM 2.0, the node then unlocks its state at boot by itself, only on the same machine with the same Secure Boot keys. See Unlocking nodes after a reboot.
Needs: --repo or --via.
pcctl --repo /srv/pc,s3://my-bucket/pc node tpm home-1 on
node peer-unlock
Not in pcctl's usage text.
pcctl --repo LOC,... node peer-unlock NAME on [--threshold K]
pcctl --repo LOC,... node peer-unlock NAME off
Turns peer unlock on or off: the node splits a key to its state volume into shares held by its peers, and after a reboot unlocks itself while K of them answer. --threshold comes after on. All peers must be reachable over the mesh to turn it on. Turn it on again after adding or moving nodes or rotating the keys. See Unlocking nodes after a reboot.
| Flag | Default | Meaning |
|---|---|---|
--threshold K |
a majority of the peers | How many peers must answer. |
Needs: --repo or --via.
pcctl --repo /srv/pc,s3://my-bucket/pc node peer-unlock home-1 on --threshold 2
node attest
pcctl node attest NAME
pcctl --repo LOC,... node attest NAME sev-snp|off
With only NAME: asks the running node for a fresh AMD SEV-SNP attestation, bound to a random nonce and the node's key, and verifies it against AMD's certificate chain. Needs: certificate.
With sev-snp or off (not in pcctl's usage text): sets or clears the registry's requirement that the node present an SEV-SNP attestation at every unlock. node unlock sets it by itself the first time a node attests; use off when a node has moved to a machine without SEV-SNP on purpose. Needs: --repo or --via.
pcctl node attest cvm-1
node cvm-1: AMD SEV-SNP verified (...); launch measurement ...
node rm
pcctl --repo LOC,... node rm [--erase] NAME
Removes a node: revokes its certificate on every node with a CA-signed revocation list, drops it from the mesh and from the registry, and removes it from nodes.json. It can no longer be unlocked. --erase must come right after rm.
| Flag | Default | Meaning |
|---|---|---|
--erase |
off | First have the node crypto-erase its state volume and power off. If the node can't be reached, nothing is removed; run without --erase to remove it anyway. |
Needs: --repo or --via.
pcctl --repo /srv/pc,s3://my-bucket/pc node rm --erase home-1
node renew
pcctl --repo LOC,... node renew [NAME...]
Renews node certificates (they last a year). Without names, renews every registered node whose certificate expires within 30 days or has expired; named nodes are renewed regardless. Works on expired certificates. Prints one line per node.
Needs: --repo or --via.
pcctl --via home-1 node renew
node storage
pcctl --repo LOC,... node storage [--sync 1h|off] NAME [LOC,...]
Lets node NAME serve the cluster's storage, so admins can use --via NAME. Sends the node the locations (--repo's, or the ones given, for a node that reaches them by other addresses), the write quorum (--quorum) and the S3 credentials those locations name, taken from your environment. The node keeps them on its encrypted disk and refuses locations it can't reach or that belong to another cluster. Only s3:// and node:// locations (and ec: over them) can be served.
| Flag | Default | Meaning |
|---|---|---|
--sync DURATION |
1h |
How often the node copies blobs some locations lack from one that has them; off turns it off. |
Needs: --repo (refused with --via).
pcctl --repo 's3://a/pc?creds=r2,s3://b/pc?creds=b2' node storage --sync 30m home-1
node sync
pcctl node sync NAME
Has a node that serves storage copy missing blobs between its locations now, and prints the result. Exits with an error (sync incomplete) if any copy failed.
Needs: certificate.
pcctl node sync home-1
node upgrade
pcctl node upgrade NAME FILE.efi
pcctl node upgrade --commit NAME
Installs a PowerCloud node image (powercloud-VERSION-ARCH.efi from a PowerCloud release, or out/powercloud-ARCH.efi built from source) on one node, A/B: the node writes it beside the running image and reboots into it once. When pcctl reaches the node on the new image, it commits it as the default. A node that doesn't come back on it reverts at its next boot. pcctl waits up to 10 minutes (POWERCLOUD_UPGRADE_WAIT). --commit (in that position) commits an image on trial, for example after you had to unlock the node first. See Upgrades and releases.
Needs: certificate.
pcctl node upgrade home-1 powercloud-vYYYY.MM.DD-amd64.efi
node poweroff, node reboot
pcctl node poweroff NAME
pcctl node reboot NAME
Powers off or reboots a node. After a reboot the node is locked until unlocked (by node unlock, its TPM or its peers).
Needs: certificate.
pcctl node reboot home-1
Mesh
mesh endpoint
pcctl --repo LOC,... mesh endpoint NAME IP:PORT
Sets where peers reach node NAME's WireGuard port, and publishes a new membership list. HOST:PORT (a DNS name, resolved by the nodes every minute) is accepted, and '' clears the endpoint, for a node behind NAT.
Needs: --repo or --via.
pcctl --repo /srv/pc mesh endpoint home-1 home.example.net:51820
mesh sync
pcctl --repo LOC,... mesh sync
Asks every reachable node for its WireGuard key and records any that changed, then publishes the revocation list (if anything was ever revoked) and the membership list to every node. For a node whose key changed or that missed an update.
Needs: --repo or --via.
pcctl --repo /srv/pc mesh sync
mesh api
Not in pcctl's usage text.
pcctl --repo LOC,... mesh api NAME HOST:PORT
Sets where peers reach node NAME's API outside the mesh, which locked nodes use for peer unlock. By default that is the address pcctl uses (unless it is on this machine only), else the mesh endpoint's host. '' returns to the default. Publishes a new membership list. Turn peer unlock on again afterwards, as holders' addresses are copied when it is turned on.
Needs: --repo or --via.
pcctl --repo /srv/pc mesh api home-2 192.0.2.11:7443
Apps
Apps are static Linux binaries or container images that a node runs as sandboxed services. All app commands talk to one node and need only the certificate. See Apps on a node.
app deploy
pcctl app deploy [OPTIONS] NODE NAME FILE [-- ARGS...]
pcctl app deploy --image NAME[:TAG][@DIGEST] [OPTIONS] NODE NAME [-- COMMAND...]
Deploys (or replaces) app NAME on node NODE. For a binary, everything after FILE is passed to it as arguments, with or without --. For an image, pcctl pulls it on your machine for the node's architecture and sends the flattened files; arguments after -- replace the image's command. Prints the node's apps afterwards.
| Flag | Default | Meaning |
|---|---|---|
--mem SIZE |
256M |
Memory limit, with K, M or G. |
--cpu N |
none | CPU limit in CPUs, such as 0.5. A microVM gets one vCPU per CPU, rounded up. |
--procs N |
256 | Process and thread limit. |
--env K=V |
Environment variable. Repeatable. | |
--port NODE:APP |
Publish the app's port APP on the node's port NODE; NODE:APP/udp for UDP. Repeatable. |
|
--net host |
the app's own network | Share the node's network instead. |
--image REF |
Deploy a container image instead of a binary. | |
--link NAME:PORT |
Let the app reach app NAME's port PORT by its name; /udp for UDP. Repeatable. |
|
--egress |
off | Let the app connect out, through the node (not to the node itself or other apps). |
--vm |
off | Run the app in a microVM, under a kernel of its own (nodes with KVM). |
pcctl app deploy --image nginx:alpine --port 80:80 home-1 site
app ls
pcctl app ls NODE
Lists a node's apps: state, uptime, restarts, OOM kills, memory used and limit, CPU used and cap, seccomp, network and ports, last exit.
pcctl app ls home-1
app logs
pcctl app logs NODE NAME [BYTES]
Prints the end of an app's output, up to BYTES (default 65536).
pcctl app logs home-1 site 4096
app restart
pcctl app restart NODE NAME
Restarts an app. Not in pcctl's usage summary. Prints nothing on success.
pcctl app restart home-1 site
app rm
pcctl app rm [--keep-data] NODE NAME
Removes an app from a node.
| Flag | Default | Meaning |
|---|---|---|
--keep-data |
off | Keep the app's data directory. |
pcctl app rm --keep-data home-1 site
Cluster apps
Cluster apps are apps the nodes place among themselves and move when a node goes away. All need --repo or --via. See Cluster apps.
cluster app deploy
pcctl --repo LOC,... cluster app deploy [--replicas N | --exclusive] [--nodes a,b] [--storage] [--volume] [APP OPTIONS] NAME FILE [-- ARGS...]
pcctl --repo LOC,... cluster app deploy [--replicas N] [--nodes a,b] [APP OPTIONS] --image REF NAME [-- COMMAND...]
Publishes (or replaces) cluster app NAME, signed by the cluster CA, and sends it to every node it reaches; others get it from their peers. A binary must be a static ELF for amd64 or arm64. An image is pulled once for each architecture among the nodes it may run on (amd64 if none is reached). Takes every app deploy option, plus:
| Flag | Default | Meaning |
|---|---|---|
--replicas N |
1 | How many nodes run the app. |
--nodes a,b |
any node | The nodes that may run it, comma-separated. |
--exclusive |
off | Run on at most one node at any time, through the nodes' consensus (needs consensus init). Only one replica. |
--storage |
off | Give the app an S3 endpoint at 127.0.0.1:9000 backed by the cluster's storage. |
--volume |
off | Keep the app's data directory in the cluster's storage, so it follows the app. Needs --exclusive. |
pcctl --repo /srv/pc cluster app deploy --replicas 2 --image nginx:alpine --port 80:80 site
cluster app ls
pcctl --repo LOC,... cluster app ls
Lists the cluster apps: replicas, allowed nodes, where each runs now (and its state), and the source (binary or image, with +storage, +volume, +exclusive).
pcctl --via home-1 cluster app ls
cluster app rm
pcctl --repo LOC,... cluster app rm NAME
Removes a cluster app from every node.
pcctl --repo /srv/pc cluster app rm site
Consensus and key-value state
The nodes can form a Raft group that keeps a key-value state they agree on, while a majority of voters is up. See Cluster apps for what uses it.
consensus init
pcctl --repo LOC,... consensus init [--nodes a,b,c]
Founds the group with a CA-signed document naming the first voters, and sends it to every node it reaches. Runs once per cluster; nodes enrolled later become voters by themselves. Warns that two voters tolerate no loss.
| Flag | Default | Meaning |
|---|---|---|
--nodes a,b,c |
every node | The first voters, comma-separated. |
Needs: --repo or --via.
pcctl --repo /srv/pc consensus init
consensus status
pcctl consensus status
Shows each node's view of the group: role, term, leader, applied index, number of keys, voters. Nodes without it show not started.
Needs: certificate.
pcctl consensus status
kv
pcctl kv [--node NAME] [--stale] put KEY VALUE
pcctl kv [--node NAME] [--stale] get KEY
pcctl kv [--node NAME] [--stale] rm KEY
pcctl kv [--node NAME] [--stale] ls [PREFIX]
Reads and changes the consensus state through a node. Changes and (by default) reads need a majority of voters and fail after about 10 seconds without one. get prints the value; ls prints KEY=VALUE lines. The flags come before the subcommand.
| Flag | Default | Meaning |
|---|---|---|
--node NAME |
the first node (by name) that answers and has the consensus state | The node to ask. |
--stale |
off | Read the node's own copy, without a majority (may miss recent changes). |
Needs: certificate.
pcctl kv put greeting hello
pcctl kv --stale get greeting
S3 gateway
The S3 gateway lets S3 clients use the cluster's storage through nodes. See S3 gateway.
s3 enable
pcctl --repo LOC,... s3 enable [--port 9443] [--name DNS]... [--ip ADDR]... NODE...
Starts the gateway on the nodes, with a certificate from the cluster CA (valid a year) for the node's own addresses plus the names and addresses given. Running it again renews the certificate. Warns if a node serves no storage (node storage).
| Flag | Default | Meaning |
|---|---|---|
--port N |
9443 | The port the gateway listens on. |
--name DNS |
A DNS name clients reach the gateway by. Repeatable. | |
--ip ADDR |
An address clients reach the gateway at, besides the node's own. Repeatable. |
Needs: --repo (refused with --via).
pcctl --repo /srv/pc s3 enable --name s3.example.net home-1 cloud-1
s3 disable
pcctl s3 disable NODE...
Stops the gateway on the nodes. Needs: certificate.
pcctl s3 disable home-1
s3 key add
pcctl --repo LOC,... s3 key add [--bucket B]... [--read-only] NAME
Creates an access key named NAME and prints AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY once. Keys are kept in the nodes' consensus state, so consensus init must have been run.
| Flag | Default | Meaning |
|---|---|---|
--bucket B |
all buckets | A bucket the key may use. Repeatable. |
--read-only |
off | The key may only read. |
Needs: --repo (refused with --via).
pcctl --repo /srv/pc s3 key add --bucket backups --read-only restic
s3 key ls, s3 key rm
pcctl s3 key ls
pcctl s3 key rm NAME
key ls lists access keys: name, access key ID, buckets, read-only or read-write, creation date. key rm removes a key by name or access key ID; gateways refuse it as soon as their consensus state has the change. Needs: certificate.
pcctl s3 key rm restic
s3 status
pcctl s3 status
Shows which nodes run the gateway: port, names, number of access keys, days left on its certificate, or the error it failed with. Needs: certificate.
s3 ca
pcctl s3 ca
Prints the cluster CA certificate (PEM), for S3 clients to trust. Needs: certificate.
pcctl s3 ca > ca.pem
export AWS_CA_BUNDLE=ca.pem
Releases
release publish
pcctl --repo LOC,... release publish [--version V] IMAGE.efi...
Signs a release of the given node images (at most one per architecture, read from each image's header) and sends it to every node it reaches, with the image for that node's architecture. Nodes that are down get it from their peers. The nodes then upgrade themselves one at a time, and stop the rollout at the first node it fails on. See Upgrades and releases.
| Flag | Default | Meaning |
|---|---|---|
--version V |
the current UTC date and time, such as 2026-10-28T14:02Z |
The release name shown on nodes. |
Needs: --repo or --via.
pcctl --repo /srv/pc release publish --version vYYYY.MM.DD powercloud-vYYYY.MM.DD-amd64.efi powercloud-vYYYY.MM.DD-arm64.efi
release status
pcctl release status
Shows each node's architecture, running image, the release it has (serial and name) and its state on it, including the node a halted rollout failed on. Needs: certificate.
Keys and access
See Admins, keys and revocation.
login
pcctl --repo LOC,... login
Issues a new admin certificate (valid 30 days) and writes it, with the CA certificate, to the configuration directory. Needs: --repo or --via (with --via, you must already hold a working admin certificate to reach the node).
pcctl --repo /srv/pc,s3://my-bucket/pc login
revoke-admins
pcctl --repo LOC,... revoke-admins
Revokes every admin certificate issued so far (for example one on a lost laptop), pushes the revocation list to every node, and issues you a new one. Other admins must run login again. Needs: --repo or --via.
pcctl --repo /srv/pc revoke-admins
rotate
pcctl --repo LOC,... rotate
pcctl --repo LOC,... rotate finish [--force]
Replaces the cluster root key, after a passphrase or recovery key may have leaked. rotate asks for a new passphrase (or reads POWERCLOUD_NEW_PASSPHRASE), which must differ from the old one, prints a new recovery key, re-encrypts the store, deletes the data under the old keys from every location, and moves every reachable node to a new CA with its volume key rewrapped. Every location must be reachable. Run rotate again, with the new passphrase, to move nodes that were offline or to finish an interrupted rotation. rotate finish then stops nodes accepting the old CA and drops the old root key; it refuses while nodes are still on the old keys, unless --force (in that position) gives up on them, after which they must be removed and enrolled again. Moved nodes stop accepting the old CA by themselves 7 days after the rotation started.
Needs: --repo (refused with --via).
pcctl --repo /srv/pc,s3://my-bucket/pc rotate
pcctl --repo /srv/pc,s3://my-bucket/pc rotate finish
Other
version
pcctl version
Prints the version pcctl was built as: the release name (vYYYY.MM.DD) for a PowerCloud release, or dev when built from source with go build ./cmd/pcctl. Needs nothing.
Commands missing from the usage text
pcctl -h summarises most commands. These exist in pcctl but are not in that summary, or appear there with fewer options:
| Command | Where it is described |
|---|---|
node peer-unlock NAME on [--threshold K], node peer-unlock NAME off |
node peer-unlock |
node attest NAME sev-snp|off |
node attest |
mesh api NAME HOST:PORT |
mesh api |
app restart NODE NAME |
app restart |
app rm --keep-data, app logs NODE NAME BYTES |
app rm, app logs |
app deploy options --procs, --port, --net, --image, --link, --egress, --vm |
app deploy |
cluster app deploy options --exclusive, --storage, --volume |
cluster app deploy |
Quick lookup
| Command | Needs |
|---|---|
init, check, repair, gc, rotate, rotate finish, node storage, s3 enable, s3 key add |
--repo |
put, get, ls, rm, login, revoke-admins, node enroll, node provision, node addr, node unlock, node tpm, node peer-unlock, node attest NAME sev-snp|off, node rm, node renew, mesh endpoint, mesh sync, mesh api, cluster app deploy|ls|rm, consensus init, release publish |
--repo or --via |
status, console, node ls, node info, node attest NAME, node sync, node upgrade, node poweroff, node reboot, app ..., consensus status, kv ..., s3 disable, s3 key ls, s3 key rm, s3 status, s3 ca, release status |
certificate |
version |
nothing |