Skip to content

Networking

Peerborne uses libp2p for all peer-to-peer networking. libp2p is a modular networking stack that handles transport, stream multiplexing, connection encryption, peer discovery, NAT traversal, and pubsub messaging — all in one framework.

Peerborne supports these transport protocols. The actual set used depends on the runtime (browser vs. Node.js) and network topology:

TransportRuntimePurpose
WebSocketBrowser, Node.jsReliable bidirectional stream. Used for relay and bootstrap connections.
WebRTCBrowserBrowser-to-browser direct connections (STUN improves NAT traversal; TURN or Circuit Relay may be needed for restrictive NATs).
WebRTC DirectNode.jsNode-to-Node direct connections.
WebTransportBrowser (Chrome 97+)Modern, low-latency QUIC-based transport.
TCPNode.jsTraditional stream transport for Node.js peers.
import { defaultConfig, defaultBootstrapConfig } from '@peerborne/core';
const bootstrapPeers = [
'/dns4/relay.example.com/tcp/443/wss/p2p/12D3KooW...',
];
const config = defaultConfig(defaultBootstrapConfig(bootstrapPeers));
// Pass config to Peerborne.initialize()
await swarm.initialize(config);

In practice, browser peers typically use WebSocket to reach a relay, and may upgrade to WebRTC or WebTransport for direct peer connections when NAT traversal succeeds.

Document updates are announced and delivered via GossipSub — a pubsub protocol built on libp2p. Each document has a corresponding pubsub topic derived from its document ID:

// Document /todo-list → topic: /peerborne/document/v3/todo-list
// Changes published to this topic reach all subscribed peers.

Relays admit the current document namespace by default. A custom pubsubDocumentPrefix requires a matching slash-terminated namespace in every relay’s TOPIC_ALLOWLIST. With an empty prefix, allow each concrete document topic or explicitly select unrestricted * mode. All peers must use the same runtime and topic prefix.

Topic names are public routing labels, not authentication, authorization, or wire validation. Application URLs such as /document/:id are unrelated and do not change.

GossipSub is best-effort:

  • Messages are relayed through the mesh, not stored
  • Peers that join late may miss announcements
  • There is no message persistence, acknowledgment, or guaranteed delivery
  • Initial load and catch-up use point-to-point bitswap / HTTP fetch, not GossipSub

Peerborne peers find each other through several mechanisms:

A static list of well-known peers that new nodes connect to first:

bootstrap: [
'/dns4/bootstrap.peerborne.dev/tcp/443/wss/p2p/12D3KooW...',
'/ip4/192.168.1.100/tcp/4002/p2p/12D3KooW...',
]

Bootstrap nodes introduce the new peer to the network. They do not store or relay document data.

Once connected, nodes participate in a distributed hash table (Kademlia) for peer and content routing. The DHT maps peer IDs to multiaddrs and CIDs to providers.

AutoNAT determines whether a peer is reachable from the public internet. If a peer is behind NAT, it cannot accept incoming connections and must use a relay.

Browsers and most home/office networks are behind NAT, which prevents direct incoming connections. Peerborne uses several mechanisms to work around this:

A relay node bridges traffic between two peers behind NAT:

Two NAT-isolated Chromium peers loading encrypted document history through Circuit Relay after the test gives peer B peer A's relayed circuit address; an optional direct path is shown as unverified.
The cross-NAT path is verified through Circuit Relay; a direct path remains unverified.
View diagram at full sizeFit diagram to page

Evidence boundary: The solid relay path represents the narrow CI-backed result: one user identity runs in two NAT-isolated Chromium processes, the document key is restored to the second device out of band, and that device loads existing encrypted document history through Circuit Relay. The test reads peer A’s /p2p-circuit/ address and has peer B dial it explicitly; it does not establish a separate bootstrap-discovery proof edge. The topology has app servers and a relay but no application database service. It does not demonstrate live post-load synchronization, invitation delivery, direct WebRTC/DCUtR, relay failover, or production deployment behavior.

The relay forwards encrypted packets. It sees metadata (peer IDs, timing, data volume) but cannot decrypt document content.

DCUtR (Direct Connection Upgrade through Relay)

Section titled “DCUtR (Direct Connection Upgrade through Relay)”

After an initial relayed connection, peers attempt to establish a direct WebRTC connection using DCUtR. The relay facilitates the hole-punching handshake; if successful, peers communicate directly, reducing relay load and latency.

  • STUN servers help peers discover their public IP and port for WebRTC hole-punching.
  • TURN servers relay media when direct WebRTC connections are impossible (e.g., symmetric NAT). TURN is more expensive than Circuit Relay but handles a broader range of NAT types.

Relays are the most important infrastructure component in a Peerborne deployment, and their trust properties matter:

What relays can see:

  • Peer IDs and multiaddrs of connecting peers
  • Connection timing and duration
  • Data volume and message frequency
  • PubSub topic IDs (derived from document IDs)

What relays cannot see:

  • Document content (encrypted with the document key; AES-GCM by default)
  • Signing keys or document keys
  • ACL entries or identity information (embedded in encrypted blocks)

What relays can do:

  • Drop, delay, or reorder messages
  • Terminate transport connections and forward relayed traffic
  • Censor specific peers or topics
  • Log metadata about who communicates with whom

What relays cannot do:

  • Decrypt document content without the document key
  • Forge application-level signatures without the signing private key
  • Authenticate as another peer at the libp2p level (Noise provides end-to-end peer authentication)
  • Modify encrypted blocks (detected via CID integrity check)

A relay that loses its identity file restarts with a new peer ID and breaks clients pinned to the old identity. The standard relay image persists an app-managed key on its /shared volume; hosted deployments must likewise mount durable storage at RELAY_IDENTITY_KEY_PATH. DNS (/dns4/...) changes address resolution but /p2p/<peerID> still pins the relay identity. Never share one private identity between concurrently running relays.

  • Relay identity requires durable storage. Restart preserves the peer ID only while the configured identity file survives. Losing it requires clients to learn a new peer ID.
  • No relay meshing. Each relay operates independently. There is no relay-to-relay routing.
  • Topic allowlists are not Circuit Relay policy. TOPIC_ALLOWLIST controls only which GossipSub topics the relay node auto-subscribes to. It does not inspect or restrict opaque, Noise-encrypted Circuit Relay streams, authenticate publishers, or authorize documents.
  • Readiness is local evidence. /readyz confirms local startup and seed subscriptions, not a remote reservation or end-to-end convergence.
  • No durable storage on relay. The relay does not store messages. If a subscriber is offline, it misses messages.

Verified in CI:

  • WebSocket transport through Circuit Relay in Docker-backed NAT tests
  • Cross-NAT encrypted document retrieval (real Peerborne nodes behind NAT)
  • Basic peer discovery (bootstrap connection) in integration tests
  • GossipSub message delivery in NAT topology

Not verified:

  • WebRTC direct connection upgrade (DCUtR)
  • WebTransport transport
  • Relay failover (kill one relay, verify peers reconnect through another)
  • Live post-load convergence under network partition
  • AutoNAT detection and relay fallback
  • DHT content/provider routing at scale