Skip to content

DHT & bootstrap peers

This page covers the server’s place in the Kademlia DHT, which libp2p peers use to find each other’s addresses, and how to connect it to other nodes with bootstrap peers.

Every server runs a Kademlia DHT in server mode: it answers other peers’ queries as well as making its own. This is fixed; there is no setting to change it.

Ricochet uses the DHT for peer routing only: finding the addresses of a peer ID. It never publishes or looks up provider records for content.

A peer enters the server’s routing table only while the server holds a direct connection to it that the server opened.

A routing table entry is a promise to query that peer on its own. An inbound connection from a client behind a NAT proves nothing about whether the server can reach it later; such a client would be queried, fail to answer, and drain the table. So:

  • Inbound connections never qualify.
  • Relayed connections never qualify, whichever side opened them.
  • Bootstrap peers are dialled at startup, and peers learned from lookups are dialled by the DHT, so the peers that belong in the table arrive over outbound connections anyway.
  • A peer that only ever dialled this server stays out until this server dials it.

This means most of your clients will never appear in the routing table. That is expected.

Bootstrap peers are the nodes the server connects to at startup to join the DHT. List them as full multiaddrs, ending in /p2p/<peer-id>:

/etc/ricochet/config.yaml
server:
bootstrap_peers:
- /ip4/198.51.100.7/udp/55223/udx/p2p/12D3KooW...
- /ip4/192.0.2.44/udp/55223/udx/p2p/12D3KooW...

There is no command-line flag for bootstrap peers; set them in the file. The default is none: a single server works without any, but it has no DHT neighbours until someone it dials joins.

The server runs only the UDX transport, so a bootstrap peer must be reachable over UDX. In practice that means other Ricochet servers you run. Public IPFS bootstrap nodes, which do not speak UDX, cannot be dialled.

The same list serves as the relay candidates for AutoRelay when that is on. See NAT traversal & relay.

At startup, for each bootstrap peer, the server logs connected to bootstrap peer or failed to connect to bootstrap peer with the peer ID and the error. An entry that does not parse is logged as invalid bootstrap peer or invalid bootstrap peer info and skipped.

On every maintenance tick (intervals.cleanup_min, 5 minutes by default), the server logs DHT status with:

  • routing_table_size and routing_table_peers: the peers in the routing table.
  • connected_peers: open connections, clients included.
  • peerstore_peers: peers the host knows addresses for.
Terminal window
grep 'DHT status' /var/log/ricochet/stdout.log | tail -n 1

A healthy server with bootstrap peers has a non-zero routing_table_size. For a detailed trace, start the server with --debug-dht, which turns the dht and dht/RtRefreshManager loggers to DEBUG. With DEBUG on, a peer refused from the table is logged as routing table: refusing peer without a direct outbound connection.

  • routing_table_size stays at 0: no bootstrap peers are configured, or none were reachable. Check the connected to bootstrap peer lines. Many connected clients and an empty table is normal for a server with no bootstrap peers.
  • failed to connect to bootstrap peer: the address is wrong, the peer is down, or its UDP port is blocked. Check that the /p2p/ peer ID matches the peer’s startup line.
  • invalid bootstrap peer info: the multiaddr has no /p2p/<peer-id> part.