Skip to content

Allow custom RelayMode via XS_RELAY_URL env var#139

Open
joeblew999 wants to merge 1 commit into
cablehead:mainfrom
joeblew999:feature/relay-url-env
Open

Allow custom RelayMode via XS_RELAY_URL env var#139
joeblew999 wants to merge 1 commit into
cablehead:mainfrom
joeblew999:feature/relay-url-env

Conversation

@joeblew999
Copy link
Copy Markdown

Why

xs currently hardcodes iroh::RelayMode::Default in three places (listener.rs:303, listener.rs:374, client/connect.rs:74). RelayMode::Default routes via n0's public relay infrastructure (use1, euw1, apse-1).

That's the right default, but operators have legitimate reasons to override:

  • Regions where n0's defaults aren't reachable. As of writing, apse-1.relay.iroh.network has no public DNS A record. Iroh nodes in Asia hang indefinitely on home_relay().initialized().await — a laptop in Thailand cannot bind an iroh:// endpoint at all. Self-hosting an iroh-relay (e.g. on a Hetzner Singapore VM) is the workaround, but today it requires source-patching xs.
  • Compliance / air-gapped networks where outbound to relay.iroh.network isn't permitted.
  • Local development against a self-hosted dev relay.

What

Introduces src/relay.rs exporting relay_mode_from_env() -> RelayMode:

XS_RELAY_URL value resolves to
empty / unset RelayMode::Default (preserves existing behavior — strict superset)
"disabled" (case-insensitive) RelayMode::Disabled
any other value parsed as iroh_base::RelayUrlRelayMode::Custom(RelayMap)
parse failure falls back to RelayMode::Default with a tracing::warn!

The three iroh endpoint builders in listener.rs and client/connect.rs now call this helper instead of using the hardcoded constant.

Backward compatibility

Strict superset. Users who don't set XS_RELAY_URL get exactly the prior behavior.

Tests

6 unit tests in src/relay::tests cover: unset, empty, whitespace, "DISABLED" keyword, valid URL → Custom, malformed URL → Default fallback.

All existing tests pass (cargo test --lib).

Verification

Built locally and run from a Thai laptop against a self-hosted iroh-relay 1.0.0-rc.0 on Hetzner Singapore (5.223.94.174 in --dev mode):

XS_RELAY_URL=http://5.223.94.174:3340 ./target/release/xs serve /tmp/store --expose iroh://

09:54:38.859  INFO XS_RELAY_URL=http://5.223.94.174:3340 — using RelayMode::Custom
09:54:38.888 DEBUG Iroh endpoint bound successfully
09:54:41.892  INFO Iroh endpoint ready with node ID: f19a07801049…
09:54:41.892  INFO Iroh ticket: nodeadyzub4ac…

Without the patch, the bind hangs forever in that environment.

Naming alternative

Happy to rename the env var (e.g. XS_RELAY or CROSSTREAM_RELAY_URL) if there's a project convention I should follow.

xs currently hardcodes `iroh::RelayMode::Default` in three places (the
iroh listener bind, the listener's outbound dial, and the client connect
path). RelayMode::Default routes through n0's public relay infrastructure
(use1, euw1, apse-1).

This is the right default, but operators have legitimate reasons to
override:

- **Regions where n0's defaults aren't reachable.** The Asia-Pacific
  regional relay (apse-1.relay.iroh.network) currently has no public DNS
  A record, so iroh nodes in that region hang indefinitely on
  `home_relay().initialized().await`. A laptop in Thailand cannot bind
  an iroh:// endpoint at all. The workaround is to self-host an
  iroh-relay (e.g. on Hetzner Singapore) and point xs at it — but that
  is impossible today without source-patching xs.

- **Compliance / air-gapped networks** that don't allow outbound to
  relay.iroh.network.

- **Local development** against a self-hosted dev relay.

This commit introduces a small `relay` module that resolves the iroh
`RelayMode` from an `XS_RELAY_URL` environment variable:

  - empty / unset           → RelayMode::Default  (preserved default; strict superset)
  - "disabled" (any case)   → RelayMode::Disabled
  - any other value         → parsed as RelayUrl → RelayMode::Custom(map)
  - parse failure           → falls back to RelayMode::Default + warn log

The three call sites in listener.rs and client/connect.rs now call
`relay_mode_from_env()` instead of using the hardcoded constant. No
behavior change for anyone who doesn't set the env var.

Includes unit tests for all five paths (unset, empty, whitespace,
disabled keyword, valid URL, malformed URL fallback).

Verified end-to-end against a self-hosted iroh-relay v1.0.0-rc.0 on
Hetzner Singapore from a Thai laptop — bind completes in ~3s where
previously it hung forever.
@joeblew999 joeblew999 force-pushed the feature/relay-url-env branch from 2561b57 to d45fca9 Compare May 22, 2026 09:57
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant