Bootstrap/relay node for peerkit networks. It provides a stable, publicly reachable circuit-relay-v2 server so peers behind NAT can be discovered and connected. Built for the peerkit showcase app and Wind Tunnel test runs (see holochain/peerkit#5).
Note: The network-access-bytes derivation scheme (
src/network-access.ts) is a stub. Replace it with the real scheme from peerkitSPECIFICATIONS.mdbefore production use.
The relay is built with PeerkitRelayBuilder from @peerkit/peerkit, which
wraps the libp2p relay transport. A relay handles the access and agents
protocols (no message protocol) and acts as a circuit-relay-v2 server. Every
inbound connection must pass the /peerkit/access/v1 handshake before anything
else.
On the agents protocol the builder cbor-decodes each inbound agent-info
payload, verifies its Ed25519 signature, and stores the verified records in an
in-memory MemoryAgentStore (from @peerkit/agent-store). When a new peer
connects, the relay replays the full store to it. Records are evicted purely by
each record's own expiresAt; the relay imposes no TTL or entry cap and does
not drop records when a peer disconnects.
On startup the relay emits a relay ready JSON log line containing its
current listenAddrs and peerId, read from the container logs
(journalctl -u peerkit-relay) to publish the bootstrap multiaddr (see
Discovery).
- Node.js
>=22
npm cinpm run buildPEERKIT_NETWORK_SECRET=<shared-secret> npm startAll options can be supplied as CLI flags or environment variables. CLI flags take precedence over environment variables, which take precedence over defaults.
| Flag | Env var | Default | Description |
|---|---|---|---|
--id |
PEERKIT_RELAY_ID |
peerkit-bootstrap-relay |
Log / metrics identifier |
--listen-addr (repeatable) |
PEERKIT_RELAY_LISTEN_ADDRS |
/ip4/0.0.0.0/tcp/4001,/ip6/::/tcp/4001 |
libp2p listen multiaddrs; env value is comma-separated |
--network-secret |
PEERKIT_NETWORK_SECRET |
(required; prefer env var) | Shared secret for network-access handshake |
--public-host |
PEERKIT_PUBLIC_HOST |
(optional) | Publicly reachable hostname advertised in announced multiaddrs |
--certificate-file |
PEERKIT_RELAY_CERTIFICATE_FILE |
(optional) | Path to a relay certificate JSON file (see Deployment) |
--log-level |
PEERKIT_LOG_LEVEL |
info |
Log level (trace, debug, info, warn, error) |
--otel-otlp-endpoint |
PEERKIT_OTEL_OTLP_ENDPOINT |
(optional; presence enables OTLP export) | OTLP gRPC/HTTP endpoint for OpenTelemetry metrics |
--otel-export-interval-ms |
PEERKIT_OTEL_EXPORT_INTERVAL_MS |
60000 |
OTLP export interval in milliseconds |
--otel-headers |
PEERKIT_OTEL_HEADERS |
(optional) | OTLP request headers as comma-separated k=v pairs |
Clients are configured with the relay's multiaddr out-of-band as a well-known
bootstrap address, typically a WebRTC-Direct multiaddr
/ip4/<ip>/udp/<port>/webrtc-direct/certhash/<hash>/p2p/<peer-id>.
On startup the relay logs a relay ready JSON line containing its current
listenAddrs and peerId. Read it from the container logs
(journalctl -u peerkit-relay) to publish or refresh the bootstrap address
(see Deployment).
Note: Supplying a persisted relay certificate (see Relay certificate) keeps the WebRTC-Direct certhash — and therefore the dialable multiaddr — stable across restarts and droplet replacements. Without one the certificate is ephemeral and the certhash changes on every restart.
The relay is deployed as a DigitalOcean droplet provisioned by
infra/cloud-init.yaml and driven by the manual
Deploy relay GitHub Actions workflow. Each
run builds the relay from a chosen git ref on a fresh droplet, delivers the
network secret and the persisted relay certificate over SSH, and reassigns a
DigitalOcean Reserved IP so the announced multiaddr stays stable across
replacements. See infra/README.md for the full runbook.
@peerkit/relay does not expose an HTTP endpoint, so readiness is read from
the container logs (journalctl -u peerkit-relay) rather than HTTP; the
relay ready line carries the announced multiaddr.
@peerkit/relay generates an ephemeral WebRTC-Direct certificate on every
start, so the certhash — and the dialable multiaddr — change on each restart.
Supplying a persisted certificate keeps them stable. Generate one once and
store it as the RELAY_CERT_JSON GitHub secret (the --silent flag keeps
npm's banner out of the JSON):
npm run --silent gen-cert > relay-cert.jsonThe certificate is valid for 5 years; re-mint it and update the secret before it expires.
On startup the relay logs a relay ready JSON line with its listenAddrs and
peerId. Read it from the droplet and record the announced multiaddr for
client bootstrap configuration:
journalctl -u peerkit-relaynpm run lint # eslint
npm run fmt # prettier --write
npm run fmt:check # prettier --check
npm test # vitesthusky + lint-staged run prettier and eslint on staged files at commit
time (installed via the prepare script on npm install).
CAL-1.0 — same as peerkit.