How to Configure iroh Node Settings Using the Builder API

You configure iroh node settings through the chainable Builder API in iroh::endpoint::Builder, applying methods like relay_mode(), alpns(), and secret_key() before calling bind() to instantiate the Endpoint.

The n0-computer/iroh library exposes all node configuration options through a type-safe Builder pattern defined in iroh/src/endpoint.rs. This design allows you to customize cryptographic identities, transport layers, relay connectivity, and application protocols before the node opens sockets or establishes TLS contexts.

Understanding the Builder Pattern Architecture

In iroh/src/endpoint.rs, the Builder struct serves as the central configuration interface. You initialize it through Builder::empty() for a blank slate or Builder::new(preset) to start with sensible defaults.

All configuration methods return Self, enabling fluent chaining:

let endpoint = iroh::endpoint::Builder::empty()
    .secret_key(my_key)
    .alpns(vec![b"my-protocol".to_vec()])
    .bind()
    .await?;

The node only materializes when you invoke bind(), which consumes the Builder and returns a ready-to-use Endpoint. Until that point, you are merely assembling configuration state.

Essential Node Configuration Parameters

Node Identity and Cryptography

The secret_key() method sets the cryptographic identity of your node. If omitted, the builder generates a fresh SecretKey automatically via Default::default(). You must also supply a crypto provider via the ecosystem or explicitly, or bind() will return BindError::InvalidCryptoProvider.

use iroh::SecretKey;

let secret = SecretKey::generate();
builder.secret_key(secret);

For debugging TLS handshakes, enable keylog(true) to generate key-log files compatible with Wireshark.

Application Protocol Configuration

Incoming connections require at least one ALPN (Application-Layer Protocol Negotiation) identifier. The alpns() method accepts a Vec<Vec<u8>>:

builder.alpns(vec![
    b"my-app/1.0".to_vec(),
    b"my-app/2.0".to_vec(),
]);

Without ALPNs configured, the node cannot accept incoming connections, though it can still dial outbound.

Relay and Connectivity Settings

Relay configuration determines how your node discovers and communicates with peers through NAT traversal. The relay_mode() method accepts variants from RelayMode:

  • RelayMode::Disabled — Default in Builder::empty(); no relay assistance
  • RelayMode::Default — Uses production relay infrastructure defined in iroh/src/defaults.rs
  • RelayMode::Custom — Specify your own relay URLs
// Production relays
builder.relay_mode(iroh::RelayMode::Default);

// Custom private relay (line 165‑68 in endpoint.rs)
let custom = vec![iroh::RelayUrl::from_str("https://relay.example.com")?];
builder.relay_mode(iroh::RelayMode::Custom(custom.into()));

For NAT traversal, the portmapper_config() method accepts PortmapperConfig to control STUN/TURN behavior, while net_report_config() configures periodic network diagnostics.

Transport Layer Customization

By default, the builder adds IPv4 and IPv6 transports automatically. To customize this:

use iroh::transport::QuicConfig;

builder
    .clear_ip_transports()  // Removes auto-added IPv4/IPv6 (line 503)
    .add_custom_transport(QuicConfig::default().into()); // Line 813

This pattern allows injection of custom transport implementations alongside or replacing the standard QUIC configuration.

Security and TLS Configuration

When connecting to private relays with self-signed certificates, use ca_tls_config() to customize trust anchors:

use iroh::tls::CaTlsConfig;

// Development only: skip verification (line 713)
builder.ca_tls_config(CaTlsConfig::insecure_skip_verify());

For production, supply proper root anchors via CaTlsConfig::from_pem() or system defaults. The max_tls_tickets() parameter controls TLS session resumption limits, defaulting to DEFAULT_MAX_TLS_TICKETS from defaults.rs.

Address Discovery Services

To enable DNS-based peer resolution, attach an address lookup service:

use iroh::address_lookup::DnsAddressLookupBuilder;

builder.address_lookup(DnsAddressLookupBuilder::default());

This integrates with iroh/src/address_lookup.rs to resolve EndpointId values to network addresses dynamically.

Practical Configuration Examples

Minimal Node with Production Relays

This example uses the N0 preset from iroh::endpoint::presets, which bundles sensible defaults:

use iroh::{Endpoint, endpoint::presets};

#[tokio::main]
async fn main() -> iroh::Result<()> {
    let ep = Endpoint::builder(presets::N0)
        .alpns(vec![b"my-app".to_vec()])
        .relay_mode(iroh::RelayMode::Default)
        .bind()
        .await?;

    println!("Node ID: {}", ep.id());
    Ok(())
}

Source: Endpoint::builder → presets::N0 (see presets module in iroh/src/endpoint.rs).

