Private Swarms (PSK)
A private swarm uses a Pre-Shared Key (PSK) to create a fully isolated libp2p network. Nodes without the correct key are rejected at the connection level — they can't even see which peers are in the swarm.
1. Generate a swarm key
Generate a 32-byte random PSK on any machine (you only do this once per swarm):
$ tubo keygen swarm --out swarm.key ✓ Swarm key written to swarm.key $ chmod 600 swarm.key $ cat swarm.key
The file uses the standard libp2p pnet format:
/key/swarm/psk/1.0.0/ /base16/ <64 hex characters>
swarm.key can join your private network.
Never commit it to version control.
2. Distribute the key
Copy swarm.key to every machine that should be part of the private swarm
(relay, service hosts, client hosts). Use a secure channel — SCP, age encryption, or a
secrets manager.
3. Start the relay
On the machine with a public IP:
# Get the relay's PeerID (so other nodes can address it) $ tubo id from-seed my-relay-seed $ tubo relay \ --swarm-key ./swarm.key \ --public-addr /ip4/1.2.3.4/tcp/4001 \ -d
Note the printed relay multiaddress — it looks like:
/ip4/1.2.3.4/tcp/4001/p2p/12D3KooWExample...
4. Join from service and client hosts
# On each host that needs to join the private swarm $ tubo join overlay/manual \ --relay /ip4/1.2.3.4/tcp/4001/p2p/12D3KooWExample... \ --swarm-key ./swarm.key ✓ Joined private swarm relay /ip4/1.2.3.4/tcp/4001/p2p/12D3KooWExample...
5. Create a cluster (recommended)
On the service host, create a cluster and namespace. This adds a cryptographic trust root on top of the PSK transport isolation:
$ tubo create cluster/myteam $ tubo create namespace/production $ tubo use cluster/myteam $ tubo use namespace/production
6. Publish a service
$ tubo attach myapi --port 8080 -d
7. Invite a client and connect
# On the authority host: create a member invite $ tubo share cluster/myteam --role member ✓ Invite token: tubo join cluster/myteam --token eyJ... # On the client host: join and connect $ tubo join overlay/manual --relay ... --swarm-key ./swarm.key $ tubo join cluster/myteam --token eyJ... $ tubo get services NAME ACCESS myapi namespace_members $ tubo connect myapi --local 127.0.0.1:9000
PeerID allowlist
For additional lockdown, you can restrict which PeerIDs are allowed to connect to a node, regardless of swarm key:
$ export LIBP2P_ALLOWED_PEERS=12D3KooWAlice...,12D3KooWBob...
Connections from any peer not in this list will be gated at the transport level. This is especially useful on relay nodes to prevent abuse.
Using environment variables instead of a file
In containerised environments you can pass the swarm key as a base64-encoded env var:
$ export LIBP2P_PRIVATE_NETWORK_KEY_B64=$(base64 -w0 swarm.key)