Table of Contents
Relays and discovery
Reach a peer you only know by public key — relay modes, DNS and pkarr lookup, mDNS, and self-hosting.
A direct IP address only works when both peers can route to each other. This page covers the two mechanisms that make an endpoint ID enough: relays (a path that always works) and discovery (turning an ID into an address).
Relay modes
Relays are configured with iroh.WithRelayMode and the relay package:
| Mode | Use when |
|---|---|
relay.ModeDefault() |
you want the number0 production relays |
relay.ModeStaging() |
you are testing against number0 staging |
relay.ModeCustomURLs(urls...) |
you run your own relays |
relay.ModeCustom(m) |
you need per-relay relay.Config (QUIC settings) |
relay.ModeDisabled() |
direct paths only; no relay fallback |
ep, err := iroh.Bind(ctx, iroh.WithRelayMode(relay.ModeDefault()))
if err != nil {
return err
}
if err := ep.Online(ctx); err != nil { // wait for a home relay connection
return err
}
fmt.Println(ep.Addr().RelayURLs())
Endpoint.Online blocks until a home relay connection exists. Until then your
Addr() may have no relay URL in it, so a ticket minted too early is not
reachable. Endpoint.HomeRelayStatus() observes the connection, and
InsertRelay / RemoveRelay adjust the map at runtime.
When several relays are configured, relay.RankByLatency with a
relay.Prober (relay.HTTPConnectProber) measures them; with WithNetReport()
the endpoint’s own NetReport().PreferredRelay reports the relay with the best
recent latency, chosen with hysteresis.
The relay is a fallback path, not the destination — see How go-iroh works for the upgrade to a direct path.
Discovery: from ID to address
Discovery is optional. If you already have an address — from a ticket, a config file, or a previous session — you can dial without any lookup service.
The abstraction is iroh.AddressLookupServices: a registry with publisher and
resolver halves, registered on an endpoint with iroh.WithAddressLookup. It
“publishes the endpoint’s own info to every publisher and merges resolver
streams” (its doc comment). Resolution is an iterator of Item values, each
tagged with the provenance of the service that produced it.
Shipped services:
| Service | Constructors | Provenance |
|---|---|---|
| DNS | NewDNSAddressLookup(origin, resolver), N0DNSAddressLookup(resolver) |
DNSProvenance |
| pkarr | NewPkarrPublisher / NewPkarrResolver, N0PkarrPublisher / N0PkarrResolver |
PkarrProvenance |
| Static | StaticLookupFromAddrs(addrs...) |
static_lookup |
| Memory | NewMemoryLookup() + AddEndpointAddr |
memory_lookup |
| mDNS | mdns.New(id, opts...) in iroh/mdns |
local link |
The N0… constructors use the number0 production endpoints:
iroh.N0DNSPkarrRelayProd is https://dns.iroh.link/pkarr, with
N0DNSPkarrRelayStaging alongside it, and the DNS lookup uses
dns.N0DNSEndpointOriginProd.
A typical internet-facing setup publishes with pkarr and resolves with both pkarr and DNS:
publisher, err := iroh.N0PkarrPublisher(sk, nil)
if err != nil {
return err
}
resolver, err := iroh.N0PkarrResolver(nil)
if err != nil {
return err
}
var services iroh.AddressLookupServices
services.AddPublisher(publisher)
services.AddResolver(resolver)
services.AddResolver(iroh.N0DNSAddressLookup(nil))
ep, err := iroh.Bind(ctx,
iroh.WithSecretKey(sk),
iroh.WithAddressLookup(&services),
)
Publishing is what makes a bare netaddr.NewEndpointAddr(id) dialable by
someone who has only your ID.
pkarr records are signed with your endpoint’s secret key, so a pkarr relay
distributes them without being trusted to be honest about their contents. The
underlying codec is the pkarr package; the DNS/TXT encoding is in dns.
For LAN-only peers, iroh/mdns implements both halves over multicast DNS
(default service name irohv1) and is not built for js.
Self-hosting
The core module ships both servers, so you do not need number0 infrastructure:
cmd/iroh-relay— a self-hostable relay server; therelayserverpackage is the embeddable form.cmd/iroh-dns-server— the pkarr HTTP and DNS surfaces; thednsserverpackage is the embeddable form.
Point endpoints at them with relay.ModeCustomURLs(...) and
NewPkarrPublisher / NewPkarrResolver / NewDNSAddressLookup with your own
URL and origin. See Commands for flags and a health check.
Next steps
- Commands — running your own relay and DNS server.
- Endpoints and connections — dialing once the address resolves.
- Troubleshooting — “no address”, “no relay”, and dials that never connect.