docs/Deployment/Self Hosting

Self-Hosting

Deploy a relay to Fly.io or any server.

Fly.io deployment#

The recommended way to deploy a Subway relay.

fly.toml

app = "my-subway-relay"
primary_region = "iad"
 
[[services]]
  protocol = "udp"
  internal_port = 9000
  [[services.ports]]
    port = 9000
 
[[services]]
  protocol = "tcp"
  internal_port = 9001
  [[services.ports]]
    port = 443
    handlers = ["tls", "http"]
  [[services.http_checks]]
    interval = 10000
    timeout = 2000
    path = "/"

Persistent volume

The relay's identity keys must survive redeploys:

fly volumes create subway_data --size 1 --region iad

Mount at /data in your Dockerfile and set key storage to /data/.subway/relay-keys.

Deploy

fly deploy

Bare metal / VPS#

# Build from source
cargo build --release -p subway-cli
 
# Run the relay
RUST_LOG=info ./target/release/subway relay --port 9000

Requirements:

  • UDP port 9000 open (QUIC/WebTransport)
  • TCP port 9001 open (HTTP health + REST bridge)
  • TCP port 9002 open (WebSocket bridge)
  • Persistent storage for identity keys

Connecting agents to your relay#

subway agent --name worker.relay --relay your-relay.example.com:9000

Or in Rust:

let node = AgentNode::builder()
    .name("worker.relay")
    .relay("your-relay.example.com:9000")
    .build()
    .await?;
Tip

For production, put TLS termination in front of port 9001 (Fly.io handles this automatically). QUIC on port 9000 handles its own encryption via the Noise protocol.