How the phone connects
Direct, punched or relayed, always one SSH connection, and never an open port on your router.
Your computer is only reachable through connections it opened itself. Link Host never asks you to forward a port, change a firewall or run a VPN. It keeps one outgoing connection to a meeting point and learns there when a phone wants it. Whatever the path, what travels is one SSH connection, encrypted between the app and the computer's SSH server.
The three paths
Direct
The phone dials the computer's SSH server: same network, a public address, or a VPN you already use.
Punched
Different networks: both sides send UDP to each other at once, so their routers let the replies through. Still direct, end to end.
Relayed
When no direct path opens: both sides dial a relay, which passes the encrypted bytes along.
Which ones are on offer depends on how you paired (below). When the phone changes network on a punched path, say from Wi-Fi to mobile data, the same SSH session moves with it after a signed challenge, with no reconnect; where the computer's firewall drops that first packet, the app reconnects instead, a few seconds' pause.
The default: rendezvous
A plain link-host ssh setup pairs in rendezvous mode. There's no server of yours anywhere:
- Each side asks a public STUN server what its public address looks like from outside.
- They swap those addresses over a public ntfy topic that only the two of them know. The messages are sealed with AES-GCM using a key that only the pairing code carried, so ntfy sees ciphertext.
- They punch a direct UDP path and run the SSH connection over it (with KCP for reliable delivery).
ntfy only ever sees two sealed messages per connection, posted without caching, and which IP addresses used the topic.
Rendezvous has no fallback: when no direct path forms, the phone says "No direct path from this network". That happens on the strictest networks, such as mobile carriers that give each destination a different port. For those, pair through a relay. The free ntfy.sh also allows 250 messages a day per IP address, and each connection uses two.
Through a relay
link-host ssh setup --relay wss://link-relay.example.workers.devWith a relay, the computer keeps one outgoing WebSocket to it, and the phone dials it too. The relay:
- introduces the two sides so they can punch a direct path, and steps out of the way when they do;
- otherwise splices their streams together, seeing only SSH ciphertext;
- admits only phones whose token the computer registered.
A relay that holds a Cloudflare TURN key can also hand the computer short-lived TURN credentials, which gives one more route that works when both sides sit behind strict NATs.
Link doesn't run a public relay yet: you deploy your own to your Cloudflare account, free, with one command. See Your own relay.
Is it peer-to-peer?
| Path | Who's in the middle | Needs an open port on the computer |
|---|---|---|
| Direct | Nobody | Only on networks where the phone dials in (your LAN, a VPN) |
| Punched (rendezvous or relay) | Nobody once the path is up; ntfy or the relay only introduced the two sides | No |
| Relayed | Your relay, which sees ciphertext only | No |
| TURN | Cloudflare's TURN service, which sees ciphertext only | No |
Your SSH server's key is pinned on the phone at pairing. Whatever the path, a computer that presents a different key is refused (see Security).
Firewalls on the computer
Direct connections on your own network reach port 2222. Some distributions (Arch Linux, for one) ship a firewall that drops incoming connections; setup notices and prints the one command that allows the port. Rendezvous and relayed connections don't need it.