# How to Bind an Iroh Endpoint to a Specific IP Address and Port

> Learn how to bind an Iroh endpoint to a specific IP address and port using the builder pattern. Configure your UDP socket for reliable networking.

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

---

**Use the `bind_addr` method on `iroh::endpoint::Builder` to supply a `std::net::SocketAddr`, then call `bind().await` to create the endpoint and open the UDP socket on your chosen interface.**

The n0-computer/iroh networking library provides a flexible `Endpoint` abstraction for peer-to-peer connectivity. When you need to bind an Iroh endpoint to a specific IP address and port—whether for IPv4, IPv6, or dual-stack networking—you configure the underlying transport through the `Builder` API before the socket is created.

## The Endpoint Builder Pattern

The `iroh::endpoint::Builder` type, defined in [`iroh/src/endpoint.rs`](https://github.com/n0-computer/iroh/blob/main/iroh/src/endpoint.rs), serves as the configuration interface for `Endpoint` creation. The builder stores transport parameters in an internal state and only applies them when you finalize construction. This deferred binding lets you specify exactly which IP address and port the underlying UDP socket should use.

## Configuring the Bind Address

To bind an Iroh endpoint to a specific IP address and port, pass a `SocketAddr` to the builder's `bind_addr` method. This stores the address in the builder's transport configuration until you invoke `bind().await`.

### Step-by-Step Binding Process

1. Create a builder instance using `Builder::new(preset)` or `Builder::default()`.
2. Call `bind_addr(socket_addr)` with your target `std::net::SocketAddr`.
3. Await `builder.bind()` to open the socket and return the configured `Endpoint`.

### IPv4 Binding Example

The following example binds to a concrete IPv4 address and port:

```rust
use std::net::{IpAddr, Ipv4Addr, SocketAddr};
use iroh::endpoint::{Builder, Preset};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Create the builder with a preset or default configuration
    let preset = Preset::default();
    let builder = Builder::new(preset);

    // Configure the specific IPv4 address and port
    let bind_ip: IpAddr = Ipv4Addr::new(192, 168, 1, 42).into();
    let bind_port = 44323;
    let bind_addr = SocketAddr::new(bind_ip, bind_port);

    // Apply the bind address to the builder
    let builder = builder.bind_addr(bind_addr);

    // Open the socket and create the endpoint
    let endpoint = builder.bind().await?;
    
    println!("Iroh endpoint bound to {}", endpoint.local_addr());
    Ok(())
}

```

### IPv6 Binding Example

The same API works for IPv6 by using `Ipv6Addr`:

```rust
use std::net::{Ipv6Addr, SocketAddr};

let bind_ip = Ipv6Addr::UNSPECIFIED; // :: 
let bind_addr = SocketAddr::new(bind_ip.into(), 8080);
let endpoint = Builder::default()
    .bind_addr(bind_addr)
    .bind()
    .await?;

```

### Binding to Multiple Addresses

You can call `bind_addr` repeatedly to listen on several interfaces simultaneously. Each invocation pushes a new address onto the internal transport list. When you finally call `bind()`, Iroh creates a separate UDP socket for each configured address.

## Transport Layer Implementation

Under the hood, your specified address flows to `IpTransport::bind` in [`iroh/src/socket/transports/ip.rs`](https://github.com/n0-computer/iroh/blob/main/iroh/src/socket/transports/ip.rs). This function invokes `netwatch::UdpSocket::bind_full(addr)` to perform the OS-level UDP socket binding with the exact `SocketAddr` you provided. If the bind succeeds, the transport is registered with the endpoint's socket coordinator in [`iroh/src/socket.rs`](https://github.com/n0-computer/iroh/blob/main/iroh/src/socket.rs).

If the bind fails—for example, because the port is already in use—the error propagates back through `Builder::bind()` as a `Result::Err`, allowing you to handle the failure gracefully.

## Error Handling for Bind Failures

Since `bind().await` returns a `Result`, you must handle cases where the specific IP address and port are unavailable. Common failure modes include:

- **Address already in use**: The OS reports the port is bound by another process.
- **Permission denied**: Attempting to bind to a well-known port (below 1024) without sufficient privileges.
- **Address not available**: The specified IP is not assigned to any local network interface.

Match on the `Result` to implement retry logic with ephemeral ports or exit with a descriptive error.

## Summary

- Use `iroh::endpoint::Builder` and its `bind_addr` method to specify the listening address before constructing the endpoint.
- Supply a `std::net::SocketAddr` containing your target IP (IPv4 or IPv6) and port number.
- Call `bind().await` to execute the socket binding via `IpTransport::bind` in [`iroh/src/socket/transports/ip.rs`](https://github.com/n0-computer/iroh/blob/main/iroh/src/socket/transports/ip.rs).
- Support multiple bindings by calling `bind_addr` repeatedly before the final `bind()` invocation.
- Handle binding errors, such as "address already in use," through the returned `Result` type.

## Frequently Asked Questions

### Can I bind to a specific port with IP address 0.0.0.0?

Yes. Construct a `SocketAddr` with `Ipv4Addr::UNSPECIFIED` (or `Ipv6Addr::UNSPECIFIED`) and your desired port. This binds the endpoint to all available network interfaces on that specific port, which is useful for servers that accept connections from any IP.

### What happens if I don't call `bind_addr` on the builder?

The builder uses default transport behavior which may bind to ephemeral ports or unspecified addresses depending on the preset configuration. For production deployments requiring specific ports or network isolation, always explicitly set the bind address using `bind_addr`.

### How do I handle "address already in use" errors when binding?

The `bind().await` method returns a `Result` that will be `Err` if the OS reports the address is unavailable. Match on this error to implement retry logic with different ports, wait for the port to be released, or exit gracefully with a user-facing message.

### Can I bind to both IPv4 and IPv6 simultaneously?

Yes. Call `bind_addr` twice—once with an IPv4 `SocketAddr` and once with an IPv6 `SocketAddr`—before invoking `bind()`. According to the implementation in [`iroh/src/endpoint.rs`](https://github.com/n0-computer/iroh/blob/main/iroh/src/endpoint.rs), the endpoint will create separate transports for each address family, allowing dual-stack operation.