Managing nodes
Day-to-day operation of PowerCloud nodes with pcctl, including status, node info, the web console, power, storage sync, changing addresses, the mesh, NAT traversal, relays and how pcctl finds and authenticates to nodes.
This page covers running PowerCloud nodes once they are enrolled: seeing their health, opening the web console, rebooting them, and keeping the mesh working when addresses change. Most of these commands need only your admin certificate, not the cluster passphrase. The ones that change the cluster's records (addresses, endpoints) unlock the cluster with --repo or --via.
A node is a machine running PowerCloud OS that has joined your cluster (see Enroll a node). Terms such as cluster, repository and admin certificate are defined in Concepts. Every command and flag is listed in pcctl command reference.
How pcctl finds and authenticates to nodes
pcctl keeps its credentials and its list of nodes in a local configuration directory:
$POWERCLOUD_CONFIGif that variable is set.- Otherwise the operating system's user configuration directory plus
powercloud:~/.config/powercloudon Linux (or$XDG_CONFIG_HOME/powercloud), and~/Library/Application Support/powercloudon macOS.
The directory is created with mode 0700 and each file with mode 0600. It holds:
| File | What it is |
|---|---|
admin.key, admin.crt |
Your admin client certificate and its private key, issued by the cluster CA. Valid for 30 days. |
ca.crt |
The cluster CA certificate, used to check that a node is really one of yours. |
nodes.json |
The nodes this machine knows: each node's name, node ID and API address (HOST:PORT). |
amd-kds/ |
A cache of AMD's certificates, used when verifying SEV-SNP attestation. |
Every connection to a node is mutual TLS. pcctl presents the admin certificate, and checks that the node's certificate comes from your cluster CA and names the node ID recorded for it in nodes.json. A node accepts only certificates from its own cluster CA, and checks the role (admin or node) on every request. Nodes have no SSH and no login: the node API on TCP port 7443 is the only way in.
Getting and renewing the admin certificate
pcctl --repo LOC,... login unlocks the cluster with the passphrase and writes a fresh admin certificate:
pcctl --repo /srv/pc,s3://my-bucket/pc login
admin certificate for cluster 92283421c94b924005629e1405c47c54 written to /home/alex/.config/powercloud (valid 30 days)
You rarely need to run it by hand. Any command that unlocks the cluster (with --repo or --via) reissues the saved certificate when it has a week or less left, and prints a note on stderr. node enroll and node provision write one if none is saved. If the certificate has expired, commands that use it say so and ask you to run login. To revoke every admin certificate, for example one on a lost laptop, see Admins, keys and revocation.
To save typing, set the storage locations once in the environment. POWERCLOUD_REPO stands in for --repo on every command:
export POWERCLOUD_REPO=/srv/pc,s3://my-bucket/pc
Which nodes pcctl knows
nodes.json is filled in by this machine's own commands: node enroll, node provision --addr, and node addr add or update a node, and node rm removes it. The cluster's shared record of nodes (the registry, kept in the encrypted storage) is what --repo and --via commands use, so every admin sees the same nodes there.
On a second admin machine, login writes the certificate but no node list. Record each node's address on that machine with node addr (it needs the cluster passphrase), after which status, node info and the other certificate-only commands work there too:
pcctl --repo LOC,... login
pcctl --repo LOC,... node addr home-1 192.0.2.10
Cluster status
pcctl status asks every known node about itself, all at once, and prints one line per node followed by what needs attention. It uses only the admin certificate.
pcctl status
NODE STATE ARCH VERSION UPTIME CPU MEMORY MESH APPS STORAGE CERT
cloud-1 ok arm64 vYYYY.MM.DD 72h4m10s 3% of 2 412/3891 MiB 2/2 peers 1/1 2 loc 341d
home-1 ok amd64 vYYYY.MM.DD 5h12m3s 12% of 4 1204/7820 MiB 1/2 peers 3/3 - 200d
vps-1 unreachable - - - - - - - - -
needs attention:
home-1: reaches 1 of 2 mesh peers
vps-1: unreachable (dial tcp 198.51.100.4:7443: i/o timeout)
The columns:
| Column | Meaning |
|---|---|
STATE |
ok, plus AMD SEV-SNP when the node runs on a confidential VM; unreachable when it doesn't answer within 10 seconds, or answers with an error. |
ARCH, VERSION, UPTIME |
The node's architecture, the PowerCloud version it runs and how long since it booted. |
CPU |
How busy its CPUs are, of how many. |
MEMORY |
Memory in use of the total, in MiB. |
MESH |
How many of its mesh peers it can reach over the mesh. |
APPS |
Apps running, of apps deployed. |
STORAGE |
How many storage locations it serves (- if it serves none; see Storage). |
CERT |
Days until its node certificate expires. |
Needs attention
When nothing is wrong, the last line is all nodes healthy (it also says so when nodes.json lists no nodes at all). Otherwise each line names a node and a problem:
| Message | What to do |
|---|---|
unreachable (...) |
The node is down, locked after a reboot, or its address changed. Check it with pcctl node info NAME; unlock it (Unlocking nodes after a reboot) or update its address with node addr. |
reaches N of M mesh peers |
Some peers can't be reached over the mesh. See the mesh below. |
app NAME is STATE (...) |
An app isn't running; the last exit is shown. See Apps on a node. |
last storage sync incomplete |
The node's last copy between its storage locations failed for some blobs, or a location couldn't be listed. Run pcctl node sync NAME once the location is back. |
certificate expires in N days |
Fewer than 7 days left. Run pcctl --repo LOC,... node renew. |
release V rejected or halted |
A published release failed on this node. See Upgrades and releases. |
runs an upgrade on trial |
The node booted a new image that isn't committed yet. See Upgrades and releases. |
cluster app NAME: no node has the memory or CPU for it |
A cluster app runs on fewer nodes than it should. See Cluster apps. |
state is in RAM, lost at reboot |
The node has no encrypted state disk, so its identity and apps don't survive a reboot. |
Listing nodes and node details
pcctl node ls prints the nodes in this machine's nodes.json, without contacting them:
pcctl node ls
NAME ID ADDRESS
cloud-1 3c91e07d5b2a8f14 203.0.113.7:7443
home-1 fa8adc53910a6a79 192.0.2.10:7443
pcctl node info NAME asks one node for its details:
pcctl node info home-1
It prints these fields, the later ones only when they apply:
| Field | Meaning |
|---|---|
name, id, cluster |
The node's name, node ID and cluster ID. |
arch, kernel, version, uptime |
Architecture, kernel release, PowerCloud version, time since boot. |
boot |
How it booted, including whether Secure Boot is on. |
lockdown |
The kernel lockdown mode. |
state |
encrypted volume, N MiB (N MiB free), or RAM (lost at reboot). |
certificate |
When the node certificate expires, with a reminder to run node renew from 30 days before. |
cluster CA |
The CA fingerprint; during a key rotation, also the old CA it still accepts and until when. |
confidential |
The confidential computing kind, with a hint to verify it with pcctl node attest NAME. |
image |
The running image's sha256, and whether an upgrade is on trial; last upgrade reports a rollback. |
release |
The published release's serial, name and this node's state on it. |
storage, last sync |
Locations served, write quorum, sync interval, and the last sync's result. |
volume, tpm unlock, peer unlock |
How the state volume is encrypted and how it unlocks at boot (Unlocking nodes after a reboot). |
membership, revocations |
The serials of the signed membership and revocation lists the node holds. |
mesh |
Its mesh address and WireGuard port, then a table of peers. |
The peer table shows, for each peer, its mesh address, the endpoint WireGuard sends to (with (relay NAME) when the pair is relayed), the age of the last WireGuard handshake, and whether the peer's API answers over the mesh, with the round-trip time:
mesh fdd5:f552:ce70::fa8a:dc53:910a:6a79 (WireGuard port 51820)
PEER MESH ADDRESS ENDPOINT HANDSHAKE API OVER MESH
cloud-1 fdd5:f552:ce70::3c91:e07d:5b2a:8f14 203.0.113.7:51820 12s ago ok, 18.4 ms
home-2 fdd5:f552:ce70::77e2:1ab:9c3d:4e55 203.0.113.7:51822 (relay cloud-1) 31s ago ok, 41.0 ms
If the node refuses the admin certificate, pcctl says so and suggests login (admin certificates may have been revoked). If the node's own certificate has expired, it suggests node renew NAME.
The web console
pcctl console serves a web page on your own machine that shows the cluster as pcctl status sees it, live, and lets you read app logs and deploy, restart and remove apps. The nodes serve no web page: the console runs inside pcctl and reaches the nodes with your admin certificate, like every other command, so no key leaves your machine.
pcctl console
PowerCloud console at http://127.0.0.1:41377/?t=5b0c...
(for one browser, the first to open it; Ctrl-C to stop)
It opens your browser at that link and runs until you press Ctrl-C.
| Flag | Default | What it does |
|---|---|---|
--port N |
any free port | The port to listen on. |
--listen ADDR |
127.0.0.1 |
The IP address to listen on. Any address other than loopback lets other machines in; 0.0.0.0 listens on every address. Must be an IP address, not a name. |
--host NAME |
this machine's name and addresses | A name or address other machines use to reach the console. Repeatable. Only used with --listen. |
--no-open |
off | Don't open a browser; just print the link. |
What it shows
- A summary bar: nodes up, apps running, CPU busy across all nodes, memory in use, how much memory apps' limits promise of what the nodes set aside for apps, and the number of issues.
- Needs attention: the same list as
pcctl status. - Nodes: one row per node with state, CPU, memory, apps, architecture, version, uptime, mesh peers reached, storage locations served, consensus role and leader, release state, and days until the certificate expires.
- A node's detail (select its row): bars for CPU, memory, app memory and app CPU promised and in use, and the state disk; its addresses (where
pcctlreaches it, the node's own addresses, and its mesh address with each peer's round-trip time or relay); and facts such as node ID, kernel, boot, state encryption, how it unlocks, what apps get, the image and lockdown. - The node's apps: state, uptime, restarts, memory, CPU, network, where each published port is reached (as a link for TCP ports), whether it is a cluster app, and the last exit.
- Logs: the last 64 KiB of an app's output, refreshed every 2 seconds while Follow is ticked.
The page refreshes every 5 seconds and shows how old its data is. A short guided tour starts on a browser's first visit, and again from the Guide button.
What you can do from it
- Restart an app, or Remove it (with an option to keep its data directory). Removing a cluster app removes it from the whole cluster.
- Deploy an app to the selected node, from a container image (pulled on your machine and sent to the node) or a static Linux binary you upload (up to 512 MiB), with memory, CPU cap, published ports, environment, links, microVM and egress options. See Apps on a node for what these mean.
- Deploy a cluster app, which the nodes place among themselves, with replicas, allowed nodes, exclusive, storage and volume options. This needs the cluster's keys, so it is offered only when you start the console with the repository:
pcctl --repo LOC,... console. A console started with--viaor with neither flag can't publish cluster apps. See Cluster apps.
Who can open it
- The link carries a random token. The first browser to open it trades the token for a cookie (HttpOnly, SameSite=Strict), and the link lets no other browser in after that. To open it in another browser, stop and restart
pcctl consolefor a new link. - Requests must use one of the console's own host names, which blocks DNS rebinding, and changes must come from the console's own page.
- The page loads nothing from elsewhere (a strict Content-Security-Policy).
Reaching it from another machine
By default the console listens on loopback only. The safest way to use it from another machine is an SSH tunnel to a loopback console. On the machine that has pcctl and your admin certificate (here admin-box), start the console on a fixed port without a browser:
pcctl console --port 8080 --no-open
On the machine with the browser, forward the port, then open the link the console printed (it uses 127.0.0.1:8080, which the tunnel carries):
ssh -L 8080:127.0.0.1:8080 admin-box
--listen puts it on the network over plain HTTP, and pcctl warns that anyone who can see the traffic can take the link or the session. Use it only on a network you trust:
pcctl console --listen 0.0.0.0 --port 8080 --host admin-box.lan --no-open
Pass --no-open whenever the browser that should use the console is on another machine. Without it, --listen 0.0.0.0 opens a browser on this machine, which then takes the one-time link.
Power and reboots
pcctl node reboot home-1
pcctl node poweroff home-1
node home-1 is rebooting
Both need only the admin certificate. After a reboot a node's encrypted state stays locked until it is unlocked, by you with pcctl --repo LOC,... node unlock NAME CODE, or by itself with TPM or peer unlock. See Unlocking nodes after a reboot. Until then pcctl status reports it as unreachable. A powered-off node has to be started again at the machine or at its provider.
Storage sync on a node
A node can serve the cluster's storage locations so that admins can use --via NAME instead of --repo (set up with node storage, described in Storage). Such a node copies any blob that some of its locations lack from one that has it, one minute after it starts and then every hour by default. pcctl node sync NAME runs that copy now:
pcctl node sync home-1
node home-1 synced its storage: 2026-10-28 14:02 UTC: 18234 blobs, 12 copied
It exits with an error (sync incomplete) if any copy failed or a location couldn't be listed. Sync only fills gaps and needs no keys; replacing stale or corrupt copies is pcctl --repo LOC,... repair.
When an address changes
There are two addresses per node, and they can change separately:
- The API address (
HOST:PORT, port 7443 by default) is wherepcctlreaches the node. - The mesh endpoint (
IP:PORTorHOST:PORT, port 51820 by default) is where the other nodes send the node's WireGuard traffic.
A node's API address: node addr
When a node comes back with a new IP (a cloud VM restarted without a fixed IP, a home router handing out a new lease), tell pcctl where it is:
pcctl --repo LOC,... node addr cloud-1 203.0.113.50
node cloud-1 is at 203.0.113.50:7443
mesh endpoint of cloud-1 set to 203.0.113.50:51820
This updates the cluster registry and this machine's nodes.json. If the node's mesh endpoint was empty or had been derived from its old address, node addr also sets it to the new address on port 51820 and publishes a new membership list to every node, so the other nodes find it again. An endpoint you set by hand with mesh endpoint is left alone. A DNS name works too (node addr home-1 home.example.net), for a node behind dynamic DNS.
A node's mesh endpoint: mesh endpoint
Set the endpoint explicitly when the other nodes must reach the node at a different address from the one pcctl uses, for example a public address with a port forwarded on the router while pcctl uses the LAN address:
pcctl --repo LOC,... mesh endpoint home-1 198.51.100.7:51820
pcctl --repo LOC,... mesh endpoint home-1 home.example.net:51820
pcctl --repo LOC,... mesh endpoint home-1 ''
The last form clears the endpoint, for a node behind NAT that nobody can send to first. Every change publishes a new signed membership list to the nodes. With a DNS name, the nodes resolve it themselves, again every minute, and apply a new address only to a peer with no handshake in the last three minutes.
Re-reading keys: mesh sync
Enrolling, removing and changing endpoints publish the membership list on their own. pcctl --repo LOC,... mesh sync asks every reachable node for its WireGuard key, records any that changed, and publishes the membership and revocation lists to every node again. Use it when a node was missed or its key changed:
pcctl --repo LOC,... mesh sync
Nodes that can't be reached keep the key on record (with a warning), and get the new lists from their mesh peers later.
The mesh
Nodes talk to each other over an encrypted WireGuard mesh. Each node gets a private IPv6 address derived from the cluster ID and its node ID, so there are no addresses to manage. The peer list is the membership list, signed by the cluster CA, which pcctl pushes to every node it can reach whenever it changes; nodes that were offline get it from any peer. Inside the tunnel, nodes authenticate each other again with their node certificates. Every node checks each peer's API through the mesh every 5 seconds, which is what pcctl node info and the MESH column of pcctl status report.
NAT traversal: what's automatic
A node behind NAT (a home router, a cloud VM without a public IP) needs no configuration beyond a clear or unreachable endpoint:
- It connects outwards to the nodes that have a public endpoint, which learn its NAT's public address from its packets.
- Nodes share what they see. A node with a peer it has no session with asks the peers it can reach every 5 seconds, and tries the address they report. Two nodes behind NAT do this at the same time, which opens both NATs, and they get a direct session. Traffic between them doesn't pass through the public node.
- When two nodes still can't connect after 20 seconds (symmetric NAT, as with carrier-grade NAT and many corporate firewalls), they relay through a public node. Both pick the same relay; if it doesn't connect them within another 20 seconds, they move on to the next. The relay forwards WireGuard packets it can't read or change: the session is end to end between the two nodes.
- Relayed pairs try a direct path again every 10 minutes, backing off up to about every 10 hours after repeated failures, in case the network changed.
pcctl node info shows a relayed peer as (relay NAME). These paths are checked in automated tests with emulated NATs.
What you configure
- At least one node with a public endpoint. Two nodes behind NAT find each other only through a third node both can reach. Relays are the nodes with an endpoint in the membership list.
- Firewall ports on public nodes:
| Port | Protocol | Who connects | Needed on |
|---|---|---|---|
| 7443 | TCP | pcctl (and, for peer unlock, locked peers) |
Every node pcctl manages |
| 51820 | UDP | Other nodes' WireGuard | Every node with a public endpoint |
| 51821 to 51920 | UDP | Relayed WireGuard traffic | Public nodes that may act as relays |
| 9443 | TCP | S3 clients | Nodes running the S3 gateway (S3 gateway) |
- The right endpoint. Enrolling a node sets its endpoint from the address you enrolled it at, on port 51820. If that is a LAN address the other nodes can't reach, set the public one with
mesh endpoint(with a port forward on the router), or clear it withmesh endpoint NAME ''so the node is treated as behind NAT. Note thatnode addrsets an empty endpoint again from the new address; clear it afterwards if the node is behind NAT.
Limits
- Mesh changes start from an admin: nodes only pass on membership lists signed by the CA.
- Relaying costs the relay's bandwidth and a detour. Pairs behind truly symmetric NATs keep relaying.
- When the first peer to report a missing node's address is on the same LAN as it, it reports the LAN address, which a node elsewhere can't use; the two connect once that peer loses its session.
- The mesh carries traffic between the nodes' APIs (health checks, consensus, replicas on other nodes). Your admin machine is not on the mesh:
pcctlreaches each node's API directly, on its API address.
Node storage
A node's encrypted disk can hold a replica of the cluster's storage (node://NAME locations), and a node can serve the storage locations to admins so they use --via NAME with only the passphrase and admin certificate. Both are covered in Storage.
Good to know
- Commands that only read or act on one node (
status,node ls,node info,node reboot,node poweroff,node sync,node upgrade,node attest NAME,app ...,console) need only the admin certificate. - Commands that change the cluster's records (
node addr,mesh endpoint,mesh sync,node renew,node rm) unlock the cluster with the passphrase, through--repoor--via. pcctl statusand the console ask each node for at most 10 seconds, so one slow node doesn't hold up the rest.- For problems not covered here, see Troubleshooting.