Your GPU box, reachable from anywhere

A GPU box at home or in the office runs a local model server: Ollama, vLLM, or anything else that speaks the OpenAI chat completions API. The laptop that wants to use it is somewhere else: a café, a train, a client's office. The model server listens on its own machine only (Ollama binds 127.0.0.1:11434 by default) and has no authentication of its own, so reaching it from outside takes some assembly.

We built that setup twice, the conventional way and with nfltr, and ran both through the same test: completions, streamed answers, a wrong credential, a restart, and a look at what the box leaves open. The model is a stand-in that streams tokens like Ollama does, so no GPU was involved; the network around it is what was measured.

The usual setup

Most guides to reaching a home server describe the same four pieces. The home router forwards its public ports 80 and 443 to the box. A dynamic DNS name follows the home's changing address, kept current by a job on the box. A reverse proxy on the box (Caddy here) serves HTTPS with a Let's Encrypt certificate for that name and refuses any request without a bearer token. The model server stays on loopback behind it.

It works, and with a free DNS name and a free certificate it can cost nothing. It also leaves ports 80 and 443 of the home open to the whole internet, with a token check as the only thing between a scanner and the model. And it needs a public IPv4 address: behind carrier-grade NAT, which some internet providers use, nothing can be forwarded. The usual way out there is a rented cloud VM and a reverse SSH tunnel from the box to it, one more machine to pay for and patch.

Before and after: reaching a GPU box from a laptop Before: the laptop connects in to the home router's public ports, which forward to a proxy on the box, which checks a token and passes requests to the model server on loopback. After: the box and the laptop each connect out to a relay, and the laptop's local port reaches the model server through an end-to-end encrypted session. Before laptop token router 80, 443 open box: proxy HTTPS, token, DNS job connections come in from anywhere; the token decides After laptop 127.0.0.1:11434 relay ciphertext only box no open port both connect out; TLS runs from the laptop to the box
Before, the home opens two ports and a token guards the model; after, both machines connect out and the box accepts nothing from the network.

The same with nfltr

nfltr runs one small agent on each machine, and each agent connects out to a relay. On the box, nfltr up publishes the model server's loopback port under a name, end-to-end encrypted:

agent: gpu
services:
  model: { tcp: 11434, e2ee: true }

On the laptop, nfltr up maps that name to a port on the laptop itself, pinned to the box's certificate:

connect:
  model: { target: gpu/model, listen: "127.0.0.1:11434", pin: "<the box's pin>" }

Any tool pointed at http://127.0.0.1:11434/v1 on the laptop now reaches the box: an editor plugin, a chat UI, a script using an OpenAI client library. Each connection is one session through the relay, with TLS running between the two agents, so the relay carries encrypted records and never sees a prompt or an answer. For a one-off session, nfltr dial gpu/model --pin <pin> connects stdin and stdout instead of a port. The box does not need a public address, so carrier-grade NAT makes no difference.

What we measured

Both setups ran as containers on one Mac: the box behind a home router that adds 10 ms each way between home and the outside, a laptop outside, and in the nfltr setup a private relay outside as well. The laptop ran 100 completions and 100 streamed answers of 16 tokens through each setup, after one untimed call to open the connection. The stand-in model produces one token every 10 ms.

completion p50 / p95 first token p50 / p95 streamed answer p50
on the box itself 185.0 / 193.7 ms 11.4 / 13.4 ms 188.2 ms
port forward + proxy 209.1 / 218.4 ms 35.2 / 38.0 ms 209.9 ms
nfltr 205.4 / 215.5 ms 34.4 / 38.0 ms 207.3 ms

The time to first token, the delay a chat user feels, was the same through both: 23 to 24 ms over the box's own, most of it the 20 ms round trip through the home router. The relay sat on the laptop's side of that round trip; a relay far from both machines adds its distance to every answer.

