How to Configure Custom Relay Servers in iroh Using RelayMode::Custom
Use RelayMode::Custom(RelayMap) when building your iroh Endpoint to route traffic through self-hosted relay servers instead of the default infrastructure.
When direct peer-to-peer connections fail, the iroh networking layer relies on relay servers to forward traffic between nodes. The RelayMode enum in iroh/src/endpoint.rs controls this behavior, allowing you to configure custom relay servers using RelayMode::Custom for complete infrastructure control.
Understanding RelayMode Variants
The RelayMode enum in iroh/src/endpoint.rs defines four distinct strategies for relay discovery:
RelayMode::Disabled– Restricts connections to direct peer-to-peer paths only, with no relay fallback.RelayMode::Default– Automatically uses the production relay map fromcrate::defaults::prod::default_relay_map().RelayMode::Staging– Uses the staging relay map fromcrate::defaults::staging::default_relay_map()for testing environments.RelayMode::Custom(RelayMap)– Accepts a user-suppliedRelayMapcontaining your own set ofRelayUrlendpoints.
The RelayMap type is simply a collection of RelayUrls that the endpoint queries when establishing relayed connections.
Configuring Custom Relay Servers
To configure custom relay servers, construct a RelayMode::Custom variant using the helper method RelayMode::custom(iter), which accepts any iterator of RelayUrls.
Building the RelayMap
Parse your relay URLs and pass them to RelayMode::custom():
use iroh::{RelayMode, RelayUrl};
let custom_relays = [
"https://my-relay-1.example.com/".parse::<RelayUrl>()?,
"https://my-relay-2.example.com/".parse::<RelayUrl>()?,
];
let relay_mode = RelayMode::custom(custom_relays);
Applying to the Endpoint Builder
Pass the configured RelayMode to the builder before binding:
use iroh::{Endpoint, presets};
let endpoint = Endpoint::builder(presets::Minimal)
.relay_mode(relay_mode)
.bind()
.await?;
Practical Implementation Examples
Basic Custom Relay Configuration
use iroh::{Endpoint, RelayMode, RelayUrl, presets};
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let urls = vec![
"https://relay-1.example.com/".parse::<RelayUrl>()?,
"https://relay-2.example.com/".parse::<RelayUrl>()?,
];
let endpoint = Endpoint::builder(presets::Minimal)
.relay_mode(RelayMode::custom(urls))
.bind()
.await?;
Ok(())
}
Loading Relays from Environment Variables
As demonstrated in iroh/examples/connect.rs, you can dynamically configure relays from environment variables:
use std::{env, str::FromStr};
use iroh::{Endpoint, RelayMode, RelayUrl, presets};
async fn build_endpoint() -> Result<Endpoint, Box<dyn std::error::Error>> {
let urls = env::var("RELAY_URLS")?;
let relay_urls: Vec<RelayUrl> = urls
.split(',')
.map(|s| RelayUrl::from_str(s.trim()))
.collect::<Result<Vec<_>, _>>()?;
let endpoint = Endpoint::builder(presets::Minimal)
.relay_mode(RelayMode::custom(relay_urls))
.bind()
.await?;
Ok(endpoint)
}
Disabling Relays for LAN-Only Deployments
use iroh::{Endpoint, RelayMode, presets};
let endpoint = Endpoint::builder(presets::Minimal)
.relay_mode(RelayMode::Disabled)
.bind()
.await?;
Internal Implementation Details
When Endpoint::builder prepares the configuration, the relay_mode() method stores your chosen RelayMode. During connection establishment, iroh calls relay_map() on the mode to retrieve the appropriate RelayMap. For RelayMode::Custom, this returns your user-supplied map rather than the default production or staging maps.
The conversion happens in the From<RelayMode> for Option<TransportConfig> implementation in iroh/src/endpoint.rs, which maps the RelayMode to the internal TransportConfig::Relay variant used by the networking layer. This design is validated in iroh/tests/patchbay/util.rs, which uses RelayMode::Custom in integration tests.
Summary
RelayMode::Customenables self-hosted relay infrastructure in n0-computer/iroh via theRelayMaptype.- The helper method
RelayMode::custom(iter)constructs a valid mode from any iterator ofRelayUrls. - Set the mode using
.relay_mode()on theEndpointbuilder before calling.bind(). - The configuration is defined in
iroh/src/endpoint.rsalongside the conversion logic that produces the internalTransportConfig.
Frequently Asked Questions
What is the difference between RelayMode::Default and RelayMode::Custom?
RelayMode::Default automatically uses the production relay servers maintained by the iroh team (via crate::defaults::prod::default_relay_map()), while RelayMode::Custom requires you to supply your own relay URLs via a RelayMap for complete control over the relay infrastructure.
Can I use multiple custom relay servers in iroh?
Yes. The RelayMode::custom() helper accepts any iterator, allowing you to pass multiple RelayUrl instances. The endpoint will use these relays for hole-punching and traffic forwarding when direct connections fail, as implemented in the relay_map() method.
How do I disable relay servers entirely in iroh?
Use RelayMode::Disabled when configuring your endpoint. This prevents the endpoint from using any relay infrastructure, restricting connections to direct peer-to-peer paths only, which is useful for LAN-only deployments.
Where is the RelayMode configuration stored in the iroh codebase?
The RelayMode enum and its conversion logic are defined in iroh/src/endpoint.rs. This file also contains the From<RelayMode> for Option<TransportConfig> implementation that translates the high-level mode into the internal transport configuration used by the networking stack.
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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →