Skip to content
Blueprint

← All articles · Hosts

SSH tunneling

How Blueprint reaches a remote host's svc over the existing SSH connection — no port forwarding, no firewall changes, no `ssh -L`.

3 min read

The trick

The blueprint-svc on a remote host binds to 127.0.0.1:17832 only. It never exposes itself on the public network — that's an SSH operator's choice, not ours. So how does the desktop GUI reach it?

The Go net/http Transport accepts a custom DialContext. Blueprint swaps the default dialer (which would open a TCP socket on your local machine) for one that dials through the existing SSH session to the remote's localhost. From the HTTP client's perspective it's calling http://127.0.0.1:17832/v1/snapshot; in reality the bytes flow:

GUI → in-process HTTP client → SSH client → SSH server on remote
    → remote's loopback to localhost:17832 → blueprint-svc

Bytes never touch the public network past the SSH wrapper that secures them.

Why this matters

  • Zero firewall configuration on the host — the svc port stays local. You don't open 17832 to the world; you don't even open it to your own LAN.
  • No ssh -L dance — users don't have to remember ssh -L 17832:127.0.0.1:17832 user@host before they can connect. Connect is one button.
  • All the security of SSH — the same key authentication you already trust for shell access secures the svc HTTP control plane. No second auth system to manage.
  • The svc has zero exposed surface — if you've never started Blueprint, the port is bound but unreachable from anywhere except 127.0.0.1. Failed bearer attempts (logged in ~/.blueprint/logs/blueprint.log) shouldn't ever appear from any IP other than 127.0.0.1.

What this means for the bearer token

The bearer token at ~/.blueprint/svc-token on the remote is the ONLY auth between the SSH tunnel and the svc. SSH protects the network path; the bearer token protects the svc from co-located processes (anyone with a shell on the same host could otherwise hit 127.0.0.1:17832 unauthenticated).

If someone gains shell access to your host, they can read the token file. The token is 0600 — only the owning user can read it. Treat it like an ssh agent socket: same trust model.

What happens on connection loss

The SSH connection is the lifeline. If it drops (network blip, laptop sleep, manual disconnect), the cached HTTP client is dead. The next IPC call fails fast with an SSH error; the host selector shows the host as disconnected.

Reconnect is a single Connect click. The cached svc token in your OS keychain skips the SFTP refetch, so reconnect is sub-second.

Common pitfalls

  • NAT / proxy collapsing idle SSH connections: corporate networks often drop SSH after 5-10 min idle. Either enable SSH keepalives (ServerAliveInterval 60 in ~/.ssh/config) or accept the occasional disconnect.
  • HTTP timeouts mid-call: a long-running model pull initiated via the tunnel can exceed the default HTTP client timeout if you put it in front. svcclient sets a 30s timeout for routine calls and a 5-minute timeout for chat; long pulls run as background goroutines on the svc and report status via polling, so they survive HTTP timeouts.
  • Trying to reach the remote svc directly over the LAN: even if the remote IS on your LAN, the svc binds 127.0.0.1 only. You'd have to change BindHost in the svc config to expose it — which we don't recommend.

Need help with this in production?

Inspire AI Lab runs LLM optimization engagements end-to-end using Blueprint. If you'd rather hand the work to us instead of running it yourself, book a 30-minute review.