nfltr with the tools you already run
Parts 4 to 8 of this series each took one thing people run at home or in a small office, set it up the usual way, set it up again with nfltr, and ran both through the same test: Home Assistant, a model server on a GPU box, Caddy and Traefik in front of several services, Tailscale, and a Pi-hole. Parts 1 to 3 did the same for an organization's services and a .NET gRPC fleet. Each part is long because it carries its evidence.
This part is the map. Start from what you run, find the part that measured it, see what nfltr replaced there, the numbers, what the test left out, and where something other than nfltr is the better choice. Every number below comes from those parts; nothing was measured again for this post.
Three ways in
Every case comes down to who has to connect.
- A browser or a phone app that installs nothing.
nfltr upgives the service an unlisted HTTPS link (anhttp:service). TLS ends on the home machine, so the relay forwards bytes it cannot read. Parts 4 (Home Assistant) and 6 (a reverse proxy) use it. The link is a random name on the relay; each visit keeps it alive for another day, and a link nobody opens for a day ends, so the next start ofnfltr upprints a new one. - Your own machine, which runs nfltr too. The service is a
tcp:service withe2ee: true, and the other machine'snfltr upmaps it to a local port, pinned to the service's certificate (aconnect:mapping), or a program runsnfltr dial. Only your account reaches it. Parts 2 (a gRPC fleet), 5 (a GPU box) and 8 (a Pi-hole) use it. - All your devices, to each other, on every port. That is a mesh VPN, and nfltr is not one. Part 7 ran Tailscale beside nfltr on the same machine.
In both nfltr cases each end connects out to the relay, so nothing at home needs a public address or a forwarded port, behind carrier-grade NAT too.
Pick your case
| you run | used from | the usual setup nfltr replaced | part |
|---|---|---|---|
| Home Assistant, or one web app | a phone or browser anywhere | a router port forward, DuckDNS, Caddy with Let's Encrypt | 4 |
| a model server (Ollama, vLLM) | your laptop | a port forward, dynamic DNS, an HTTPS proxy with a token; behind carrier-grade NAT, a rented VM and a reverse SSH tunnel | 5 |
| Caddy or Traefik in front of several services | browsers and phones | only the public entry: the port forward, dynamic DNS and the proxy's certificates; its routes, login and headers stay | 6 |
| devices on a tailnet | people outside it | nothing: nfltr runs beside Tailscale | 7 |
| a Pi-hole | your laptop away from home | a WireGuard VPN home (PiVPN, wg-easy), a forwarded UDP port, dynamic DNS | 8 |
| gRPC services on many machines | your own clients and control plane | a public TLS endpoint, a private CA and the client's TLS code | 1, 2, 3 |
The numbers side by side
Each test measured what its users feel, so the latency column measures a different thing on each row: compare a row's usual path with its nfltr path, not one row with another. Every test ran on one host. Home Assistant and the gRPC fleet had no added network delay; the others had a home router that adds 10 ms each way, and the relay sat next to the client. All latencies are p50.
| case | open at home, usual → nfltr | latency, usual → nfltr | answering again after a restart of the home side, usual → nfltr | lines of configuration, usual → nfltr |
|---|---|---|---|---|
| Home Assistant | ports 80 and 443, 4 router rules → none | REST call 0.14 → 0.16 ms | not measured → 0.8 s, same link | 16 → 9 |
| GPU box | 2 listeners, 2 router rules → none | first token 35.2 → 34.4 ms | 263 → 264 ms | 20 → 21 (25 with a private relay) |
| Caddy | ports 80 and 443, 4 router rules → none | GET 22.8 → 22.9 ms | 0.4 → 0.6 s | 28 → 27 |
| Traefik | the same → none | GET 22.5 → 21.9 ms | 0.6 → 0.8 s | 46 → 32 |
| Tailscale, beside nfltr | none either way | open connection 23.3 and 23.3 ms; new connection 47.1 and 72.7 ms | not measured | 16 for Tailscale with Tailscale's hosted control server, 24 for nfltr with the hosted relay |
| Pi-hole | 1 forwarded UDP port → none | cached query 23.3 → 24.9 ms | 18.4 → 0.18 s | 32 → 30 (34 with a private relay) |
| .NET gRPC fleet | 1 public listener, 1 private CA → none | +0.13 to +0.28 ms per call | 593–595 → 338–347 ms | one line of the channel changed, a 51-line TLS client deleted |
Four things follow.
Open ports went to zero wherever there were any. In every case that had a forwarded port or a public listener, the nfltr setup had none, and the router had no inbound rule. Tailscale had none either; that is not where the two differ.
An open connection costs about the same; a new one costs more. On a connection that is already open, every nfltr path was within 1.6 ms of the usual one. A new connection is a new end-to-end TLS session through the relay: 25.6 ms more than Tailscale's direct path in part 7, and 74.4 ms per DNS query when each query opened its own connection in part 8, which is why the Pi-hole setup keeps one open. The relay sat next to the client in every test. A relay far from both machines adds its distance to every round trip; a direct path, such as Tailscale's between two devices, adds none.
Restarts came back within about a second. The home side's nfltr process, killed and started, was answering again within 0.18 to 0.8 s in the runs above (0.6 to 1.6 s across both runs of the reverse proxy test). The largest gap was WireGuard's 18.4 s in part 8: it kept using its old session until its handshake timed out.
Configuration is not always shorter. It was shorter for Home Assistant and Traefik, and about the same for Caddy, the GPU box (one line more) and the Pi-hole (two lines fewer, with the hosted relay), where creating the box's certificate, copying its pin to the laptop and, for the Pi-hole, the laptop's stub resolver take most of the room. The Pi-hole setup also has one more moving part than the VPN (six against five). What changes more than the count is where the parts face: the usual parts face the internet, and nfltr's face only the relay.
What each test left out
- Home Assistant: no real mobile network. Home Assistant Cloud and Cloudflare Tunnel, which also need no port forward, were not tested. A share password does not stack on the app's own login, because the app sends its own
Authorizationheader, so Home Assistant's login stays the gate. - GPU box: a stand-in model that streams tokens, no GPU. A real model's time to first token is mostly its prompt processing, which dwarfs every difference above.
- Caddy and Traefik: stand-in services that report what they received, Basic auth only; a forward-auth middleware was not tested. Behind nfltr the services see
Hostas the home name and the visitor's address first inX-Forwarded-For, which needs one trust line in the proxy. - Tailscale: Funnel and device sharing were not tested. The client ran in userspace mode, which adds a SOCKS5 hop on the laptop that the desktop client does not have.
- Pi-hole: phones, nfltr's WireGuard mode and DNS over HTTPS were not tested, and the stub resolver only on Linux.
- gRPC fleet: one small fleet in one language, written for the comparison; only grpc-go was measured in part 3. Windows code has Windows-only tests but no Windows CI runner yet.
- All of them: one host, so no packet loss and no real distance; two runs each, which is no distribution.
Where something else is the better choice
- A network of your own devices. Many devices that all reach each other, on every port, under one policy, or a whole subnet routed in: that is what Tailscale is built for. nfltr has no address per device, no name for every device and no direct path between devices; every session crosses the relay. Tailscale relays through its DERP servers only as "a fallback option when a direct connection isn't possible" (DERP servers, read October 31, 2026). For a whole LAN,
nfltr wg servereaches only the destinations one machine on it allows. - Phones beyond a browser. There is no nfltr app for iOS or Android. A phone opens a share link, as in parts 4 and 6, but it cannot run a mapping. For a phone's DNS, Android's Private DNS speaks DNS over TLS to a hostname on port 853 (Android's developer blog and RFC 7858, read November 1, 2026), which a share link on 443 cannot be: a VPN home or a hosted filtering resolver fits there.
- A name that never changes. A DuckDNS name or your own domain stays the same for years. An nfltr link is a random name on the relay's share domain, and one left unused for a day is replaced. If a bookmark must survive weeks unused, if your apps must see their public name in
Host, or if your proxy must hold the public certificate itself, keep the direct path. - A public IPv4 address and an open port you accept. Then the usual setup does the job and can cost nothing in money: DuckDNS is free and so is Let's Encrypt.
- Home Assistant's voice assistant integrations need Home Assistant Cloud.
- Sharing a mapped service with people outside your account, such as the GPU box's model server: a mapping reaches only services in your own account.
- Paths that cannot take the trip to the relay. Every nfltr session goes through it.
What it costs
nfltr is free until further notice. Each part priced, with our cost ledger at public cloud list prices, what relaying its traffic for an assumed month costs whoever runs the relay. These are costs at list prices, not prices.
| case | the assumed month | Google Cloud | Hetzner |
|---|---|---|---|
| Home Assistant | connected all month, 20 opens a day, 0.0356 GiB | 0.016 USD | 0.0003 EUR |
| GPU box | 6,000 streamed answers, 0.6 GiB, two agents | 0.087 USD | 0.0011 EUR |
| Caddy or Traefik | two agents, 30,000 requests, 10 GiB | 1.45 USD | 0.013 EUR |
| Tailscale, beside nfltr | three agents, 2 GiB, 1,000 link visits | 0.27 USD | 0.0029 EUR |
| Pi-hole | 150,000 queries, 0.02 GiB, two agents | 0.017 USD | 0.0005 EUR |
The usual setups cost nothing in money with a public IPv4 address. Behind carrier-grade NAT they need a rented VM, from 4 USD a month at DigitalOcean (read October 31, 2026). Tailscale's Personal plan costs nothing for up to 6 users and non-commercial use (pricing, read October 31, 2026).
Evidence: where each number on this page comes from
- Setup
- No new measurement. Every number is from the evidence blocks of parts 2 and 4 to 8 and the example tests behind them, each run as Linux containers on one Mac (Apple Silicon) with Docker: the .NET fleet on October 16, 2026; Home Assistant, the GPU box, the reverse proxies and Tailscale on October 31; the Pi-hole on October 31 and November 1. Home Assistant and the fleet had no added network delay; the others had a home router adding 10 ms each way (tc netem), and the relay sat next to the client. The configuration counts for Caddy and Traefik are from the reverse proxy example's results, which part 6 did not print.
- Numbers
- Open at home, usual to nfltr: 2 ports to 0 (Home Assistant, Caddy, Traefik), 2 listeners to 0 (GPU box), 1 forwarded UDP port to 0 (Pi-hole), 1 public listener and 1 private CA to 0 (fleet), 0 and 0 (Tailscale). Latency p50, usual to nfltr: 0.14 to 0.16 ms, 35.2 to 34.4 ms, 22.8 to 22.9 and 22.5 to 21.9 ms, 23.3 and 23.3 ms (47.1 and 72.7 ms for a new connection), 23.3 to 24.9 ms, +0.13 to +0.28 ms. Back after a restart: 0.8 s; 263 and 264 ms; 0.4 and 0.6 s to 0.6 and 0.8 s; 18.4 to 0.18 s; 593–595 to 338–347 ms. Configuration lines: 16 to 9, 20 to 21, 28 to 27, 46 to 32, 16 and 24, 32 to 30.
- Reproduce
- (a) With the released binaries: each part's own Reproduce line, starting from the files printed in that part. (b) Our checks, in the closed nfltr repository: each example's end-to-end test, which runs both setups in containers and judges each claim by an exit code.
- Limits
- The latency rows measure different things (a REST call, a first token, a GET, an echo, a DNS query, a gRPC call), so compare within a row. One host, so no loss and no real distance; two runs per setup. The costs cover relaying only, at list prices, for assumed months; prices change, and each one names the date it was read.
Is it for you?
Fits if you run one or a few services at home, in a small office or on machines you do not control, and the people who use them either open a browser that installs nothing or sit at your own machines that can run nfltr up, and you would rather not forward ports, keep a dynamic DNS name current or need a public IPv4 address at all. The tools you already run stay: Home Assistant keeps its login, your proxy keeps its routes, your Tailscale keeps your devices.
Not ready for a network of your own devices (Tailscale is the better tool); phones that need more than a browser link, since there is no nfltr app; your own domain names on links, or a link left unused for weeks; a mapped service shared outside your account. The nfltr CLI and relay server are closed source, and running your own relay is a beta.
Try next: install nfltr and sign in on the machine that runs the service:
curl -fsSL https://nfltr.xyz/install.sh | sh
nfltr config login
Then pick your row in the table above and run that part's file with nfltr up -c <file>: part 4 for a link to a web app, part 5 for a mapping to your own laptop. The nfltr up and nfltr dial reference covers services:, share links and connect:; Reach a private LAN covers nfltr wg.