DocsGetting StartedCore Concepts

Core Concepts

A handful of ideas recur throughout ngstone's design. Once these click, the rest of the docs — the wire protocol, the failure modes, the operations guides — read as consequences of a small set of decisions rather than a pile of unrelated facts.

The edge (ngstoned)#

Runs on a public Linux VPS. Terminates public TLS, issues certificates, and routes each incoming request to the agent session that owns its hostname.

The agent (ngstone)#

Runs on your dev machine (macOS or Linux). Dials out to the edge and forwards traffic to a local port.

ngstoned

The edge. Public TLS, certificate issuance, request routing.

ngstone

The agent and CLI. Also opens the terminal request inspector — see below.

The agent always initiates the connection to the edge — the VPS never dials into your laptop. That single design choice is why ngstone needs no inbound firewall holes at home and no NAT traversal.

Sessions and streams#

The agent dials ngstone.site:4443 and establishes one long-lived TLS connection. On top of that connection runs a single yamux session, which multiplexes many independent byte streams over the one TCP connection.

The first stream opened on a session is a dedicated control stream — it carries authentication, bind/unbind requests, and heartbeats. Every proxied HTTP request the edge forwards to the agent gets its own stream, opened fresh and closed when the request completes.

one TLS connection
└── yamux session
├── control stream (auth, bind, ping/pong, goodbye)
├── request stream (one HTTP exchange)
├── request stream (one HTTP exchange)
└── ...

Bindings and the registry#

A Binding maps a hostname (like api.ngstone.site) to the agent session that owns it. The edge keeps all bindings in a Registry: a plain map guarded by an RWMutex, plus a secondary index from session to the set of hostnames it owns. That secondary index is what lets a dying session's cleanup release exactly its own bindings without racing a newer session that just took the same name.

Routing a request is a read lock and a map lookup. A miss returns an immediate 404without ever touching the agent; a hit hands the request to that binding's session.

Instance identity#

Every agent process mints a stable InstanceIDonce, at startup, and keeps it for the process's lifetime — it survives reconnects but dies with the process. This identity is what authorizes taking over a binding: if a reconnecting agent presents the same InstanceID as the current holder of a subdomain, the takeover is immediate, regardless of whether the old session still looks alive.

The inspector#

ngstone port opens a full-screen terminal dashboard — not a web UI, no localhost:4040, no HTTP API — showing every request and response your tunnel handles as it happens. One agent process runs exactly one tunnel and one inspector; a second tunnel is a second terminal tab.