Run the relay on your own network (beta)

A question from people trying nfltr orch on their own machines: can the path between those machines stay in-house? Until now every node and hub met on nfltr.xyz. Today, in beta, you can run that meeting point yourself: nfltr relay serve on a VM of your own, and your machines connect to it instead.

What it is

The relay is transport. It carries messages between a hub, the nodes joined to it and the agents they start; it runs no model. The hub is a Claude session on the machine where you start it (nfltr orch "<goal>", or your own Claude Code with the hub tools), and agents are Claude Code processes on your nodes. Nodes and hubs open outbound connections to the relay, so the relay's machine is the only one that needs open ports: two TCP ports, 8443 and 8444 by default.

It is the same nfltr binary you already install on your machines. You bring the TLS certificate, either one your machines already trust or a self-signed one the relay creates and your machines pin by fingerprint. The relay creates one API key on its first start and writes it to a file readable only by its user; it never prints or logs it. Each machine then runs one step:

nfltr config set-relay relay.lan:8443 --proxy-url https://relay.lan:8444 \
    --cert-sha256 <fingerprint> - < admin-api-key

After that step, every nfltr command on that machine uses your relay. Some defaults cannot be turned off: every client needs the key; without TLS the relay listens only on loopback; its admin API, health and metrics listen only on 127.0.0.1.

What your relay stores

On nfltr.xyz, the hub sends the relay a status summary of its agents for the dashboard: state, machine, timing and token counts, with prompts, progress and results left on the hub's machine unless you opt in. We checked whether that still applies when there is no dashboard. It does: on your own relay the hub sends the same status rows. Nothing shows them in a browser; nfltr orch task list --include-completed reads them. Our check read the raw rows and found no prompt, progress, result or error text in them. They are kept in memory and are gone after a relay restart. --dashboard-digest off stops them.

What we checked

On 2026-10-03 we ran the relay with a self-signed certificate on a non-loopback address, plus a second relay with a certificate from a private CA, and used each feature from other machines with no relay flags, only the saved set-relay step. The machines were Linux containers on one Docker network, and the agent was a scripted stand-in for Claude Code, so the check covers nfltr's side, not model work.

Each feature with no relay flag, on 2026-10-03. "Refused" means the relay or CLI says so, with the message shown.
UseResult
Join a node, run a goal with nfltr orchWorks: the agent ran on the node and completed
The hub in your own Claude CodeWorks: the hub server listed the node, spawned an agent there and returned its completion
orch nodes, orch doctor, orch task listWorks
Messages and notifications (a2a, notify)Works
Files with p2pWorks on one network (a direct connection); across NATs, see the update below
A certificate from your own CAWorks, no pin needed
Share links (nfltr http, share)Refused: shares need http.share_domain
SSH and TCP tunnelsRefused: tcp tunneling is not enabled on this server
WireGuard private LANRefused: the relay does not run end-to-end WireGuard

We also restarted the relay: the key and the certificate stayed the same, and the joined node reconnected by itself within 12 seconds.

Checking found three gaps, fixed in the version this post describes. Commands that do not start or join a hub, such as nfltr http, ignored the saved relay and went to nfltr.xyz with your relay's key, which nfltr.xyz rejected; now every command reads the saved relay. nfltr orch task list did not use the saved certificate pin. And share requests went to the wrong port, so the CLI showed a connection error instead of the relay's refusal.

Then we ran every row again on a Docker network with no route out, where the only DNS server and gateway logged each lookup and connection attempt. One more gap showed up: p2p looked up Google's public STUN server, its default on nfltr.xyz. With your own relay it now asks none unless you pass --stun. After that fix, nothing looked up a name but the relay's own and nothing tried to leave the network. Your git origin, your model provider and nfltr update are the traffic you set up yourself; the tutorial lists them under What leaves your network.

Update: p2p across NATs is now checked too, in a lab with cone and symmetric NATs and your own STUN and TURN server. Files and calls connect directly when both sides name your STUN server (--stun) and through your TURN server between symmetric NATs; otherwise files go through your relay. The setup is in the tutorial, Messages and files between your machines.

Limits

  • Beta. The commands and files may change before it is final.
  • One account per relay: one API key, shared by your machines. No per-machine keys and no second account.
  • No dashboard and no Google sign-in. Everything above works from the CLI.
  • No high availability: one process on one machine, with its state on that machine's disk. No Postgres or Redis, and hub hooks and schedules do not survive a relay restart.
  • Not included: share links, SSH and TCP tunnels, WireGuard, automatic certificate renewal (restart the relay after renewing), Windows as the relay host.
  • Closed source. The relay is the same closed-source nfltr binary as the CLI; running it yourself does not change that.

Try it

The tutorial goes from an empty Linux VM to a goal run by agents on your nodes: certificate, firewall, the key file, the set-relay step, nodes, nfltr orch and your own Claude Code, and the errors you may see: Run your own relay (beta).

nfltr relay serve --data-dir /var/lib/nfltr-relay --tls-self-signed --tls-name relay.lan

This is a beta so that we hear what breaks. If you run it, tell us what you ran it on, what went wrong, and which of the missing pieces (share links, SSH, the dashboard, several keys) you need first.

← All posts