How to Configure an Iroh Endpoint for Different Network Environments (NAT and Firewall)

You configure an iroh endpoint for different network environments by using the Builder type in iroh/src/endpoint.rs to set bind addresses, relay modes, port-mapping behavior, and outbound proxies before calling .bind().await.

The n0-computer/iroh library provides fine-grained control over network discovery and traversal through its endpoint builder API. Whether you are deploying on a home router behind NAT, a locked-down corporate network, or a public server with a static IP, you can adapt the endpoint's behavior to maximize connectivity. This guide covers the builder methods and source files that control how the crate handles NAT, firewalls, and address advertisement.

Configuring the Iroh Endpoint Builder for Different Network Environments

The entry point for all network customization is the Builder type defined in iroh/src/endpoint.rs. It accumulates transport, addressing, and traversal settings before materializing a bound Endpoint when you call .bind().await. By adjusting bind options, port mapping, relay selection, and proxy settings, you can precisely control how the node behaves across varying topologies.

Binding to Local Interfaces and Subnets

To control which network interface the endpoint listens on, use bind_addr for a simple socket address or bind_addr_with_opts for advanced subnet control. The latter accepts a BindOpts struct that lets you specify a prefix length and mark the socket as the default route. This logic lives in iroh/src/endpoint.rs under Builder::bind_addr_with_opts.

use iroh::endpoint::BindOpts;

// Bind to a LAN address with a /24 netmask
.bind_addr_with_opts("192.168.1.10:0", BindOpts::default().set_prefix_len(24))

NAT Traversal and Firewall Bypass Options

Residential gateways and enterprise firewalls often block unsolicited inbound traffic. Iroh counters this with port mapping, explicit external address advertisement, and relay fallback. Each strategy is exposed as a builder method in iroh/src/endpoint.rs.

Automatic Port Mapping with portmapper_config

Iroh can negotiate port openings via UPnP, PCP, or NAT-PMP through the port-mapper subsystem in iroh/src/portmapper.rs. Enable this behavior with portmapper_config, which is the default, or disable it to avoid SSDP multicast traffic that can trigger firewall alerts.

.portmapper_config(iroh::PortmapperConfig::Enabled {})

Advertising External Addresses with external_addr

If you already know a public address from a STUN probe or static allocation, inject it with external_addr. These addresses are announced to peers and used during NAT traversal, as implemented in Builder::external_addr near line 444 of iroh/src/endpoint.rs.

.external_addr("203.0.113.42:0".parse().unwrap())

Relay Selection with relay_mode

When direct hole punching fails, fall back to a relay server via relay_mode. You can pass RelayMode::Default, RelayMode::Staging, or a custom RelayMap to provide a rendezvous point for traffic behind symmetric NATs and strict firewalls.

use iroh::endpoint::RelayMode;

.relay_mode(RelayMode::Default)

Proxy and Address Lookup Configuration

Corporate proxies and custom discovery layers require additional HTTP(S) routing and address resolution. The builder exposes proxy_url and address_lookup for these scenarios, both defined in iroh/src/endpoint.rs.

Routing Outbound HTTPS Through a Proxy

Route relay lookups and DNS-over-HTTPS through an outbound proxy using proxy_url, or automatically ingest standard environment variables with proxy_from_env. According to the source, Builder::proxy_url is located around line 889 of iroh/src/endpoint.rs.

.proxy_from_env()

Pluggable Address Lookup Services

To help peers discover your endpoint even when NAT masks your address, plug in a lookup service with address_lookup. The default implementation supports DNS and pkarr, and you can supply custom logic through iroh/src/address_lookup.rs.

.address_lookup(my_custom_lookup_service)

Environment-Specific Configuration Patterns

The following patterns assemble the individual builder methods into complete configurations for three common deployment scenarios. Each example is fully runnable and targets a specific network constraint.

Home Router Behind NAT

Bind to the LAN interface so traffic stays on the correct subnet, keep port mapping enabled to open the router automatically, and advertise a public address if you already know it. This combination maximizes the odds of a direct connection while still allowing relay fallback.

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

async fn home_nat() -> n0_error::Result<()> {
    let endpoint = Endpoint::builder(presets::N0)
        .bind_addr_with_opts(
            "192.168.1.10:0",
            BindOpts::default().set_prefix_len(24),
        )?
        .external_addr("203.0.113.42:0".parse().unwrap())
        .portmapper_config(iroh::PortmapperConfig::Enabled {})
        .bind()
        .await?;

    Ok(())
}

Corporate Firewall

In restrictive enterprise environments, SSDP discovery is frequently blocked and outbound ports are filtered. Disable the port mapper to avoid blocked multicast probes, force relay usage for connectivity, and send all HTTP(S) traffic through the corporate proxy.

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

async fn corporate_firewall() -> n0_error::Result<()> {
    let endpoint = Endpoint::builder(presets::N0)
        .bind()
        .await?
        .portmapper_config(iroh::PortmapperConfig::Disabled)
        .relay_mode(RelayMode::Staging)
        .proxy_from_env()
        .await?;

    Ok(())
}

Public Server with Static IP

Publicly routable hosts do not need port mapping or relay fallback for inbound connections. Bind to all interfaces with 0.0.0.0:0 and explicitly inject the static public address so peers can reach you directly.

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

async fn public_server() -> n0_error::Result<()> {
    let endpoint = Endpoint::builder(presets::N0)
        .bind_addr("0.0.0.0:0")?
        .external_addr("198.51.100.77:0".parse().unwrap())
        .bind()
        .await?;

    Ok(())
}

Summary

  • The Builder in iroh/src/endpoint.rs is the central API used to configure an iroh endpoint for different network environments.
  • Use bind_addr_with_opts to pin the endpoint to a specific interface or subnet.
  • Enable portmapper_config for automatic NAT traversal on home routers, or disable it in firewall-sensitive environments.
  • Set relay_mode and proxy_url when direct connectivity is blocked by symmetric NATs or corporate firewalls.
  • Inject known public addresses with external_addr to accelerate peer discovery on servers with static IPs.

Frequently Asked Questions

What is the default relay mode for a new iroh endpoint?

By default, the builder uses RelayMode::Default, which connects to the standard n0-computer relay infrastructure. This mode provides automatic fallback for NAT and firewall traversal without requiring any explicit configuration. You can override it with a staging relay or a custom RelayMap if needed.

Can I disable all automatic NAT traversal and rely solely on a static address?

Yes. Disable port mapping with portmapper_config(iroh::PortmapperConfig::Disabled), skip relay configuration if desired, and supply your expected public address via external_addr. Peers will then attempt to reach you directly at that address instead of using automated discovery.

How does the port mapper interact with corporate firewalls?

The port mapper sends SSDP multicast packets to discover local routers, which many corporate firewalls block or flag as suspicious. If your security team reports blocked outbound SSDP alerts, disable the port mapper and rely on a configured relay or proxy for outbound connectivity.

Is there a way to test whether my endpoint is reachable before advertising it?

The iroh/src/net_report/mod.rs module contains network-report utilities that probe reachability. You can use these probes to determine whether your endpoint is publicly accessible and whether a relay or port mapping is actually necessary.

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 →