Custom Relay with Self-Signed TLS

For private infrastructure requiring insecure TLS verification:

use iroh::{Endpoint, RelayMode, RelayUrl, tls::CaTlsConfig};
use std::str::FromStr;

#[tokio::main]
async fn main() -> iroh::Result<()> {
    let relay = RelayUrl::from_str("https://my.private.relay:443")?;
    
    let ep = Endpoint::builder(iroh::endpoint::presets::N0)
        .relay_mode(RelayMode::Custom(vec![relay].into()))
        .ca_tls_config(CaTlsConfig::insecure_skip_verify())
        .alpns(vec![b"demo".to_vec()])
        .bind()
        .await?;

    println!("Running with custom relay, node ID {}", ep.id());
    Ok(())
}

Source: RelayMode::Custom (line 165‑68) and ca_tls_config (line 713) in iroh/src/endpoint.rs.

DNS Address Lookup Integration

Enable resolution of human-readable addresses to EndpointId values:

use iroh::{Endpoint, address_lookup::DnsAddressLookupBuilder};

#[tokio::main]
async fn main() -> iroh::Result<()> {
    let ep = Endpoint::builder(iroh::endpoint::presets::N0)
        .alpns(vec![b"my-proto".to_vec()])
        .address_lookup(DnsAddressLookupBuilder::default())
        .bind()
        .await?;

    // Now connect using only the remote EndpointId
    // let conn = ep.connect(remote_id, b"my-proto").await?;
    Ok(())
}

Source: Builder::address_lookup (line 605) and DnsAddressLookupBuilder in iroh/src/address_lookup.rs.

Isolated QUIC Transport Configuration

Control exactly which network transports the node utilizes:

use iroh::{Endpoint, transport::QuicConfig};

#[tokio::main]
async fn main() -> iroh::Result<()> {
    let ep = Endpoint::builder(iroh::endpoint::presets::N0)
        .clear_ip_transports()
        .add_custom_transport(QuicConfig::default().into())
        .bind()
        .await?;
    
    Ok(())
}

Source: Builder::clear_ip_transports (line 503) and add_custom_transport (line 813) in iroh/src/endpoint.rs.

Key Source Files for Configuration Reference

File Purpose Location
iroh/src/endpoint.rs Core Builder type, all configuration methods, bind() logic endpoint.rs
iroh/src/defaults.rs Default relay hostnames, ports, and DEFAULT_MAX_TLS_TICKETS defaults.rs
iroh/src/address_lookup.rs DNS and PKARR lookup service traits and builders address_lookup.rs
iroh/src/tls.rs CaTlsConfig, crypto provider setup, and TLS context creation tls.rs
iroh/src/portmapper.rs NAT traversal configuration and STUN/TURN behavior portmapper.rs

These files collectively define the complete configuration surface for iroh nodes according to the n0-computer/iroh source code.

Summary

  • Use the Builder API: All configuration happens through iroh::endpoint::Builder methods chained before bind().
  • Set ALPNs: Required for accepting incoming connections via alpns().
  • Choose Relay Mode: Defaults to disabled; use relay_mode(RelayMode::Default) for production relays defined in defaults.rs.
  • Configure TLS: Supply ca_tls_config() for custom trust anchors or development overrides.
  • Customize Transports: Use clear_ip_transports() and add_custom_transport() to override default QUIC sockets.
  • Enable Discovery: Attach address_lookup services to resolve peers via DNS or PKARR.

Frequently Asked Questions

What is the default relay mode for iroh nodes?

By default, Builder::empty() initializes nodes with RelayMode::Disabled, meaning no relay servers are used for NAT traversal. You must explicitly call relay_mode(iroh::RelayMode::Default) to use the production relay infrastructure defined in iroh/src/defaults.rs.

How do I configure iroh to accept incoming connections?

You must configure at least one ALPN protocol using the alpns() method on the builder. Without ALPN identifiers, the node will reject incoming connection attempts even if bound successfully. Example: builder.alpns(vec![b"my-protocol".to_vec()]).

Can I use custom TLS certificates with iroh relays?

Yes. Use builder.ca_tls_config(CaTlsConfig::from_pem(...)) to supply custom root certificates for validating private relay servers. For development scenarios only, CaTlsConfig::insecure_skip_verify() disables certificate verification entirely, as implemented in iroh/src/tls.rs.

Where are the default relay URLs defined in the iroh source code?

Default relay hostnames and ports for production and staging environments are defined in iroh/src/defaults.rs. The N0 preset references these defaults automatically when you initialize the builder with Endpoint::builder(presets::N0).

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 →