# How to Configure iroh Endpoint to Listen on Multiple Addresses

> Learn how to configure iroh endpoint to listen on multiple addresses using bind_addr or bind_addr_with_opts methods. Easily manage network connections for your application and optimize performance.

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

---

**To configure an iroh Endpoint to listen on multiple addresses, use the `Builder::bind_addr()` or `Builder::bind_addr_with_opts()` methods repeatedly before calling `bind()`, and call `clear_ip_transports()` first to remove default unspecified sockets.**

The iroh networking library provides a flexible `Endpoint` builder pattern that allows precise control over socket binding. When you need to configure an iroh Endpoint to listen on multiple addresses, you modify the transport configuration before the endpoint initializes. This guide covers the specific builder methods and options available in the n0-computer/iroh repository.

## Understanding the Default Listening Behavior

By default, the iroh `Endpoint` builder creates sockets bound to unspecified addresses: **IPv4** on `0.0.0.0` and **IPv6** on `[::]`. This automatic configuration occurs in [`iroh/src/endpoint.rs`](https://github.com/n0-computer/iroh/blob/main/iroh/src/endpoint.rs) (lines 318-333) unless you explicitly override it with custom transport settings. The builder stores these configurations as `TransportConfig::Ip` entries that determine which sockets the endpoint will open during the `bind()` call.

## Configuring Multiple Bind Addresses

To listen on specific interfaces rather than all available network interfaces, you must clear the defaults and add explicit bind addresses using the builder API.

### Clearing Default Transports

Call `Builder::clear_ip_transports()` to remove the default "listen-on-all-interfaces" behavior. This method ensures the endpoint only listens on the specific addresses you define, preventing unintended exposure on all network interfaces.

### Simple Address Binding

Use `Builder::bind_addr()` as a convenience wrapper that applies default `BindOpts`. This method accepts a socket address string and returns the builder for method chaining, making it ideal for straightforward multi-address configurations.

### Advanced Binding with Options

For fine-grained control over routing and network topology, use `Builder::bind_addr_with_opts()`. This method accepts a `BindOpts` struct (defined in [`iroh/src/bind.rs`](https://github.com/n0-computer/iroh/blob/main/iroh/src/bind.rs)) that allows you to:

- Set subnet prefix lengths for address validation
- Mark addresses as required or optional for endpoint operation
- Designate specific addresses as default routes

Each call to these methods inserts a new `TransportConfig::Ip` entry into the builder's internal configuration, as implemented in [`iroh/src/endpoint.rs`](https://github.com/n0-computer/iroh/blob/main/iroh/src/endpoint.rs) (lines 313-368).

## Adding External Addresses After Binding

Once the endpoint is active, you can advertise additional reachable addresses using `Endpoint::add_external_addr()`. This method affects the advertised `EndpointAddr` without creating new listening sockets, allowing you to inform peers of NAT-mapped or relay addresses that differ from your local bind addresses.

## Implementation Examples

The following example demonstrates binding to specific IPv4 and IPv6 addresses with custom subnet prefixes, clearing the default transports first:

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

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // 1️⃣  Start from a preset (e.g. the “N0” preset).
    let builder = Endpoint::builder(presets::N0)
        // 2️⃣  Remove the default unspecified IPv4/IPv6 sockets.
        .clear_ip_transports()
        // 3️⃣  Bind to an IPv4 address on a random port, with a /24 subnet prefix.
        .bind_addr_with_opts(
            "192.168.1.10:0",
            BindOpts::default().set_prefix_len(24),
        )?
        // 4️⃣  Bind to an IPv6 address on a random port, with a /48 subnet prefix.
        .bind_addr_with_opts(
            "[fd00::1]:0",
            BindOpts::default().set_prefix_len(48),
        )?;

    // 5️⃣  Finish the construction – this creates the listening sockets.
    let endpoint = builder.bind().await?;

    // 6️⃣  (Optional) Advertise an additional external address after the endpoint is alive.
    endpoint.add_external_addr("203.0.113.5:0".parse()?).await;

    println!("Endpoint ready – listening on {:?}", endpoint.addr());
    Ok(())
}

```

The two `bind_addr_with_opts` calls add distinct transport entries; the builder now listens on both the IPv4 and IPv6 addresses, as stored in the `ip_bind_addrs` collection in [`iroh/src/socket.rs`](https://github.com/n0-computer/iroh/blob/main/iroh/src/socket.rs) (lines 364-422).

For simpler use cases using default options:

```rust
let endpoint = Endpoint::builder(presets::N0)
    .clear_ip_transports()
    .bind_addr("0.0.0.0:0")?            // IPv4
    .bind_addr("[::1]:0")?             // IPv6
    .bind()
    .await?;

```

The [`iroh/examples/transfer.rs`](https://github.com/n0-computer/iroh/blob/main/iroh/examples/transfer.rs) file (lines 540-560) provides a real-world example showing how a CLI parses multiple IPv4/IPv6 bind arguments and calls the builder repeatedly.

## Summary

- **Default behavior**: The `Endpoint` builder automatically binds to `0.0.0.0` and `[::]` on all interfaces unless modified.
- **Clear defaults**: Use `clear_ip_transports()` to remove unspecified address bindings before adding custom ones.
- **Add addresses**: Call `bind_addr()` for simple binding or `bind_addr_with_opts()` for advanced control over subnet prefixes and routing.
- **External addresses**: Use `add_external_addr()` post-binding to advertise additional reachable addresses without creating new sockets.
- **Source locations**: Implementation details reside in [`iroh/src/endpoint.rs`](https://github.com/n0-computer/iroh/blob/main/iroh/src/endpoint.rs), [`iroh/src/socket/transports/ip.rs`](https://github.com/n0-computer/iroh/blob/main/iroh/src/socket/transports/ip.rs), and [`iroh/src/bind.rs`](https://github.com/n0-computer/iroh/blob/main/iroh/src/bind.rs).

## Frequently Asked Questions

### What is the default binding behavior of iroh Endpoint?

By default, the `Endpoint` builder in [`iroh/src/endpoint.rs`](https://github.com/n0-computer/iroh/blob/main/iroh/src/endpoint.rs) creates an IPv4 socket bound to `0.0.0.0` and an IPv6 socket bound to `[::]` (the unspecified addresses). This allows the endpoint to accept connections on any available network interface unless you explicitly configure specific bind addresses.

### How do I remove default unspecified address bindings?

Call `Builder::clear_ip_transports()` before adding your custom addresses. This method removes the pre-configured IPv4 and IPv6 unspecified entries, ensuring the endpoint only listens on the specific interfaces you define with subsequent `bind_addr()` or `bind_addr_with_opts()` calls.

### What is the difference between bind_addr and bind_addr_with_opts?

`bind_addr()` is a convenience wrapper that accepts a socket address and uses default `BindOpts` for simple configuration. `bind_addr_with_opts()` accepts both a socket address and a `BindOpts` struct, allowing you to specify subnet prefix lengths, mark addresses as required or optional, and set default route flags for advanced network topology control.

### Can I add listening addresses after the endpoint is bound?

No, you cannot add new listening sockets after calling `bind()`. However, you can use `Endpoint::add_external_addr()` to advertise additional reachable addresses to peers. This updates the `EndpointAddr` metadata without creating new listening sockets, useful for informing peers of NAT-mapped or relay addresses.