Requirements
Penumbra's own guidance is 2 to 4 vCPU, 8 GB RAM and ~200 GB of disk growing 20 GB a week. With the pruned snapshot and a pruned pd, the disk figure drops to about 100 GB growing roughly 2 GB a week. Disk latency matters more than CPU: the state store is RocksDB and a virtualized cloud SSD will make you fall behind.
| Port | Service | Exposure |
|---|---|---|
| 26656 | CometBFT P2P | Public. The only inbound port you need. |
| 26657 | CometBFT RPC | Private |
| 26658 | pd ABCI | Private, localhost only |
| 8080 | pd gRPC | Private unless you run an RPC service |
| 9000, 26660 | Metrics | Private |
Stake and the rules
These are the live chain parameters for penumbra-1, read from state at height 12,562,477 on 2026-09-06. Amounts are in UM; the chain counts in upenumbra, one millionth of a UM.
| Parameter | Value | What it means for you |
|---|---|---|
| Minimum validator stake | 100 UM | Your validator needs at least this much delegated to it, self-delegation included, before it can be active. |
| Active set | 100 | Only the top 100 validators by voting power sign blocks and earn. Rank is recomputed every epoch. |
| Epoch | 34,560 blocks | About 2 days. Delegations, rank changes and your activation take effect at the next epoch boundary. |
| Signed-blocks window | 10,000 blocks | Uptime is judged over a sliding window of about 14 hours. |
| Missed-blocks maximum | 9,500 | Miss more than this within the window and you are jailed. In practice, an outage longer than about 13 hours. |
| Unbonding delay | 120,960 blocks | About 7 days for delegations to leave. Also the window in which past misbehaviour can still be punished. |
| Downtime penalty | 0.01% | Applied once when you are jailed for missing blocks. Small, but you stop earning until you re-enable the validator with a new definition upload. |
| Misbehaviour penalty | 10% | Double-signing slashes 10% of everything delegated to you and tombstones the validator. Never run the same consensus key on two machines. |
Budget for the stake itself, a small amount for transaction fees, and one funding-stream decision: Penumbra has no flat commission. Your validator definition declares one or more streams, each a recipient address and a rate in basis points, and the rest flows to delegators.
Install pd and CometBFT
5 minutesReleases come from Rotko's repository. The installer puts pd in ~/.cargo/bin; move it wherever your unit files expect.
# pd 2.0.8, prebuilt for x86_64 and arm64 Linux
curl --proto '=https' --tlsv1.2 -LsSf \
https://github.com/rotkonetworks/penumbra/releases/download/v2.0.8/pd-installer.sh | sh
pd --version# CometBFT 0.37.18 (the binary prints 0.37.16; that is a known upstream bug)
curl -LO https://github.com/cometbft/cometbft/releases/download/v0.37.18/cometbft_0.37.18_linux_amd64.tar.gz
tar -xzf cometbft_0.37.18_linux_amd64.tar.gz cometbft
sudo install -m 0755 cometbft /usr/local/bin/cometbftDo not run anything older than 0.37.18. It carries the fix for the critical January 2026 CometBFT advisory.
Join the network
1 minuteThis generates the node directory under ~/.penumbra/network_data/node0, including your node key and consensus key, and fetches genesis and peers from an existing node.
pd network join \
--moniker "your-validator-name" \
--external-address "YOUR.PUBLIC.IP:26656" \
https://penumbra.rotko.netThen create the two systemd units. The file limit line is not optional.
# /etc/systemd/system/penumbra.service
[Unit]
Description=Penumbra daemon
After=network-online.target
[Service]
User=penumbra
ExecStart=/usr/local/bin/pd start --home /home/penumbra/.penumbra/network_data/node0/pd
Restart=on-failure
LimitNOFILE=65536
[Install]
WantedBy=multi-user.target
# /etc/systemd/system/cometbft.service
[Unit]
Description=CometBFT
After=penumbra.service
Requires=penumbra.service
[Service]
User=penumbra
ExecStart=/usr/local/bin/cometbft start --home /home/penumbra/.penumbra/network_data/node0/cometbft
Restart=on-failure
LimitNOFILE=65536
[Install]
WantedBy=multi-user.targetDo not start them yet. Restore the snapshot first, or you will replay the chain from the last upgrade height, which takes days.
Restore the pruned snapshot
~1 hour, mostly downloadThe snapshot is a pd state store already pruned to a single version plus CometBFT's block history since the last upgrade. It contains no keys and no node identity. Your own priv_validator_state.json must survive the restore, so it is moved aside and back.
Preferred: torrent. The torrent is seeded continuously by Rotko and by everyone who restored before you, and it carries our HTTPS host as a web seed, so it never has fewer sources than the plain download. Any client works; the commands use aria2c because it is non-interactive.
cd ~/.penumbra/network_data/node0
curl -LO https://snapshot.rotko.net/penumbra-1/latest/manifest.json
curl -LO "https://snapshot.rotko.net/penumbra-1/latest/$(jq -r .torrent manifest.json)"
aria2c --seed-time=0 --dir=. "$(jq -r .torrent manifest.json)"
# the torrent's piece hashes verify the download; the sha256 below is a second, independent check
sha256sum -c <(jq -r '"\(.sha256) \(.file)"' manifest.json)Or plain HTTPS, resumable with curl -C -:
curl -C - -LO "https://snapshot.rotko.net/penumbra-1/latest/$(jq -r .file manifest.json)"
sha256sum -c <(jq -r '"\(.sha256) \(.file)"' manifest.json)Then swap it in, keeping your own signing state:
mv cometbft/data/priv_validator_state.json /tmp/pvs.json
rm -rf pd/rocksdb cometbft/data
lz4 -dc "$(jq -r .file manifest.json)" | tar -xf -
mkdir -p cometbft/data && mv /tmp/pvs.json cometbft/data/Leave your torrent client seeding afterwards if you can. That is how the next validator gets it quickly.
The manifest carries the snapshot height H and the pd root hash. That root hash is the app_hash in the header of block H+1, which any RPC will give you:
H=$(jq -r .height manifest.json)
curl -s "https://penumbra.rotko.net/block?height=$((H+1))" | jq -r .result.block.header.app_hash
jq -r .root_hash manifest.json
# the two lines must be identical (case-insensitive)Run and verify
minutes to catch upsudo chown -R penumbra:penumbra ~penumbra/.penumbra
sudo systemctl enable --now penumbra
sudo systemctl enable --now cometbft
journalctl -fu cometbftThe first CometBFT lines should read ABCI Handshake App Info height=H hash=<root hash> followed by Completed ABCI Handshake. Blocks then arrive from peers at a few hundred per minute until you reach the tip.
curl -s localhost:26657/status | jq '.result.sync_info | {latest_block_height, catching_up}'You are synced when catching_up is false. Nothing you do in the next step matters until then.
Become a validator
2 days to activationThe wallet that owns the validator can live on a different machine from the node, and for a production validator it should. The identity key derived from that wallet is permanent; you cannot rotate it later. Choose custody accordingly.
# wallet for the validator identity (soft-kms is fine for testing; use threshold custody in production)
pcli init soft-kms generate
pcli view address 0
# fund this address with at least 100 UM plus a little for fees
pcli view balance# build the definition from the node's consensus key
pcli validator definition template \
--tendermint-validator-keyfile ~/.penumbra/network_data/node0/cometbft/config/priv_validator_key.json \
--file validator.tomlEdit validator.toml: set enabled = true, fill name, website and description, and decide your funding streams. If pcli runs elsewhere, paste the value from the node's priv_validator_key.json into [consensus_key]. Then upload, find your identity, and self-delegate.
pcli validator definition upload --file validator.toml
pcli validator identity
pcli tx delegate 100penumbra --to penumbravalid1...
pcli query validator list --show-inactiveYour validator appears as inactive immediately and becomes active at the next epoch boundary if it ranks inside the top 100 by voting power. Every later change to the definition is the same upload with sequence_number incremented.
Two nodes with the same priv_validator_key.json will eventually double-sign. That is a 10% slash of all delegations and a permanent tombstone. Back the key up offline, never run it twice, and never restore a snapshot without keeping your own priv_validator_state.json.
Day two
Pruning your own node later
A node restored from this snapshot starts pruned. If you joined the older way, pd migrate prune in pd 2.0.8 takes the state store from about 350 GB to 30 GB in an hour. Both services are stopped for the duration. Coordinate with the other validators so that never more than a third of voting power is offline, and if you alone hold more than a third, do not prune. The full procedure is in the 2.0.8 release notes.
Upgrades
Consensus upgrades are announced on the repository. Point releases in the same series, such as 2.0.6 to 2.0.8, are drop-in binary swaps with no coordination. A release with a new APP_VERSION halts the chain at a governance-set height and every node runs pd migrate; that migration deletes CometBFT block history by design, which is why the archive is kept separately.
Monitoring
Watch two numbers: your node's latest_block_height against a public RPC, and the missed-blocks counter for your identity in pcli query validator uptime. Alert well before 9,500.
Help
Issues and questions go to github.com/rotkonetworks/penumbra. The public RPC is https://penumbra.rotko.net, which stays unpruned as the network's archive and relayer endpoint.
Snapshots
Taken weekly from Rotko's archive node with a ZFS freeze, pruned on a clone, verified by starting a node on the result and syncing it live before publishing. Every snapshot is published as a torrent with the HTTPS file as a web seed, and Rotko seeds it permanently; seeding health is on status.rotko.net. Restore with the commands in step 4.
| Date | Height | Get it | Size | pd root hash | sha256 |
|---|---|---|---|---|---|
| 2026-09-06 | 12563194 | magnet · .torrent · https infohash 8d5b6ea2aea97926a93650f72798a68789a0a101 |
83.9 GiB | d89a1cc83eccc2d52d778e934357a700ecfb728fc26191c2221bd81890085544 | 3cd41f8a402d0c0ca44eab88aebe854a86ea76f4feba71e4125334c7ee7eaebe |
Each snapshot lives at https://snapshot.rotko.net/penumbra-1/<height>/ with its manifest.json and .sha256 beside it, and penumbra-1/latest/ always points at the newest one, so the restore commands above never need editing. snapshots.rotko.net is an alias of the same host.