How to Use Iroh's Default Relay Servers Provided by n0

To use Iroh's default relay servers, configure your Endpoint with RelayMode::Default in the builder, which automatically selects the production relay infrastructure operated by n0 without additional configuration.

Iroh is a peer-to-peer networking library that establishes direct QUIC connections between peers, falling back to relay servers when NAT traversal fails. When you use Iroh's default relay servers, you leverage the production infrastructure maintained by n0 to ensure connectivity between peers behind firewalls or restrictive networks. This guide explains exactly how to configure these defaults based on the implementation in the n0-computer/iroh repository.

What Are Relay Servers in Iroh?

Relay servers act as fallback intermediaries when direct UDP communication fails. When two peers cannot establish a direct connection due to NATs or firewalls, Iroh transparently routes traffic through these relays to maintain connectivity.

According to the iroh source code, the relay system is designed to be transparent to application code. You configure the relay mode during Endpoint initialization, and the library handles the complexity of hole-punching and fallback routing automatically.

How Default Relays Are Configured

The RelayMode Enum

The RelayMode enum in iroh/src/endpoint.rs (lines 1924-1926) defines how an endpoint selects its relay infrastructure:

pub enum RelayMode {
    Default,
    Custom(RelayMap),
    Disabled,
}

When you select RelayMode::Default, the endpoint automatically uses the production relay map. This is the recommended configuration for most applications using n0's infrastructure.

Production Relay Map Definition

The actual production relays are defined in iroh/src/defaults.rs. The default_relay_map() function (lines 36-43) constructs a RelayMap containing four regional relay servers:

  • NA-East: use1-1.relay.n0.iroh.link.
  • NA-West: usw1-1.relay.n0.iroh.link.
  • EU: euc1-1.relay.n0.iroh.link.
  • AP: aps1-1.relay.n0.iroh.link.

Note that these hostnames end with a trailing dot to force DNS absolute resolution, as defined by the constants NA_EAST_RELAY_HOSTNAME, NA_WEST_RELAY_HOSTNAME, EU_RELAY_HOSTNAME, and AP_RELAY_HOSTNAME in iroh/src/defaults.rs (lines 31-34).

The RelayUrl type in iroh-base/src/relay_url.rs provides a thin, cheaply clonable wrapper around url::Url that is used throughout the relay configuration system.

Implementing Default Relays in Code

Server Configuration Example

To configure a server endpoint that uses Iroh's default relay servers, instantiate the builder with RelayMode::Default. This pattern follows the implementation in iroh/examples/listen.rs:

use iroh::{
    Endpoint, RelayMode, SecretKey,
    endpoint::presets,
};
use n0_error::Result;

#[tokio::main]
async fn main() -> Result<()> {
    // Generate a key pair for this endpoint
    let secret_key = SecretKey::generate();

    // Build the endpoint with default relay servers
    let endpoint = Endpoint::builder(presets::N0)
        .secret_key(secret_key)
        .alpns(vec![b"my/app".to_vec()])
        .relay_mode(RelayMode::Default)   // Uses n0's production relays
        .bind()
        .await?;

    // Wait until registered with a relay
    endpoint.online().await;

    println!("Listening on {:?}", endpoint.addr());

    // Accept incoming connections
    while let Some(incoming) = endpoint.accept().await {
        let conn = incoming.accept()?;
        println!("Incoming connection from {}", conn.remote_id());
    }

    Ok(())
}

Client Configuration Example

Clients connecting to peers use the same configuration. The default relay map ensures both endpoints can discover each other even when behind NAT. This mirrors the pattern in iroh/examples/connect.rs:

use iroh::{
    Endpoint, RelayMode, SecretKey,
    endpoint::presets,
};
use n0_error::Result;

#[tokio::main]
async fn main() -> Result<()> {
    let secret_key = SecretKey::generate();

    let endpoint = Endpoint::builder(presets::N0)
        .secret_key(secret_key)
        .alpns(vec![b"my/app".to_vec()])
        .relay_mode(RelayMode::Default)   // Same default map as the listener
        .bind()
        .await?;

    // Replace with actual EndpointId and addresses
    let remote_id = "...".parse()?;
    let remote_addrs = vec!["127.0.0.1:5000".parse()?];

    // The library will use default relays if direct UDP fails
    let conn = endpoint
        .connect(remote_id, remote_addrs, b"my/app")
        .await?;

    println!("Connected to {}", conn.remote_id());
    Ok(())
}

Customizing Relay Configuration

Using Staging Relays

For testing purposes, you can force the use of staging relays instead of production by setting the environment variable before starting your application:

export IROH_FORCE_STAGING_RELAYS=1

When this variable is set to any non-empty value, the library calls crate::defaults::staging::default_relay_map() instead of the production map. This logic is defined in iroh/src/endpoint.rs (lines 64-66).

Creating Custom Relay Maps

If you need to pin specific relays or use your own infrastructure, construct a custom map using RelayMode::custom:

use iroh::{RelayMode, RelayUrl};

let custom = RelayMode::custom([
    "https://use1-1.relay.n0.iroh.link.".parse::<RelayUrl>()?,
    "https://euc1-1.relay.n0.iroh.link.".parse::<RelayUrl>()?,
]);

// Use in the endpoint builder
let endpoint = Endpoint::builder(presets::N0)
    .relay_mode(custom)
    .bind()
    .await?;

The RelayMode::custom implementation is found in iroh/src/endpoint.rs (lines 45-61).

Summary

  • Iroh's default relay servers are automatically selected when you configure Endpoint::builder() with RelayMode::Default.
  • The production relay map contains four regional servers (NA-East, NA-West, EU, AP) defined in iroh/src/defaults.rs.
  • The RelayUrl type in iroh-base/src/relay_url.rs provides efficient URL handling for relay configurations.
  • Set IROH_FORCE_STAGING_RELAYS=1 to use staging relays for testing.
  • Use RelayMode::custom() to specify specific relay URLs when the defaults are not appropriate.

Frequently Asked Questions

What happens when I use RelayMode::Default?

When you select RelayMode::Default, the endpoint internally calls default_relay_map() from the defaults module, which returns a RelayMap containing the four production relay URLs operated by n0. The endpoint registers itself with these relays during the bind() operation, enabling fallback connectivity when direct UDP paths fail.

Can I use custom relay servers instead of the defaults?

Yes, you can use RelayMode::custom() to provide a specific RelayMap containing your own relay URLs. This is useful for private deployments or when you need to restrict connectivity to specific geographic regions. Pass your custom map to .relay_mode() in the endpoint builder.

How do I switch to staging relays for testing?

Set the environment variable IROH_FORCE_STAGING_RELAYS to any non-empty value before starting your application. This forces the use of crate::defaults::staging::default_relay_map() instead of the production map, allowing you to test against n0's staging infrastructure without modifying code.

Are the default relay servers free to use?

The default relay servers operated by n0 are generally available for use with Iroh applications, but you should review n0's current terms of service and any applicable rate limits or fair use policies for production deployments. For high-volume applications, consider running your own relay infrastructure using RelayMode::custom().

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 →