Run Your Own Relay (Beta)
Beta. By default your nodes and hubs meet on nfltr.xyz. You can instead run the relay on a VM or machine of your own and join your machines to it, so the path between them stays on your network. It is the same nfltr binary: nfltr relay serve. You bring the TLS certificate; the relay creates its API key. This tutorial goes from an empty Linux VM to a goal run by agents on your nodes. Everything else on this site describes nfltr.xyz.
nfltr.xyz or your own relay
The relay carries messages between hubs, nodes and agents. It runs no model: the hub is Claude, on the machine where you start it, and agents run on your nodes. Nodes and hubs connect out to the relay, so only the relay needs an open port.
| nfltr.xyz | Your own relay (beta) | |
|---|---|---|
| Who runs it | We do: updates, certificates, uptime. | You do: a VM, its firewall, its certificate, upgrades and backups. |
| Where traffic goes | Through nfltr.xyz. | Through your relay. Your machines need to reach it; nothing else does. |
| Accounts and keys | Your account, with a key per machine if you want. | One account and one API key per relay, shared by your machines. |
| Dashboard | Yes, with Google sign-in. | No. Everything below works from the CLI. |
| Share links, SSH and TCP tunnels, private LAN | Yes. | Not in the beta (see below). |
| Availability | Our service. | One process on one machine: no failover. Nodes reconnect by themselves after a restart. |
| Software | The same closed-source nfltr binary. | |
Use your own relay when the requirement is that orchestration traffic between your machines does not leave your network, and the features in the next table are the ones you need. If you need share links, SSH or the dashboard, use nfltr.xyz.
What works on your own relay
Checked on 2026-10-03 with four Linux containers on one Docker network, each standing in for a machine: a relay with a self-signed certificate (pinned by the others), a node, a hub machine, and a second relay with a certificate from a private CA (no pin). Every command below ran with no relay flags, only the saved set-relay step.
| Use | Result | What was checked |
|---|---|---|
nfltr node join and nfltr orch "<goal>" | Works | The hub spawned an agent on the node; the agent completed with its result. |
The hub in your own Claude Code (claude mcp add nfltr -- nfltr mcp --toolset hub) | Works | The server Claude Code starts lists the node, spawns an agent there and returns its completion. (A script played Claude Code.) |
nfltr orch nodes list, orch doctor, orch task list, nfltr status | Works | Each answers from your relay. |
nfltr a2a send / listen, nfltr notify send / listen | Works | The message and the notification arrived on the other machine. |
nfltr p2p send / recv / call | Works; across NATs with your STUN and TURN | On one network: a direct connection. Across NATs (a separate lab with cone and symmetric NATs, section 9): direct when both sides name your STUN server, through your TURN server between symmetric NATs, otherwise files go through your relay. Every path is end-to-end encrypted: your relay and TURN server carry only ciphertext. |
| A certificate from your CA | Works | set-relay without a pin; messages across it. |
nfltr http, nfltr share, tail, watch | Not supported | The relay refuses share links: shares need http.share_domain. |
nfltr tcp, nfltr shell, SSH behind NAT | Not supported | The relay refuses: tcp tunneling is not enabled on this server. |
nfltr wg (private LAN) | Not supported | Refused: the relay does not run end-to-end WireGuard. |
1. Prepare a Linux VM
Any small Linux VM or machine that your other machines can reach, amd64 or arm64. Install the CLI as on any machine (Getting Started, step 2), copy it where every user can run it, and give the relay its own user and data directory:
$ curl -fsSL https://nfltr.xyz/install.sh | sh
$ sudo install -m 755 ~/.local/bin/nfltr /usr/local/bin/nfltr
$ sudo useradd --system --create-home --home-dir /var/lib/nfltr-relay nfltr-relay
$ sudo chmod 700 /var/lib/nfltr-relay
The relay listens on two TCP ports: 8443 (gRPC: nodes, hubs, agents) and 8444 (HTTPS: task API, artifacts). Open them to your machines only, for example with ufw:
$ sudo ufw allow from 10.0.0.0/8 to any port 8443,8444 proto tcp
Nothing else needs to be reachable: the admin API, health and metrics listen on 127.0.0.1 (on ports the relay picks and writes to <data-dir>/ports.json). --grpc-port and --http-port change the two public ports; --listen binds one address instead of all.
2. Choose the TLS certificate
The relay does not listen on the network without TLS. Pick one:
- A certificate your machines already trust (your company CA, or a public one such as Let's Encrypt via certbot) for the name your machines use, for example
relay.example.com. Your machines need no pin. Put the PEM files where the relay user can read them, e.g./etc/nfltr-relay/fullchain.pemandprivkey.pem(mode 0640, groupnfltr-relay). - A self-signed certificate that the relay creates once and keeps in
<data-dir>/tls(ten years). Your machines pin its SHA-256 fingerprint: they trust exactly that certificate, and any other host is verified as before. List every name and IP your machines use with--tls-name.
3. Start the relay
Start it once in the foreground as the relay user to create the key and see the banner. With your certificate:
$ sudo -u nfltr-relay nfltr relay serve --data-dir /var/lib/nfltr-relay \
--tls-cert /etc/nfltr-relay/fullchain.pem --tls-key /etc/nfltr-relay/privkey.pem
Or self-signed:
$ sudo -u nfltr-relay nfltr relay serve --data-dir /var/lib/nfltr-relay --tls-self-signed --tls-name relay.lan,192.168.1.10
nfltr relay (beta): gRPC 0.0.0.0:8443, HTTPS 0.0.0.0:8444, data /var/lib/nfltr-relay
API key: /var/lib/nfltr-relay/admin-api-key (created now; copy it to your machines, it is not printed)
TLS certificate SHA-256: 3f1c…9a07
On each machine: nfltr config set-relay relay.lan:8443 --proxy-url https://relay.lan:8444 --cert-sha256 3f1c…9a07 - < admin-api-key
Secure defaults, with no flags to turn them off: every client needs the API key; without TLS the relay refuses any address but loopback (--listen 127.0.0.1, for a TLS proxy of your own in front); a data directory other users can read is refused. Stop it with Ctrl+C and run it as a service:
# /etc/systemd/system/nfltr-relay.service
[Unit]
Description=nfltr relay (beta)
After=network-online.target
[Service]
User=nfltr-relay
ExecStart=/usr/local/bin/nfltr relay serve --data-dir /var/lib/nfltr-relay --tls-cert /etc/nfltr-relay/fullchain.pem --tls-key /etc/nfltr-relay/privkey.pem
Restart=on-failure
[Install]
WantedBy=multi-user.target
$ sudo systemctl enable --now nfltr-relay
$ journalctl -u nfltr-relay | grep 'TLS certificate SHA-256'
For the self-signed form, use the --tls-self-signed --tls-name … flags in ExecStart instead of the certificate files. Ports below 1024 need extra capabilities; keep the defaults.
4. The API key file
The first start wrote the account key to /var/lib/nfltr-relay/admin-api-key (mode 0600) and only its SHA-256 to api-keys. It is never printed, logged or put on a command line. Copy the file to each machine that joins (scp, your secrets manager) and keep it out of shell history and chat. Every machine uses this one key: the beta has one account per relay.
5. Point each machine at the relay
On every node and on the machine where you run the hub, one step saves the relay, the pin (self-signed only) and the key, which - reads from stdin:
$ nfltr config set-relay relay.lan:8443 --proxy-url https://relay.lan:8444 \
--cert-sha256 3f1c…9a07 - < admin-api-key
Relay relay.lan:8443 saved (/home/you/.config/nfltr/nfltr.json)
$ rm admin-api-key
$ nfltr status
Leave out --cert-sha256 for a certificate your machines trust. From now on every nfltr command on that machine uses your relay, unless NFLTR_SERVER or NFLTR_PROXY_URL in the environment names another one. NFLTR_RELAY_CERT_SHA256 overrides the saved pin. nfltr config set-relay --reset goes back to nfltr.xyz (saved keys stay).
6. Join nodes
On each machine that should run agents, with Claude Code installed and its credentials in the environment, exactly as on nfltr.xyz (Join machines as nodes):
$ export CLAUDE_CODE_OAUTH_TOKEN=… # from `claude setup-token`, or ANTHROPIC_API_KEY
$ nfltr node join --max-agents 2 --allow-all-tools
Then, from any machine pointed at the relay:
$ nfltr orch nodes list
$ nfltr orch doctor
orch doctor names where the relay came from, e.g. configured: relay.lan:8443 (from saved config /home/you/.config/nfltr/nfltr.json).
7. Run a goal
$ nfltr orch "fix the flaky parser test and push a branch"
The hub runs on this machine and spawns agents on your nodes through your relay. Watching, steering and stopping work as described in Orchestrate a task. To see what your relay holds about the agents:
$ nfltr orch task list --include-completed
8. From your own Claude Code
The same two commands as on nfltr.xyz (Use nfltr from Claude Code). The server Claude Code starts reads the saved relay, pin and key; nothing goes in the MCP config:
$ cd ~/src/my-project
$ claude mcp add nfltr -- nfltr mcp --toolset hub
$ nfltr orch hub install-hook --prefer-agents
$ claude
9. Messages and files between your machines
These work across your relay as in Send files and messages. On the receiving machine:
$ nfltr a2a listen --name work-laptop
$ nfltr notify listen --name work-laptop-notes
$ nfltr p2p recv --name work-laptop-files --output ./inbox
From another machine:
$ nfltr a2a send work-laptop "deploy finished"
$ nfltr notify send work-laptop-notes "Build finished" --title CI
$ nfltr p2p send report.txt work-laptop-files
On one network, p2p connects directly. Between networks behind NAT, each side needs its public address from a STUN server, and with your own relay p2p asks none unless you name one. Run your own (for example coturn) and pass it on both sides:
$ nfltr p2p recv --name work-laptop-files --output ./inbox --stun stun.example.com:3478
$ nfltr p2p send report.txt work-laptop-files --stun stun.example.com:3478
Or set STUN_SERVER on each machine. Without a STUN server, or when no direct path exists, a file still arrives, through your relay. Machines behind symmetric NATs (common on mobile and corporate networks) have no direct path: a TURN server carries their files and calls instead of your relay, and a call between them needs one. Give it one of two ways:
- On the relay: start
nfltr relay servewithP2P_TURN_URLS=turn:turn.example.com:3478andP2P_TURN_SECRET(the TURN server's shared secret: coturnuse-auth-secretwith the samestatic-auth-secret, at least 16 bytes) in its environment, for example from a 0600EnvironmentFile=in the service. The relay gives each session a short-lived credential (P2P_TURN_TTL, default 1h); the machines need nothing more. - On the machines:
--turn turn:turn.example.com:3478on both sides, withNFLTR_TURN_USERNAMEandNFLTR_TURN_CREDENTIALin the environment. It wins over the relay's.
Checked on 2026-10-03 in a lab with your relay (relay serve --tls-self-signed), coturn as the STUN and TURN server, and two LANs behind NAT routers, a 100 MB file and a call each:
| Machines | Setup | File | Call |
|---|---|---|---|
| One network | none | direct | — |
| Behind two cone NATs | no STUN | through your relay | — |
| Behind two cone NATs | --stun | direct | direct, video and audio both ways |
| Behind two symmetric NATs | --stun, no TURN | through your relay | — |
| Behind two symmetric NATs | --turn on both sides | through TURN | through TURN, video and audio both ways |
| Behind two symmetric NATs | TURN on the relay | through TURN | through TURN, video and audio both ways |
A call with no path between the two machines keeps its text chat, and both pages say video failed.
What your relay stores
The hub sends the relay a status summary of its agents: state, machine, timing and token counts. Prompts, progress and results stay on the hub's machine (--dashboard-digest off on nfltr mcp or nfltr orch sends none). On your relay there is no dashboard; nfltr orch task list reads that summary. It is kept in memory and is gone after a relay restart. Tasks, artifacts and keys are on disk under the data directory.
What leaves your network
With your own relay, nfltr contacts nothing but your relay on its own: not nfltr.xyz, and no other service of ours or anyone else's. Checked on 2026-10-03 with the same containers as the table above, on a Docker network with no route out. Their only DNS server and gateway was a logger that recorded every name looked up and every connection attempt, while every row of that table ran:
- The relay, the node, the hub machine (
nfltr orch, the hub server Claude Code starts,orch task,a2a,notify,p2p) looked up no name but the relay's own, and attempted no connection out of the network. p2pasks no public STUN server for your address unless you name one with--stun(on nfltr.xyz it uses Google's).
What still goes out, and only because you set it up:
- Your git origin, when agents clone or push.
- Your model provider, from the machines that run Claude: the hub's machine and your nodes. The check used a scripted stand-in for Claude, so it made none. Claude Code also has its own update and telemetry requests; set
CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC=1on those machines to turn them off. - Your STUN and TURN servers, when you name them for
p2p(--stun,--turn, or the relay'sP2P_TURN_URLS): the machines, and the browser during a call, contact them directly. TURN carries files and calls that have no direct path, end-to-end encrypted (it cannot read them); your relay only hands out its credentials. nfltr updatedownloads releases fromstorage.googleapis.com/nfltr-downloads, only when you run it, and says so first when your own relay is configured. Nothing in nfltr checks for updates by itself. To keep the relay's VM offline, copy the binary to it instead.nfltr config loginsigns in to nfltr.xyz; you do not need it with your own relay.
Restart, upgrade, back up
- Restart (
sudo systemctl restart nfltr-relay): the key and the self-signed certificate stay the same, and joined nodes reconnect by themselves (in the check above, within 12 seconds). Restart after replacing certificate files: the relay does not reload them. - Upgrade:
sudo nfltr update --apply(or the two install commands again), then restart. Upgrade the machines' CLIs the same way. - Back up: stop the relay and copy
/var/lib/nfltr-relay(key files,orchestration-state/,artifact-store/, andtls/when self-signed): the key, the certificate and the task store all live there. - New key: stop the relay, delete
api-keysandadmin-api-key, start it, and run theset-relaystep on each machine again. New self-signed certificate: deletetls/the same way; machines need the new pin.
Not supported in the beta
- Share links and public URLs (
nfltr http,share,tail,watch):shares need http.share_domain: agent content is served only on its own origin. - TCP tunnels and SSH behind NAT (
nfltr tcp,shell,tcp-connect,ssh-proxy):tcp tunneling is not enabled on this server. - WireGuard private LAN (
nfltr wg):the relay does not run end-to-end WireGuard (x-wg-protocol: e2e-v1). - The dashboard and Google sign-in; several accounts or per-machine keys; high availability or several relays; Postgres or Redis; hub hooks and schedules across a relay restart; automatic certificate renewal; Windows as the relay host.
Troubleshooting
| The CLI prints | Cause and fix |
|---|---|
relaytrust: certificate 623f…c7c9 is not the pinned relay certificate and does not verify: x509: certificate signed by unknown authority | The saved pin (or NFLTR_RELAY_CERT_SHA256) is not the relay's certificate, e.g. after tls/ was recreated. Run set-relay again with the fingerprint from the relay's log. |
tls: failed to verify certificate: x509: certificate signed by unknown authority | A self-signed relay and no pin on this machine: add --cert-sha256 to set-relay. With your own CA, install the CA in the machine's trust store. |
--cert-sha256: certificate fingerprint "…": want the 64 hex digits of a SHA-256 | The fingerprint was cut or mistyped. Copy the whole line from the relay's log. |
no API key for relay relay.lan:8443 or an account API key is required | No key saved on this machine: run set-relay with - < admin-api-key. |
list nodes: HTTP 403: invalid API key | The key is not this relay's, e.g. after a key rotation or an NFLTR_API_KEY left in the environment. Unset it, or run set-relay again with the current key file. |
dial tcp 192.168.1.10:8443: connect: connection refused | The relay is not running or the firewall blocks the port: check systemctl status nfltr-relay and the ufw rule. |
refusing to listen on 0.0.0.0 without TLS: give --tls-cert and --tls-key, or --tls-self-signed (or --listen 127.0.0.1 behind your own TLS proxy) | Started without a certificate. Add one of the TLS forms from step 2. |
data dir /var/lib/nfltr-relay is open to other users (mode 755): chmod 700 /var/lib/nfltr-relay | Run the chmod it names. |
Related: Join machines as nodes · Use nfltr from Claude Code · Troubleshooting.