How Iroh Relay Servers Work: NAT Traversal and Encrypted Traffic Forwarding
Iroh relay servers are optional, always-on nodes that sit between Iroh endpoints and forward encrypted traffic when direct peer-to-peer connections fail due to symmetric NATs or restrictive firewalls.
Iroh is an open-source distributed systems toolkit maintained by n0-computer that prioritizes direct connectivity, but when NAT traversal fails, the Iroh relay server provides a reliable fallback path. According to the n0-computer/iroh source code, the relay implementation lives in the iroh-relay crate and operates as a standalone binary designed to coordinate connections without compromising end-to-end encryption.
What Are Iroh Relay Servers?
Iroh relay servers act as intermediaries that maintain persistent connections to Iroh endpoints, forwarding encrypted data only when direct peer-to-peer links cannot be established. These servers do not handle plaintext payloads; they merely relay opaque encrypted frames between matched endpoint pairs. The implementation resides in the iroh-relay crate, specifically within the iroh::relay::server module imported in iroh-relay/src/main.rs.
The relay server's responsibilities are strictly limited to four core functions: accepting inbound client connections over HTTP, HTTPS, or QUIC; enforcing configurable access control policies; exchanging endpoint metadata such as public IP addresses and QUIC ports; and bidirectionally forwarding encrypted traffic between paired streams.
Core Architecture and Components
The relay binary delegates functionality across distinct modules that handle configuration, transport encryption, access verification, and data forwarding.
CLI and Configuration Layer
The entry point in iroh-relay/src/main.rs parses command-line flags and TOML configuration files to build a relay::ServerConfig structure. The key function build_relay_config(cfg) constructs this configuration, which the CLI then passes to the server constructor:
let relay_config = build_relay_config(cfg).await?;
let mut relay = relay::Server::spawn(relay_config).await?;
Configuration options include bind addresses, TLS settings, and access control policies sourced from iroh-relay.toml.
Transport and TLS Implementation
The server supports both HTTP/HTTPS and QUIC protocols, with TLS handling implemented in iroh-relay/src/tls.rs. This module manages certificate loading, supporting manual certificates, self-signed development certificates, or automatic LetsEncrypt provisioning. QUIC address discovery binds to tls.quic_bind_addr, while HTTPS listens on tls.https_bind_addr and plain HTTP (development only) binds to http_bind_addr.
Access Control System
Access control is implemented through the dyn AccessControl trait, with logic residing in iroh-relay/src/main.rs and token extraction handled in src/server/client.rs. The system supports five distinct modes:
- AllowAll permits any connection.
- Allowlist or Denylist check against known endpoint IDs.
- SharedToken validates bearer tokens from headers or URL query parameters.
- Http delegates authorization to an external HTTP endpoint by sending the
X-Iroh-Endpoint-Idheader and expecting atrueresponse.
Relay Engine and Stream Management
The core forwarding logic lives in iroh-relay/src/server.rs, which spawns the HTTP and QUIC listeners and manages client state through src/server/clients.rs. When two endpoints successfully authenticate, the server creates a pair of Stream objects defined in src/server/streams.rs that handle bidirectional frame forwarding between the matched clients.
Connection Flow and Data Relay Process
The relay server follows a strict lifecycle when establishing and maintaining connections between endpoints.
-
Startup: The binary reads
iroh-relay.toml(or uses defaults), loads TLS certificates via the TLS module, and binds to the configured addresses. -
Client Authentication: An Iroh endpoint connects with a
ClientRequestcontaining itsEndpointIdand optional authentication token. -
Policy Enforcement: The server invokes the configured
AccessControlimplementation to validate the connection attempt. -
Endpoint Pairing: Once two endpoints are authenticated and matched, the server creates bidirectional
Streampairs insrc/server/streams.rsto forward encrypted frames between them. -
Metrics Collection: If compiled with the
metricsfeature, counters for connections, bytes transferred, and rejections are incremented and exposed viasrc/server/metrics.rson a separate Prometheus-compatible endpoint.
Security Model and Encryption
Iroh relay servers are designed with a security-first architecture that maintains end-to-end encryption while providing connectivity fallback. The relay operates on a zero-knowledge principle regarding payload content, forwarding only opaque encrypted frames that it cannot decrypt or inspect.
The server enforces TLS for all QUIC address discovery and HTTPS traffic, with optional but recommended LetsEncrypt integration for automatic certificate management. Access control is fully pluggable, allowing operators to restrict relay usage to known endpoint IDs, token-based authentication, or external authorization services. Metrics and relay traffic are isolated on separate ports to prevent information leakage.
Development and Configuration Examples
To run a local relay server for development, use the development mode flag which disables TLS and binds to port 3340:
cargo run -p iroh-relay -- --dev
This command sets dangerous_http_only = true in the configuration, allowing plain HTTP connections for local testing.
For production deployments requiring authentication, configure a shared token in iroh-relay.toml:
access.shared_token = ["my-secret-token"]
Clients must then include the token in the Authorization: Bearer my-secret-token header or append ?token=my-secret-token to the connection URL.
Summary
- Iroh relay servers provide NAT traversal fallback by forwarding encrypted traffic between endpoints when direct peer-to-peer connections fail.
- The implementation in the
iroh-relaycrate separates concerns acrosssrc/main.rs(CLI),src/server.rs(core logic),src/tls.rs(encryption), andsrc/server/streams.rs(data forwarding). - Access control is pluggable, supporting static lists, shared tokens, and external HTTP authorization via the
AccessControltrait. - The relay maintains end-to-end encryption, handling only opaque encrypted frames and exposing no plaintext data to the server operator.
- Development mode (
--dev) enables rapid local testing without TLS certificates, while production deployments support LetsEncrypt and custom authentication schemes.
Frequently Asked Questions
Do Iroh relay servers see my data?
No. According to the n0-computer/iroh source code, Iroh relay servers forward only opaque encrypted frames between endpoints. The relay operates as a dumb pipe that cannot decrypt the payload, ensuring end-to-end encryption remains intact between the communicating peers.
What is the difference between Iroh relays and STUN/TURN servers?
While STUN servers help endpoints discover their public IP addresses and TURN servers relay media as a fallback, Iroh relay servers specifically handle the iroh::relay protocol. They exchange endpoint metadata including QUIC addresses and forward encrypted application data, whereas TURN typically handles raw UDP packets for WebRTC. The relay server is optimized for the Iroh protocol stack and maintains persistent HTTP/QUIC connections rather than temporary allocations.
How do I deploy a production Iroh relay server?
Production deployments require configuring TLS certificates via iroh-relay/src/tls.rs, either through manual certificate files or LetsEncrypt integration. You must specify tls.https_bind_addr and tls.quic_bind_addr in your configuration, implement appropriate AccessControl policies in the server configuration, and optionally enable the metrics feature for monitoring. The server runs as the iroh-relay binary with a custom iroh-relay.toml configuration file.
When does Iroh use a relay versus a direct connection?
Iroh endpoints attempt direct peer-to-peer connections first using NAT traversal techniques. The Iroh relay server serves as a fallback mechanism only when symmetric NATs, restrictive firewalls, or other network conditions prevent direct UDP hole punching from succeeding. Endpoints maintain persistent connections to known relays so they can rapidly fallback if direct paths become unavailable during a session.
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 →