How to Configure DNS Resolution Settings in the iroh Endpoint Builder
To configure DNS resolution settings in iroh, call Builder::dns_resolver() on the endpoint builder and pass a custom DnsResolver instance created via DnsResolver::builder() or the with_nameserver() helper.
The iroh networking library (n0-computer/iroh) exposes DNS configuration through its endpoint builder pattern defined in iroh/src/endpoint.rs. While the default configuration automatically uses the host operating system's DNS settings, you can inject a custom resolver to specify nameservers, enable DNS-over-HTTPS (DoH), or share resolution caches across multiple endpoints.
Understanding the DNS Resolution Components
The DNS configuration API spans two primary modules. The Builder struct in iroh/src/endpoint.rs (lines 74-87) holds an optional dns_resolver field and exposes the dns_resolver() setter method. The actual resolution logic lives in iroh-dns/src/dns.rs, where the DnsResolver type wraps a hickory-dns resolver and provides the builder() entry point (lines 349-351) for fine-tuned configuration.
The Role of DnsResolver
DnsResolver is an Arc-wrapped handle to an asynchronous DNS client. When you customize DNS resolution settings, you construct this resolver first, then inject it into the endpoint builder before calling bind(). The resolver is used for all hostname lookups, including relay hostnames and PKARR address resolutions.
Using the Default System DNS Resolver
If you do not explicitly call dns_resolver(), the endpoint builder automatically creates a default resolver that reads the system's DNS configuration from /etc/resolv.conf (or the platform-specific equivalent).
use iroh::endpoint::{Builder, Preset};
let endpoint = Builder::new(Preset::default())
.bind()
.await?;
This default requires no additional code and follows the host system's resolver behavior.
Configuring a Single Custom Nameserver
To route DNS queries through a specific UDP nameserver, use the DnsResolver::with_nameserver() convenience helper implemented in iroh-dns/src/dns.rs (lines 342-347). This creates a resolver configured for a single upstream server.
use iroh::{endpoint::Builder, dns::DnsResolver};
use std::net::SocketAddr;
let nameserver: SocketAddr = "1.1.1.1:53".parse().unwrap();
let dns_resolver = DnsResolver::with_nameserver(nameserver);
let endpoint = Builder::new(Preset::default())
.dns_resolver(dns_resolver)
.bind()
.await?;
Advanced DNS Resolution Settings (Multiple Nameservers and DoH)
For production deployments requiring redundant nameservers or encrypted DNS, use the full DnsResolver::builder() API exposed in iroh-dns/src/dns.rs (lines 340-368). This builder allows you to specify multiple nameservers with different protocols—including UDP, TCP, and TLS (for DNS-over-HTTPS).
use iroh::dns::{DnsResolver, DnsProtocol, Builder as DnsBuilder};
use std::net::SocketAddr;
let ns1: SocketAddr = "8.8.8.8:53".parse().unwrap();
let ns2: SocketAddr = "8.8.4.4:53".parse().unwrap();
let doh_addr: SocketAddr = "1.1.1.1:443".parse().unwrap();
let dns_resolver = DnsBuilder::default()
.with_nameserver(ns1, DnsProtocol::Udp)
.with_nameserver(ns2, DnsProtocol::Udp)
.with_nameserver(doh_addr, DnsProtocol::Tls)
.build();
let endpoint = Builder::new(Preset::default())
.dns_resolver(dns_resolver)
.bind()
.await?;
The DnsProtocol enum (defined in iroh-dns/src/attrs.rs) specifies whether to use Udp, Tcp, or Tls for each upstream server. You can also configure custom TLS client configurations via the builder's tls_client_config() method.
Sharing DNS Resolvers Across Endpoints
Because DnsResolver is wrapped in an Arc internally, you can share a single resolver instance across multiple endpoints to reduce socket overhead and maintain a consistent DNS cache.
use iroh::{endpoint::Builder, dns::DnsResolver};
use std::sync::Arc;
let resolver = Arc::new(DnsResolver::with_nameserver("9.9.9.9:53".parse().unwrap()));
let ep1 = Builder::new(Preset::default())
.dns_resolver((*resolver).clone())
.bind()
.await?;
let ep2 = Builder::new(Preset::default())
.dns_resolver((*resolver).clone())
.bind()
.await?;
Sharing the resolver ensures that DNS cache entries and connection pools are reused between endpoints according to the n0-computer/iroh source code implementation.
Summary
- Use
Builder::dns_resolver()iniroh/src/endpoint.rsto inject a custom resolver into the endpoint builder. - Create resolvers via
DnsResolver::builder()(lines 349-351 iniroh-dns/src/dns.rs) for multi-server or TLS configurations. - Use
with_nameserver()(lines 342-347) for quick single-nameserver setups. - Reference
DnsProtocoliniroh-dns/src/attrs.rsto specify Udp, Tcp, or Tls transport protocols. - Wrap resolvers in
Arcto share them efficiently across multiple endpoint instances.
Frequently Asked Questions
How do I change the DNS server for an iroh endpoint?
Call Builder::dns_resolver() and pass a DnsResolver created with DnsResolver::with_nameserver() or the full DnsResolver::builder() API. This overrides the default system resolver with your specified upstream server.
Does iroh support DNS-over-HTTPS?
Yes. When building a custom DnsResolver, use DnsProtocol::Tls with the with_nameserver() method to configure DNS-over-HTTPS (DoH) endpoints. You may also need to configure TLS settings via the builder's tls_client_config() method.
Can I share a DNS resolver between multiple iroh endpoints?
Yes. DnsResolver is designed to be cloneable and internally uses Arc for reference counting. Create the resolver once, then clone it (or dereference from an Arc) to pass into multiple Builder::dns_resolver() calls before binding each endpoint.
Where is the default DNS resolver configured in iroh?
The default resolver logic resides in iroh/src/endpoint.rs within the Builder implementation (lines 74-87). When no custom resolver is provided, the builder automatically instantiates a DnsResolver that reads the system's DNS configuration using platform-specific defaults.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →