v0.4.1 · no backend server · no account to create
The machine is behind a firewall. You still get a root shell.
RelayKey administers Windows, macOS and Linux machines that have no public IP, no open port and no VPN — over a channel encrypted end to end between your account key and the machine's. There is no server of ours in the middle, because there is no server of ours.
The browser client installs nothing. It is the fastest way to see whether this works on your network.
One line. Your client generates the pair code and hands you that command; the machine calls your account back, both ends derive the same six digits, and you compare them by eye. That comparison is the whole of the trust decision — no password, no certificate authority, nothing to sign up for.
Who it is for
One operator, N machines that live in awkward places.
A Windows server in an office behind a consumer router. A Mac mini at a colleague's house. A Linux box on a carrier-grade NAT mobile connection. A kiosk in a shop with an ISP router nobody has the password for.
The conventional answers all need infrastructure you then own: a jump host, a VPN concentrator, a coordination server, or an inbound port forward that someone has to configure and keep secure. RelayKey needs none of them, and deliberately does not try to be a fleet-management platform: there is no org directory and no RBAC. It is a tool for one person who has to get into their own machines.
How it works
The wire, annotated.
Three parties, and only outbound connections. Below each one is what it can actually observe — including the part most tools leave out.
Endpoint
Your client
The macOS app, the Windows app, the CLI, or a browser tab. Holds your account key, made on first launch by the OS random source and exportable to an encrypted backup file.
Needs
An outbound WebSocket. No listening port, no inbound rule.
Shared infrastructure — not ours
Public message relays
Three to five independent public relays, run by other people, interchangeable and swappable in config. Every message is encrypted to the recipient, then sealed inside a second envelope signed by a throwaway key and stamped with a randomised timestamp — so a relay only ever carries ciphertext it cannot read.
Sees
That some never-reused key published an envelope addressed
to a public key, at a particular arrival time, of a particular size. Not the content,
and not who sent it. Caveat: arrival time and size are real metadata —
see below.
Endpoint
The machine
A Windows service, a launchd daemon or a systemd unit, as LocalSystem or root. It executes for peers it has paired with and silently ignores everything else.
Needs
An outbound WebSocket. Nothing forwarded to it, ever.
Then the channel upgrades
Relays are fine for “run this and show me the output” and hopeless for a screen: every message is a signed, double-encrypted envelope that round-trips through a relay. So for anything interactive, the relay channel carries only the WebRTC offer, answer and ICE candidates, and the session itself moves onto a data channel — directly between the two machines wherever the network allows it.
Caveat — when direct fails
Behind strict NAT or CGNAT a direct path may not exist, and the session falls back to a TURN relay. That relay forwards DTLS ciphertext it cannot decrypt — but it does observe both endpoints' IP addresses, when you connect, and how much traffic flows. You can point RelayKey at a relay you control instead: use your own relay.
-
Open a client and look at your account
First launch generates your account key. Settings → Account shows your Account ID — the short name for the account, safe to share — and the install command carrying the address machines pair to.
-
Run one command on the machine
The client mints a single-use pair code, valid for one hour, and writes the command for you.
relaykey.exe -install -paircode=abc123xxx -
Compare six digits
Both sides derive the same short authentication string from the code and both keys. If the digits match, the channel is authenticated and the code burns. If they do not, something is between you — do not continue.
What you get
A console, then real sockets.
Console
Commands as SYSTEM or root
PowerShell on Windows, /bin/sh on macOS and Linux, with streamed stdout and stderr on separate channels, cancellation that kills the whole process tree, and per-command timeouts.
Tunnels
Forward any TCP port
On the native clients, ssh localhost -p 2222 and an RDP client pointed at 127.0.0.1:33389 reach the machine's :22 and :3389 — no inbound firewall rule and no VPN.
Browser
SSH and RDP inside the page
A web page cannot open a listening socket, so the browser client does not forward a port — it runs the SSH and RDP clients in the tab and feeds them through the same data channel.
Egress
Browse from the machine's IP
A full browser running in your tab, egressing through the remote agent, so pages load from the remote machine's network position — for the admin panel that only answers on the LAN.
Files & services
Read a config, restart a unit
Fetch a file, edit it, write it back, and manage services from the machine detail view. Deliberately minimal — fs.read is capped, and this is not a sync tool.
AI interface
A read-only MCP server
The CLI client exposes an MCP server over stdio so an agent can list machines, ping them and read the audit log. No tool in it can run a command, write a file, or control a service.
Why no backend matters
Nothing to breach, nothing to bill, nothing to switch off.
“No backend” is not a slogan here, it is a property with three consequences a technical buyer can check.
There is no account database, so there is nothing of yours to leak. Your identity is an account key generated on your device by the OS random source. We do not have it, cannot reset it, and cannot be compelled to hand over a list of your machines, because no such list exists outside your own client.
The rendezvous layer is interchangeable. The message relays are public, accept messages from any account without registration, and there are dozens of them. If one disappears or blocks you, you change a config line. If you would rather not use public ones at all, point the agent at a private one you run.
Nobody's hosting bill is between you and your machines. The one place we do spend money is the shared TURN relay used when a direct connection is impossible, which is why that path is rate-limited and best-effort — and why bringing your own relay is a documented, first-class setting rather than an enterprise upsell.
Caveat — the honest cost
The same property is the reason there is no revocation broadcast. If
your client key is compromised you must revoke it on each machine individually
(relaykey peers revoke <public ID>, or “Forget machine” in the app).
relaykey peers list exists to make that enumerable. A tool with a server
would push one revocation and be done; this one cannot.
Download · v0.4.1
Two roles. Pick both.
An agent runs on a machine you want to control. A client
is what you drive it from. Assets are named
relaykey-<role>-<interface>-<os>-<arch>, where
gui is a double-click app and cli is headless — for servers and
services.
| Your computer | Get it | Signing |
|---|---|---|
| macOS Apple Silicon · arm64 | relaykey-client-gui-macos-arm64.zipunzip, drag RelayKey.app to Applications | Developer ID signed and notarised by Apple, with the ticket stapled — it opens without a Gatekeeper prompt. |
| Windows amd64 · arm64 | relaykey-client-gui-windows-amd64.exeor -arm64 on ARM | Not notarised, and not currently code-signed. SmartScreen will warn. Check it against SHA256SUMS in the release. |
| Browser any OS · phone · tablet | app.relaykey.netno download | Served over HTTPS. Re-trusted on every load, which is why extension signing is the recommended way to hold your key there. |
| That machine | Get it | Runs as |
|---|---|---|
| Windows easiest | relaykey-agent-gui-windows-amd64.exedouble-click, click Install | Service Control Manager, session 0, LocalSystem |
| Windows headless | relaykey-agent-cli-windows-amd64.exeor -arm64 | Service Control Manager, LocalSystem |
| macOS | relaykey-agent-cli-macos-arm64or -amd64 on Intel | LaunchDaemon, root |
| Linux | relaykey-agent-cli-linux-amd64or -arm64 | systemd unit, root |
Which arch?
Apple Silicon Macs and most ARM servers are arm64; older Intel and AMD
machines are amd64. Every release ships a SHA256SUMS file, and
the Unix installer served from the release refuses to install anything it cannot verify
against it.
Caveat — if you are on v0.4.0 or older
The relay fallback now requires a client to prove it holds your account key. Older clients cannot, so they lose the relay path — and behind strict NAT or CGNAT that means tunnels stop connecting. Update the client on your own computer, and update the agents too: v0.4.0 closed a hole where an already-paired machine could grant itself capabilities you had not given it, and the fix is on the agent side.
Security, stated plainly
This grants remote SYSTEM over the public internet.
The honest framing, and the one used in RelayKey's own security document, is that this is a remote access tool with the operator's consent, and it deserves to be designed like one — including being clear about what it does not protect against. If you are evaluating it, read this section before the feature list.
What is protected
Command and output confidentiality against relay operators and network observers. Authorisation: only paired peers can execute anything, and that mutual knowledge of each other's public key is the entire authorisation model. And the pairing moment, which is the only point where a secret crosses an untrusted path.
The sharp edge: the pair code
The pair code is 8 characters — short because it has to be typed, pasted into an install command, and sometimes read aloud. Anyone who obtains it while it is live can pair with the machine and thereby gain SYSTEM. That is inherent to having no server to authenticate against, not an oversight, and it is bounded by six layered controls: single use, a one-hour expiry, proof-of-work on the enrolment beacon, a 20-attempt budget after which the agent burns the code and logs loudly, handshake HMACs proving both sides hold the code, and the six-digit string you compare by eye.
Proof-of-work is a cost multiplier, not a wall — someone with a hundred machines gets a hundred times the guesses. The attempt budget is the hard cap. And if the code leaks, the attacker pairs first, and you never look at the machine's console, the machine is compromised. The mitigation is operational: generate the code on the machine, use it immediately, check the digits.
What a message relay learns
For each message, a relay sees that some key published an envelope addressed to a recipient, at a particular arrival time, of a particular size. The outer signing key is fresh every time, so envelopes cannot be grouped by sender, and the timestamp the sender writes on the envelope is randomised into the previous 48 hours. But traffic analysis by timing and volume is not defeated: arrival time at the relay is real, a relay operator watching a live connection sees a request arrive and a response depart shortly after, and correlating a burst of envelopes to one public key with a burst to another plausibly reveals that two parties are in session. Size leaks too — the encryption layer pads onto a coarse ladder, which blurs but does not hide the difference between an idle keepalive and a 24 KB output chunk. Publishing to four independent relays helps only against any single one of them.
The explicit non-guarantees
- No forward secrecy. Encryption uses static ECDH between long-term keys. An attacker who records traffic today and obtains a private key later can decrypt what they recorded.
- No post-compromise security. Once a key leaks, every future message is readable until you re-pair.
- No revocation broadcast. Revoking is local state on each machine. A stolen client means visiting every machine.
- No protection against a relay withholding messages. A relay can silently drop; your client sees a timeout. Using several independent relays is the only mitigation.
- No sandbox. Commands run with the service's full privileges, by design.
- No metadata hiding at the timing and volume level. See above. Padding everything to a fixed size would make the tool unusably slow on relays that rate-limit by bandwidth.
- The command denylist is not a security boundary, and the code, docs and CLI help all say so. Anyone who can run one command as SYSTEM can rewrite the config. Its job is to catch a mistake, not an adversary.
Two more things worth knowing before you deploy
The audit log records full command text, including any secret you paste
into a command. That is a deliberate trade — an admin tool with no record of what was run
is unauditable — and the log lives in a SYSTEM/root-only directory. Set
log.audit: false to log metadata without command bodies.
Remote self-update of the agent is off by default. It requires an explicit config change on the machine and verifies a signature over the release artifact. It is the highest-value target in the system and is treated as such.
Your exported account file is the account. The default export format is passphrase-encrypted (scrypt + XChaCha20-Poly1305, tuned to about a second), export requires re-authentication, and the bundle carries your peer list as well as the key — which is a further reason the whole payload is encrypted rather than just the key. Restoring it on a new machine does not invalidate the old copy: both hold the same key, and both work.
Licensing
Free for five machines. A licence raises the number.
Every client enforces a default allowance of five paired machines with no licence at all — not a trial, and not a reduced feature set. A licence does exactly one thing: it raises that number for your account. Entitlement is keyed to your Public ID, so it follows your account rather than a device, and moves with it when you restore on a new machine.