mpmux by Mighty Painting
~/mpmux/docs ❯ less relay-server/contents ↓

Your own relay server#

Your devices reach your session host in one of two ways. When they can see each other on the network, for example at home on the same Wi-Fi, they connect directly. When they cannot, because the server sits behind a router or your phone is on mobile data, they meet at a relay: a small server on the internet that passes their packets on.

  tablet ──────────── direct, when possible ─────────── session host
     │                                                       │
     └──────────────► relay.mightypainting.dev ◄─────────────┘
                  (forwards encrypted packets)

mpmux uses the relay relay.mightypainting.dev unless you set up your own. That relay works and costs you nothing, so most people never need this page.

Do I need my own?#

The relay cannot read your terminal. Everything between your devices and the host is end-to-end encrypted, and the relay only forwards the encrypted packets. It holds no keys and no passwords.

What a relay does see is that your devices talk to each other, when, and how much. Run your own relay if:

  • you want that information to stay on a server you control,
  • you want the relay close to you (a server in your country or your company's network), for lower latency,
  • you do not want to depend on someone else's server being up.

What you need#

  • A small server with a public IP address: any cloud VM or a machine at home that the internet can reach. It needs little: a relay for a few devices runs on the smallest VM.
  • A domain name pointing at it, for example relay.example.com.
  • Ports 80 and 443 open (80 is only for getting the HTTPS certificate).
  • About 15 minutes.

The steps below are for Ubuntu or Debian. They are the setup that runs relay.mightypainting.dev.

Step 1: install the relay#

The relay is the iroh-relay program from the Iroh project. Install Rust (https://rustup.rs), then build and install it:

cargo install iroh-relay --version 1.1.0 --features server --locked
sudo install -m755 ~/.cargo/bin/iroh-relay /usr/local/bin/iroh-relay
sudo useradd --system --no-create-home --shell /usr/sbin/nologin iroh-relay

Version 1.1.0 is the one mpmux 0.1.8 is tested with.

Step 2: configure and start it#

The relay itself listens only on the server's own address; Caddy (step 3) takes the connections from the internet and adds HTTPS. Create /etc/iroh-relay/config.toml:

enable_relay = true
http_bind_addr = "127.0.0.1:3340"
enable_quic_addr_discovery = false
enable_metrics = true
metrics_bind_addr = "127.0.0.1:9090"
access = "everyone"

[limits]
accept_conn_limit = 20.0
accept_conn_burst = 100

[limits.client.rx]
bytes_per_second = 4194304
max_burst_bytes = 16777216

The limits keep the relay from being overrun: at most 20 new connections a second, and 4 MB/s per device. That is plenty for terminals; raise them if many people share the relay.

Then a service that starts it with the server, /etc/systemd/system/iroh-relay.service:

[Unit]
Description=Iroh relay for mpmux
After=network-online.target
Wants=network-online.target

[Service]
Type=simple
User=iroh-relay
Group=iroh-relay
Environment=RUST_LOG=info,iroh_relay=info
ExecStart=/usr/local/bin/iroh-relay --config-path /etc/iroh-relay/config.toml
Restart=on-failure
RestartSec=5s
StateDirectory=iroh-relay
NoNewPrivileges=true
PrivateTmp=true
ProtectHome=true
ProtectSystem=strict
RestrictAddressFamilies=AF_UNIX AF_INET AF_INET6

[Install]
WantedBy=multi-user.target

Start it:

sudo systemctl daemon-reload
sudo systemctl enable --now iroh-relay

Step 3: HTTPS with Caddy#

Caddy gets a certificate for your domain by itself and passes the relay's connections on. Install it (sudo apt install caddy), then put this in /etc/caddy/Caddyfile, with your domain in both places:

{
    # Iroh 1.1 and later send no server name when they connect; this tells
    # Caddy which certificate to use for them.
    default_sni relay.example.com
}

relay.example.com {
    @relay_websocket {
        path /relay
        header Upgrade websocket
    }
    handle @relay_websocket {
        reverse_proxy 127.0.0.1:3340 {
            flush_interval -1
        }
    }

    @relay_probe path /ping /generate_204
    handle @relay_probe {
        reverse_proxy 127.0.0.1:3340
    }

    handle {
        respond "Not Found" 404
    }
}

Do not leave out default_sni: without it, current mpmux versions cannot connect. If Caddy serves other websites too, keep it pointing at the relay.

sudo systemctl reload caddy

Step 4: check it#

From any computer:

curl -i https://relay.example.com/ping

It should answer HTTP/2 200. If it does not, see when something does not work.

Step 5: switch mpmux to it#

On the machine that runs your session host, install the host with your relay (--restart applies it to a host that already runs; it ends the host's shells, so save your work first):

mpmux-cli service install --remote --relay-url https://relay.example.com --restart

Check that the host uses it:

journalctl --user -u mpmux-sessiond -n 20 | grep "Iroh listener"
# mpmux-sessiond: Iroh listener online as … via https://relay.example.com/

Now pair your devices again (chapter 8): a device learns which relay to use from the invite, so devices you paired before still look for the host at the old relay. New invites carry your relay; nothing needs to be set on the devices themselves.

Devices on the same network as the host keep connecting directly; the relay is only for the rest. To send everything through your relay, add --relay-only.

When something does not work#

Symptom Likely cause
curl …/ping times out The firewall or the cloud provider blocks port 443, or the domain does not point at the server yet (dig relay.example.com).
curl reports a certificate error Caddy could not get a certificate: port 80 must be open for that, and the domain must point at this server. journalctl -u caddy says why.
curl works, but devices cannot connect default_sni is missing in the Caddyfile, or the devices were paired before the switch: pair them again.
The host's log shows no "Iroh listener online … via" your relay The service still has the old relay: run step 5 again with --restart.

journalctl -u iroh-relay -f on the relay server shows connections as they come and go.

For operators#

  • Monitoring: the relay publishes Prometheus metrics on http://127.0.0.1:9090/metrics (local to the server only), and https://relay.example.com/generate_204 answers 204 while Caddy and the relay are up, for an uptime check.
  • Short-code pairing: short codes use a separate rendezvous service, pair.mightypainting.dev, which only passes encrypted handshake data. Pairing by link or QR code does not use it. You can run it yourself (mpmux-cli short-code-relay behind Caddy on /relay); mpmux-cli session create-qr-code --relay takes its address, while mpmux-cli pair short-code always uses the default service.
  • Updates: keep iroh-relay at a version mpmux is tested with; the release notes say when that changes.