Run the relay on your own network (beta)

nfltr connects machines through a relay that every machine dials out to, so none of them needs an open port; nfltr orch uses it to run Claude Code agents on your own machines, driven by a hub that is your own Claude Code session. By default that relay is nfltr.xyz. People trying nfltr orch asked whether the path between their machines could stay in-house, because for some teams traffic between their own machines must not leave their network. Today, in beta, it can: nfltr relay serve on a VM of your own, and your machines connect to it instead.

What we found when we checked it: with nothing but one saved set-relay step per machine, orchestration, messages and files worked; share links, TCP tunnels and WireGuard were refused with a message; and in a network with no route out, nothing but the relay's own name was looked up once one STUN default was fixed. The check also found three bugs, fixed in the version this post describes. The beta has hard limits: one process and no dashboard. At first it also had one account per relay and no TCP tunnels; since 2026-10-26 each key you add is another account, and SSH and TCP tunnels work.

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: your own Claude Code with the hub tools (claude mcp add nfltr -- nfltr mcp --toolset hub). When this post was written, nfltr orch "<goal>" was a second way to start one; that launcher was removed in v2.1.20, and Claude Code with the hub MCP replaced it. 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 command you already install on your machines. Since v1.0.687 the relay is its own program, nfltr-relay, which nfltr relay serve runs; the install script adds it with --with relay (part 3 explains the split). 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.

The same relay also carries services between machines, not only orchestration; how a service on one machine is reached from a client on another with no inbound port is in Every service reachable from every remote client, with no inbound ports. That post is about the hosted relay: TCP tunnels are not in this beta (see the table below).

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.

Update 2026-10-09: hubs no longer send the relay these rows, on nfltr.xyz or on your own relay: the dashboard no longer reads hubs, and --dashboard-digest and the other dashboard flags are gone. Your relay stores nothing of your runs (why); they are seen in the hub, with nfltr orch hub runs and nfltr orch hub show on its machine and nfltr orch task ... while it runs.

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.

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, give the hub a goalWorks: 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 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

The table is the beta as released on 2026-10-03. Since 2026-10-26, SSH and TCP tunnels work on your own relay too (Limits).

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

Evidence: the features work with only the saved set-relay step

Setup
2026-10-03, the beta as released that day. Four Linux containers on one Docker network on one host, 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). The agent's model was a scripted stand-in for Claude Code.
Numbers
Six uses work, three are refused with the messages in the table. After a relay restart: same key and certificate, the node back within 12 seconds.
Reproduce
(a) With the released binaries, follow Run your own relay (beta) on two or more machines and try each row. (b) Our check, in the closed nfltr repository: make smoke-test-private-relay (Docker) runs every row, the two refusals of an unsafe start (no TLS on a network address, no key) and a wrong pin, at no model cost.
Limits
Containers on one host, not separate machines or networks. The stand-in checks nfltr's side, not model work. One pass of the table; the restart time is one restart.

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.

Nothing else leaves the network

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.

Evidence: no lookups or connections beyond the relay

Setup
2026-10-03, the same containers on an internal Docker network with no route out; one logging container was every container's only DNS server and default gateway, recording each name looked up and each TCP or UDP attempt.
Numbers
Before the fix: one outside lookup (Google's STUN server, by p2p). After it: no name but the relay's own looked up, no connection attempt out of the network, across every row of the table.
Reproduce
(a) Run your machines on a network whose DNS and gateway you log, then use each feature. (b) Our check, in the closed nfltr repository: the same make smoke-test-private-relay includes this check and fails on any other lookup or any connection attempt that reaches the logger.
Limits
Covers nfltr only, with a stand-in for Claude: a real run also reaches your model provider, and Claude Code has its own update and telemetry requests (the tutorial says how to turn them off). Checked for the features in the table, not for share links or tunnels, which the beta refuses.

Files and calls across NATs

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.

Evidence: p2p across cone and symmetric NATs

Setup
2026-10-03: your own relay (nfltr relay serve --tls-self-signed), coturn as the STUN and TURN server, and two LANs behind NAT routers in containers; a 100 MB file and a call per setup, six setups.
Numbers
Cone NATs with --stun: file and call direct. Symmetric NATs with TURN (on both sides, or issued by the relay): file and call through TURN. Without STUN, or symmetric NATs without TURN: the file arrives through your relay. The full table is in the tutorial.
Reproduce
(a) The tutorial's commands with your own coturn. (b) Our check, in the closed nfltr repository: make test-p2p-nat-lab-own-relay (Docker, $0).
Limits
Lab NATs on one host, not real carrier or corporate NATs; one transfer and one call per setup; no throughput measured.

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. Update 2026-10-26: each key added with nfltr keys generate is another account, and TCP tunnels and SSH work (the guide).
  • 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. Several replicas behind Kubernetes were tested on a local cluster only (part 4).
  • Not included: share links, WireGuard, automatic certificate renewal (restart the relay after renewing), Windows as the relay host. SSH and TCP tunnels were not included at first; they work since 2026-10-26.
  • Closed source. nfltr-relay is built from the closed relay-server repository, like the CLI; running it yourself does not change that. Since 2026-10-29 its session core (github.com/nfltr/relay-core), the client SDK and protocol (github.com/nfltr/relay) and link, under its data plane (github.com/nfltr/link), are public under Apache-2.0 (open source).

Is it for you?

Fits if your requirement is that orchestration traffic between your machines stays on your network, and what you need is in the "works" rows: nodes, a hub in your own Claude Code, orch task commands, messages, notifications and files, plus SSH and TCP tunnels and an account per added key since 2026-10-26. You can run a small Linux VM, its firewall and its certificate.

Not ready for teams that need share links or WireGuard on their own relay; a separate key per machine within one account; the dashboard; failover (one process, and hub hooks and schedules are lost on a restart); automatic certificate renewal; or a Windows relay host. It is a beta, the relay server and the CLI are closed source, and the hub is Claude Code only. If you want relay code you can read and change, relay-core is public and runs a small relay of its own (open source).

Try next the tutorial, from an empty Linux VM to a goal run by agents on your nodes, with the errors you may see: Run your own relay (beta). The relay itself starts with:

curl -fsSL https://nfltr.xyz/install.sh | sh -s -- --with relay
nfltr relay serve --data-dir /var/lib/nfltr-relay --tls-self-signed --tls-name relay.lan

then the set-relay step above on each machine, nfltr node join --max-agents 2 on the ones that run agents, and claude mcp add nfltr -- nfltr mcp --toolset hub where you run the hub. How fast that relay is against frp and other tunnels is part 2. 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