// Self-host a relay

Run your own relay

When your devices can't reach each other directly, they talk through a relay. It only ever forwards encrypted data. Running your own decides who sees the metadata: IP addresses, timing, sizes and device public keys.

Rather not run a server? Use the free public relay (see its rules), or have a managed relay run for you. Want a hand running your own? See setup help.

// What you run

Two small programs on one Linux host

iroh-relay

From the iroh project. Forwards encrypted traffic between devices that can't connect directly.

Inbound TCP 443. UDP 7842 optional.

voidwire-mailbox

Holds short-lived encrypted items for devices that are offline. It has no keys to decrypt them, keeps them in RAM only, and drops them after 60 minutes by default.

Outbound only. No open ports.

Linux, always on

x86_64 or arm64. A small machine is enough.

A public address

Not behind carrier-grade NAT, or use a tunnel you control.

A DNS name

Such as relay.example.com. Dynamic DNS is fine.

Port 443 forwarded

TCP 443 to the host. UDP 7842 helps direct connections.

// Quick start

Docker in five steps

No copy of the repository needed. Images come from the release.

  1. Get the release bundle

    bashrelease v1.1.0
    $ curl -fsSL https://github.com/voidwire-app/voidwire/releases/download/v1.1.0/voidwire-relay-docker.tar.gz | tar -xz
    $ cd voidwire-relay
  2. Fill in your settings

    bash.env holds no secrets
    $ cp .env.example .env
    # then set these three in .env
    VOIDWIRE_RELAY_HOSTNAME=relay.example.com
    VOIDWIRE_RELAY_CONTACT=you@example.com
    VOIDWIRE_RELAY_UDP=true

    The contact address is only given to Let’s Encrypt. Set UDP=false if you can’t forward UDP 7842. The defaults keep it private: token access, and the relay gets its own Let’s Encrypt certificate on port 443. The guide covers running it behind your own HTTPS proxy instead.

  3. Start it

    bash
    $ docker compose up -d
  4. Copy the relay link

    bashrewritten on every start
    $ sudo cat config/relay-link.txt
    voidwire:relay?r=https%3A%2F%2Frelay.example.com&m=…

    The link includes your relay's access token. Treat it like a password.

  5. Add it in the apps

    PC: Devices → Relays, paste the link, Add. Android: Settings → Relays → Add relay. Then choose Make home. New pairings use your relay; move an existing pairing with Change relay… and confirm on both devices.

// Defaults

Private by default

Token access

By default only devices that have your relay link can use the relay. You can open it to everyone, or keep it on your LAN or VPN.

No logs

The shipped configs log nothing: Docker's log driver is off and the services run with RUST_LOG=off. Turn off access logs on any proxy you put in front.

Limits you set

Files up to 25 MB go through the relay by default (up to 2 GB if you allow it), at 1 MB/s per device. Devices on the same network don't use the relay at all.

// Updates

Updating, and Watchtower

To update by hand, unpack the new release's compose.yml and templates over the old ones, then docker compose pull && docker compose up -d. Your .env, token and data are kept. Back up data/mailbox/identity.key: it is your relay's mailbox ID, and losing it means re-adding the link on every device.

Automatic updates with Watchtower (optional) Use the maintained fork, ghcr.io/nicholas-fedor/watchtower; the original containrrr/watchtower is archived. Label only the mailbox container. The relay image is pinned by digest on purpose, and a release that needs a newer relay ships a new compose.yml. Watchtower only updates the latest tag, and latest moves only on stable releases. Watchtower needs the Docker socket, which is root-level access to the host.

// Why not Cloudflare Tunnel

Keep TLS on your relay

A Cloudflare Tunnel or proxied (orange-cloud) DNS record is the easy way to expose a home server. For a Voidwire relay it works against the reason you're self-hosting.

  • A third party sits in the path. Cloudflare terminates TLS, so it sees who connects to whom, when and how much, and it sees your relay's access token. Content stays end-to-end encrypted, but the metadata you meant to keep is now with Cloudflare.
  • No UDP. Tunnels and the proxy don't carry UDP 7842, so devices lose address discovery and fewer connections go direct.
  • Terms of service. Cloudflare's self-serve terms restrict serving large non-HTML files through its proxy or Tunnel, so big transfers can put your account at risk.

What works: a DNS-only (grey-cloud) record pointing at your public IP, with the relay keeping its own TLS on TCP 443. Using Cloudflare for DNS only is fine. Behind CGNAT, use a tunnel or reverse proxy on a host you control.

Full guide: plain binaries, TLS behind a proxy, access control, Portainer, troubleshooting