# How to Configure iroh Node Settings Using the Builder API

> Configure iroh node settings with the Builder API. Easily customize relay mode, ALPNs, and secret keys before binding your endpoint for efficient P2P networking.

- Repository: [number zero/iroh](https://github.com/n0-computer/iroh)
- Tags: how-to-guide
- Published: 2026-07-04

---

**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`](https://github.com/n0-computer/iroh/blob/main/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`](https://github.com/n0-computer/iroh/blob/main/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:

```rust
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`.

```rust
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>>`:

```rust
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`](https://github.com/n0-computer/iroh/blob/main/iroh/src/defaults.rs)
- `RelayMode::Custom` — Specify your own relay URLs

```rust
// 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:

```rust
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:

```rust
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`](https://github.com/n0-computer/iroh/blob/main/defaults.rs).

### Address Discovery Services

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

```rust
use iroh::address_lookup::DnsAddressLookupBuilder;

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

```

This integrates with [`iroh/src/address_lookup.rs`](https://github.com/n0-computer/iroh/blob/main/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:

```rust
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`](https://github.com/n0-computer/iroh/blob/main/iroh/src/endpoint.rs)).

### Custom Relay with Self-Signed TLS

For private infrastructure requiring insecure TLS verification:

```rust
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`](https://github.com/n0-computer/iroh/blob/main/iroh/src/endpoint.rs).

### DNS Address Lookup Integration

Enable resolution of human-readable addresses to `EndpointId` values:

```rust
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`](https://github.com/n0-computer/iroh/blob/main/iroh/src/address_lookup.rs).

### Isolated QUIC Transport Configuration

Control exactly which network transports the node utilizes:

```rust
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`](https://github.com/n0-computer/iroh/blob/main/iroh/src/endpoint.rs).

## Key Source Files for Configuration Reference

| File | Purpose | Location |
|------|---------|----------|
| [`iroh/src/endpoint.rs`](https://github.com/n0-computer/iroh/blob/main/iroh/src/endpoint.rs) | Core `Builder` type, all configuration methods, `bind()` logic | [endpoint.rs](https://github.com/n0-computer/iroh/blob/main/iroh/src/endpoint.rs) |
| [`iroh/src/defaults.rs`](https://github.com/n0-computer/iroh/blob/main/iroh/src/defaults.rs) | Default relay hostnames, ports, and `DEFAULT_MAX_TLS_TICKETS` | [defaults.rs](https://github.com/n0-computer/iroh/blob/main/iroh/src/defaults.rs) |
| [`iroh/src/address_lookup.rs`](https://github.com/n0-computer/iroh/blob/main/iroh/src/address_lookup.rs) | DNS and PKARR lookup service traits and builders | [address_lookup.rs](https://github.com/n0-computer/iroh/blob/main/iroh/src/address_lookup.rs) |
| [`iroh/src/tls.rs`](https://github.com/n0-computer/iroh/blob/main/iroh/src/tls.rs) | `CaTlsConfig`, crypto provider setup, and TLS context creation | [tls.rs](https://github.com/n0-computer/iroh/blob/main/iroh/src/tls.rs) |
| [`iroh/src/portmapper.rs`](https://github.com/n0-computer/iroh/blob/main/iroh/src/portmapper.rs) | NAT traversal configuration and STUN/TURN behavior | [portmapper.rs](https://github.com/n0-computer/iroh/blob/main/iroh/src/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`](https://github.com/n0-computer/iroh/blob/main/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`](https://github.com/n0-computer/iroh/blob/main/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`](https://github.com/n0-computer/iroh/blob/main/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`](https://github.com/n0-computer/iroh/blob/main/iroh/src/defaults.rs). The `N0` preset references these defaults automatically when you initialize the builder with `Endpoint::builder(presets::N0)`.