Stav Tunnel
Serve your own models through Stav — a Mac mini or an on-prem box behind your firewall becomes a private Provider Endpoint in your workspace, with keys, routers, the request log, audit and the policy wall.
Stav Tunnel is switched on per workspace. If you do not see Your workspace → Connect → Stav Tunnel, ask support to enable it.
You have a machine that runs a model well — a Mac mini with Ollama, a workstation with LM Studio, a box running llama.cpp, a GPU server running vLLM or SGLang. Stav Tunnel lets that machine serve your workspace through Stav, so your applications keep one base URL, one key, one request log, and the same routers and policy wall — and the model itself is private to your workspace.
Nothing is open to the internet. A small daemon, stav-tunnel, connects outbound from your machine to Stav's relay over WebSocket. Requests come back down that connection and are answered by the backend on the machine. No inbound port, no firewall rule, no VPN.
How it works
- Add a node in Your workspace → Connect → Stav Tunnel. Give it a name and the country the machine computes in. You get a one-time enrolment token and the install command.
- Run the command on the machine. It installs the daemon from the platform's own package manager and connects. The daemon finds Ollama (
:11434), LM Studio (:1234), llama.cpp (:8080), vLLM (:8000) or SGLang (:30000) on the machine and reports the models it serves. - Use the models. Within a minute they appear in
/v1/modelsand in Your workspace → Connect → Models. A model Stav already knows keeps its catalogue name and gains a row for your node; one it does not know is named@your-workspace/local-id.
# macOS or Linux, Homebrew
brew install stavhq/tap/stav-tunnel
stav-tunnel up --token stn_…
On Debian or Ubuntu:
curl -fsSL https://packages.stav.ai/packages/key.gpg | sudo gpg --dearmor -o /usr/share/keyrings/stav.gpg
echo "deb [signed-by=/usr/share/keyrings/stav.gpg] https://packages.stav.ai/packages/apt stable main" | sudo tee /etc/apt/sources.list.d/stav-tunnel.list
sudo apt update && sudo apt install stav-tunnel
On Fedora, RHEL or Rocky:
sudo curl -fsSL -o /etc/yum.repos.d/stav-tunnel.repo https://packages.stav.ai/packages/stav-tunnel.repo
sudo dnf install stav-tunnel
With a package, put the token in /etc/stav-tunnel/env (STAV_TUNNEL_ARGS=--token stn_…), run sudo systemctl enable --now stav-tunnel, then remove the token line — the node keeps its own key.
To keep the node running after logout and reboot, run stav-tunnel service install on macOS (a LaunchAgent). The Linux packages ship a systemd unit: sudo systemctl enable --now stav-tunnel.
stav-tunnel status shows the connection and the backends it found. stav-tunnel logout removes the machine's credentials.
vLLM and SGLang
The daemon looks for vLLM on :8000 and SGLang on :30000. Many other servers use those ports, so a server found there is reported only when the daemon confirms it is vLLM or SGLang. Any other server works too when you name it: stav-tunnel up --backend http://127.0.0.1:8000/v1.
- A server that needs a token. If you start vLLM with
--api-key, the node page shows vLLM asks for a token. Give the daemon the key once:stav-tunnel up --backend 'http://127.0.0.1:8000/v1|your-key'. The key stays in the daemon's config on the machine and never reaches Stav. SGLang with--api-keyrefuses every request without the key, so the daemon cannot tell it from another server: name it the same way from the start. - A model served under another name.
vllm serve Qwen/Qwen3-8B --served-model-name prod-chatlists the model asprod-chat. vLLM and SGLang also say which weights it is, and Stav uses that: when the catalogue has Qwen3-8B, your model gets its catalogue name, page and benchmarks. The node page shows the weights under the local id. A model loaded from a local folder is not matched this way (the path is never sent to Stav); map it on the node page. - In a container. The
stav-tunnelcontainer image looks for the servers on its own127.0.0.1. Run it with--network host, or give it the server's address with--backend.
Addressing your node
| You send | You get |
|---|---|
creator/model or auto | The router may pick your node when it is online (see below) |
creator/model/@node | That model, pinned to your node. Never fails over |
@your-workspace/local-id | A model only your node serves |
@your-workspace/local-id/@node | The same, pinned |
A response served by your node carries X-Stav-Served-By: own-resource and X-Stav-Node-Id; X-Stav-Provider is your node's private provider, @your-workspace/node. The request log shows the node's name.
Your models, fully known
A model on your node is only useful once Stav knows what it can do. Two things make sure of that:
- Probing. When a model appears on a node, or the runtime reports it changed (a new quantization, size or version), Stav sends the node a handful of short test requests — a one-second audio file to
/v1/audio/transcriptions, a plain chat call, a tool call, a JSON-schema call, a temperature, a 1×1 image and each reasoning level — and records what the model actually accepted. What was measured wins: a runtime that liststoolsfor a model that then refuses them gives you a clean capability error instead of a garbled answer. Every fact on the node page says where it came from —mmeasured on the node,rreported by the runtime,cfrom the catalogue. Probes are free and use the machine's GPU for a moment; each node has a daily limit, and the page says when it is reached. Switch Probe new models automatically off on a node if you would rather not; Probe again still works. - Mapping. A local id Stav cannot match (
qwen3.5:9b-mlxwhen the catalogue has no Qwen 3.5 9B) stays private until you tell it. Map to a catalogue model on the node page suggests the closest public models and lets you search the whole catalogue; the map applies to every node in your workspace that reports that id, wins over every matching rule, and moves the model under the catalogue name — its page and benchmarks — with a probe right after. The row then reads Mapped by your workspace, never Matched, and the benchmarks are the catalogue model's, not something measured on your node. Pins on the old@your-workspace/local-idstop resolving. Remove the mapping and the id goes back to the rules.
Routers
Every router has a Tunnel nodes setting:
- Prefer (default) — an online node of yours goes first; if it is offline or drops before the first byte, the request fails over to the catalogue.
- Only — your nodes only. Nothing online means the request fails with
no_eligible_models; never a silent fallback to a third party. - Ignore — the router stays on the catalogue.
A pinned request (…/@node) never fails over: if the node is away you get an error, by name.
Speech to text on your node
A Whisper model in vLLM (vllm serve NbAiLab/nb-whisper-large, or any Whisper vLLM serves) answers POST /v1/audio/transcriptions through your node, so the audio stays on your machine and still gets your key, the request log and the policy wall.
- The probe proves it: the one-second audio file gets a transcript back, a plain chat call does not, and the model is listed as a transcription model — in
/v1/modelsundertranscriptions, and on the node page as transcription. - Call it as
@your-workspace/local-id, or by its catalogue name when Stav knows the model. Requests are free; the request log keeps the duration, size and format, never the audio. - A node takes files up to 24 MB.
- Audio has no router, so there is no Only setting for it. A request for a catalogue model that your node also serves goes to your node first; if the node drops before it answers, the request goes once to the catalogue. To keep audio on your machine without exception, call the private
@your-workspace/…name or pin the node (…/@node). - Update the daemon (
stav-tunnel0.4.0 or later) when vLLM is not the first server on the machine: older releases send an upload to the first server they find.
How it is classified
Your node gets level L4 and shows as L4 · Customer-operated. You own and operate the machine, so no third party sees the data. The country, zero data retention and no-training facts are what you declared when you added the node; Stav does not verify them, and Your workspace says so (declared NO, never "verified"). A policy floor that a declared fact fails says (customer_declared) in its reason.
What it costs
- Requests to your own node are free. Tokens are counted for your usage view, never charged.
- Each node costs €1.00 a month, charged from the wallet when you add it and then on the 1st. If the wallet is empty the node is suspended until you top up.
Security and privacy
- The token is shown once and works once. After that the daemon proves itself with a key it generated on the machine (Ed25519) on every connect.
- Revoking a node in Your workspace → Connect → Stav Tunnel closes the tunnel within seconds; no request reaches the machine again.
- The relay forwards bytes; it does not store prompts. The daemon holds no prompts at rest and has no self-update code — updates come from
brew upgrade(orapt/dnf). Every release ships with a software bill of materials. - Your node, its provider row, its endpoints and its private models are visible only to your workspace — never on the public catalogue, never to another workspace.
Limits in this version
- Backends: Ollama, LM Studio, llama.cpp, vLLM, SGLang. Anything else that speaks the OpenAI chat API works when you name it with
--backend, but is not tested. - One machine at a time: a cluster with many replicas of one model is not supported yet.
- Chat (
/v1/chat/completions,/v1/messages,/v1/responses), embeddings and audio transcriptions; no text-to-speech through a node. Speech to text is tested on vLLM; another server that speaks OpenAI's/v1/audio/transcriptionsand lists its models on/v1/modelsworks when you name it with--backend. - Up to 50 nodes per workspace.