How to Set Up an iroh Network: A Complete Guide

To set up an iroh network, deploy an iroh-relay server for NAT traversal fallback, configure each peer with an Endpoint pointing to the relay, and optionally run an iroh-dns-server for human-readable addressing.

Setting up an iroh network involves configuring the distributed infrastructure that enables peer-to-peer connectivity through NAT traversal and encrypted QUIC streams. The n0-computer/iroh repository provides the necessary binaries and libraries to establish this connectivity with minimal boilerplate. This guide walks through deploying the required relay infrastructure, initializing client endpoints, and optionally configuring DNS resolution for production deployments.

Architecture Overview

An iroh network consists of three distinct components that work together to provide seamless peer-to-peer connectivity:

  1. iroh-relay – A publicly accessible server that forwards encrypted packets when direct connections fail due to strict NATs or firewalls.
  2. Endpoint – The client-side abstraction (created via the iroh crate) that handles key generation, hole-punching, and protocol multiplexing.
  3. iroh-dns-server (optional) – A DNS service that resolves PKARR records, enabling human-readable addressing like endpoint-id.iroh.link.

Deploying the iroh-relay Server

The iroh-relay is the only mandatory infrastructure component. It exposes an HTTP API on port 3340 for client registration and can optionally provide QUIC address discovery on port 7824.

Development Mode

For local testing, run the relay in development mode without TLS:

cargo run --features="server" --bin iroh-relay -- --dev

This command compiles and starts the relay with permissive settings suitable for testing. According to the iroh-relay/README.md, the --dev flag disables certificate validation and enables plain HTTP communication.

Production Configuration

For production deployments, configure access control via a TOML configuration file:


# config.toml

access = "everyone"

The access field supports allow-lists, deny-lists, or shared-token schemes for restricting which endpoint IDs can utilize the relay. Refer to the access control documentation in iroh-relay/README.md for production-hardening options.

Creating an Endpoint in Rust

Each participant in the network creates an Endpoint using the iroh crate. The endpoint automatically generates a permanent EndpointId (a cryptographic public key) and manages the connection lifecycle.

Basic Endpoint Setup

The following example, adapted from iroh/examples/connect.rs, demonstrates the minimal code required to join an iroh network:

use iroh::endpoint::Endpoint;
use iroh::relay::RelayMap;

#[tokio::main]
async fn main() -> anyhow::Result<()> {
    // Create a local endpoint with a persistent EndpointId
    let endpoint = Endpoint::bind().await?;
    
    // Configure the relay for fallback connectivity
    let relay_cfg = RelayMap::default()
        .with_url("http://localhost:3340".parse()?);
    endpoint.set_relay_map(relay_cfg).await?;
    
    // Connect to a remote peer using their EndpointId
    let remote_id: iroh::EndpointId = "iroh:...".parse()?;
    let conn = endpoint
        .connect(remote_id, b"my-proto/0.1")
        .await?;
    
    // Open a bidirectional QUIC stream
    let (mut send, mut recv) = conn.open_bi().await?;
    send.write_all(b"hello iroh").await?;
    send.finish()?;
    
    let reply = recv.read_to_end(1024).await?;
    println!("reply: {}", String::from_utf8_lossy(&reply));
    
    Ok(())
}

Key Methods and Files

The implementation relies on several core components defined in the source tree:

  • Endpoint::bind() (defined in iroh/src/lib.rs) – Creates a UDP/QUIC socket and persists the endpoint ID to $XDG_DATA_HOME/iroh/endpoint-id.
  • RelayMap::default() (from iroh-base/src/relay_url.rs) – Constructs a relay configuration supporting multiple URLs for redundancy.
  • set_relay_map() – Registers the relay configuration with the endpoint, enabling fallback when direct hole-punching fails.

Optional DNS and PKARR Resolution

While peers can connect directly using raw EndpointId strings, the iroh-dns-server provides human-readable addressing through PKARR (Public Key Addressable Resource Records).

Running the DNS Server

Start the DNS server with PKARR support enabled:

cargo run --bin iroh-dns-server -- --config-path=example-dns.toml

Configuration requires enabling the PKARR service in the TOML file:

listen = "0.0.0.0:53"
pkarr = true

With this service running, peers resolve addresses like endpoint-id.iroh.link to their current QUIC sockets without exchanging raw UDP information. See iroh-dns-server/README.md for zone configuration and forwarding rules.

Address Resolution Types

The system supports multiple address types defined in iroh-base/src/endpoint_addr.rs, including raw UDP sockets, QUIC addresses, and PKARR DNS records.

Complete Working Example

To establish a functional iroh network:

  1. Start the relay infrastructure using either development mode (--dev) or a production configuration with TLS certificates.
  2. Initialize peer endpoints by calling Endpoint::bind() and configuring the RelayMap with your relay URL.
  3. Exchange EndpointIds either out-of-band or via the DNS server if deployed.
  4. Establish connections using endpoint.connect() with an ALPN protocol identifier (e.g., b"my-proto/0.1"), which enables protocol multiplexing over single connections.

The iroh/examples/echo.rs file provides a complete client-server demonstration showing bidirectional stream handling, while iroh/examples/transfer.rs illustrates file transmission over custom protocols.

Summary

  • Deploy iroh-relay – The only required infrastructure component for NAT traversal fallback and connectivity between restricted peers.
  • Configure Endpoint – Use Endpoint::bind() and set_relay_map() in Rust applications to join the network with automatic hole-punching.
  • Optional DNS – Run iroh-dns-server to enable PKARR-based human-readable addressing (*.iroh.link).
  • Core Implementation – All networking logic resides in iroh/src/lib.rs, with type definitions in iroh-base for RelayUrl and endpoint addressing.

Frequently Asked Questions

What infrastructure is required to set up an iroh network?

The minimum requirement is a single iroh-relay server. This binary handles NAT traversal and packet forwarding when direct connections fail. While optional, the iroh-dns-server simplifies peer discovery by mapping endpoint IDs to DNS names. No central coordinator or blockchain is required for basic operation.

Can I run an iroh network without a relay?

While possible on local networks with unrestricted UDP, the relay is essential for production deployments where peers reside behind corporate firewalls or symmetric NATs. The relay acts as a fallback path when hole-punching fails, ensuring connectivity in approximately 95% of network topologies.

How does the EndpointId persist between application restarts?

The Endpoint::bind() method automatically generates and stores the EndpointId (Ed25519 public key) in the platform-specific data directory ($XDG_DATA_HOME/iroh/endpoint-id on Linux). Subsequent calls to bind() load this identity, maintaining stable addressing across process lifecycles.

What is the difference between RelayMap and direct addressing?

RelayMap configures fallback servers for when direct UDP connectivity fails, while direct addressing (specifying an IP and port) attempts immediate connection. The endpoint always attempts direct hole-punching first; the relay map only activates after direct attempts timeout, ensuring optimal performance.

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 →