Each check below passed, judged by a program's exit code:

  • A wrong credential is refused. Before: a wrong or missing token gets 401 from the proxy. After: a session opened with a wrong account key is refused by the relay, and one with the wrong pin fails closed before any byte reaches the model.
  • Nothing is open after. Before, the box listens on ports 80 and 443 on every interface and the router has two forwarding rules; a connection from outside to port 443 succeeds. After, nothing on the box or the laptop listens beyond loopback, the router has no forwarding rule, and connections from outside to ports 443 and 11434 are refused.
  • A restart recovers. The front of the box (the proxy before, the box's agent after) was killed and started; the laptop's next answer came 263 ms later before and 264 ms later after.

The setup, counted

Neither setup is long. The conventional one is 20 lines of configuration: the proxy's file and environment, the router's forwarding rules, the DNS updater and the laptop's settings. The nfltr one is 25 lines with a private relay and 21 with the hosted one, where signing in replaces the relay's address and pin; most of the rest creates the box's certificate and copies its pin to the laptop. Both have five moving parts.

before after
on the router a forward for ports 80 and 443 nothing
on the box a proxy, a DNS updater, a certificate renewed every 90 days nfltr up, a certificate whose pin the laptop holds
on the laptop the name and the token nfltr up and the pin
shared secret a token on both machines the account key on both machines
outside a dynamic DNS name the relay

The difference is less in the count than in where the parts are: the conventional setup's parts face the internet, and nfltr's face only the relay.

What it costs

nfltr is free until further notice. To show what relaying this kind of traffic costs whoever runs the relay, we priced it with our cost ledger at public cloud list prices. A streamed answer in the OpenAI format sends one JSON chunk per token, 198.2 bytes per token in this test. One person using the box all day, 6,000 answers a month of 500 tokens with an 8 KiB prompt each, is 0.6 GiB a month. Relaying that end-to-end encrypted, plus two agents connected all month, comes to 0.087 USD a month at Google Cloud's list prices (0.073 for the traffic, 0.014 for the connected agents) and 0.0011 EUR at Hetzner's.

The conventional setup's costs, at list prices read on October 31, 2026:

part price
dynamic DNS name free (DuckDNS; No-IP's free tier must be confirmed by hand every 30 days), or 30 USD a year (No-IP's paid tier)
your own domain instead 10.46 USD a year (.com at Cloudflare Registrar, at cost)
TLS certificate free (Let's Encrypt)
a VM for a reverse SSH tunnel, behind carrier-grade NAT 4 USD a month (DigitalOcean), 5 USD a month (AWS Lightsail), 5.99 EUR a month (Hetzner, EU)

With a public IPv4 address, the conventional setup is cheap in money and costs its open ports. Behind carrier-grade NAT, it costs a VM.

Evidence: a GPU box reached from a laptop

Setup
Both setups as Linux containers on one Mac (Apple Silicon) with Docker, two runs on October 31, 2026; the numbers are from the second run, the first agreed within 5 ms on every latency percentile. A home network behind a router with 10 ms of added delay each way (tc netem), a laptop network outside, a private relay outside in the nfltr setup. The model server is a stand-in for Ollama's OpenAI API (one token every 10 ms, 16 tokens per answer). The proxy's certificate came from Caddy's own CA instead of Let's Encrypt, and the laptop resolved the box's name without a real dynamic DNS service.
Numbers
Completion p50 185.0 ms on the box, 209.1 ms through the port forward and proxy, 205.4 ms through nfltr; first token p50 11.4, 35.2 and 34.4 ms; a wrong token 401, a wrong account key refused, a wrong pin failed closed; non-loopback listeners on the box 2 (ports 80 and 443) and 0; router forwarding rules 2 and 0; next answer 263 ms after the proxy restarted and 264 ms after the box's agent restarted; 20 and 25 configuration lines (21 with the hosted relay); 198.2 bytes per streamed token; 0.6 GiB a month for the workload above; 0.087 USD a month at Google Cloud list prices, 0.0011 EUR at Hetzner's, for relaying it with two agents connected.
Reproduce
(a) With the released binaries: run ollama serve and nfltr up with the first file above on the box, nfltr up with the second on the laptop (the pin is in the box's nfltr up output), and point an OpenAI client at http://127.0.0.1:11434/v1. (b) Our check, in the closed nfltr repository, runs both setups in containers and judges each claim by an exit code.
Limits
One host, so the only network distance is the delay we added and there is no loss; the relay sat next to the laptop. A real model's time to first token is mostly its prompt processing, which dwarfs every difference here. Two runs are no distribution. The cost covers relaying only, at list prices, for an assumed workload; prices change, and each one names the date it was read.

Is it for you?

Fits if a model server runs on a machine you cannot or do not want to open to the internet (behind carrier-grade NAT, on an office network you do not control, or simply with no port you want to forward), and you want to use it from a laptop or another machine with the prompts and answers unreadable to every machine in between, the relay included. The relay still sees which machines talk, when, and how many bytes; it can refuse or cut a session but cannot read or change one.

Not ready for sharing the model server with people outside your account: the connect sidecar reaches services inside one account. If the box has a public IPv4 address, you already run a reverse proxy, and an open port with a token in front of it is acceptable, the conventional setup does the job and costs nothing extra.

Try next: install nfltr and sign in on both machines, then run nfltr up with the two files above. The nfltr up reference covers services: and connect:, and nfltr dial the one-session form. Part 2 of this series measures the same pattern for a gRPC fleet.

← All posts