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() in iroh/src/endpoint.rs to inject a custom resolver into the endpoint builder.
  • Create resolvers via DnsResolver::builder() (lines 349-351 in iroh-dns/src/dns.rs) for multi-server or TLS configurations.
  • Use with_nameserver() (lines 342-347) for quick single-nameserver setups.
  • Reference DnsProtocol in iroh-dns/src/attrs.rs to specify Udp, Tcp, or Tls transport protocols.
  • Wrap resolvers in Arc to 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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →