DocsGuidesExposing a local app

Exposing a local app

The whole point of ngstone: turn a port on your laptop into a public HTTPS URL.

Basic usage#

Point the agent at whatever port your app is listening on:

$ ngstone port 3000
→ https://amber-fox-42.ngstone.site

That forwards https://amber-fox-42.ngstone.site to localhost:3000. Anything the public URL receives, your local app receives.

How forwarding works#

Each incoming request opens a fresh yamux stream from the edge to the agent, carrying a small JSON preamble ahead of the raw request bytes. The agent reads the preamble, then forwards the request to your local app over a pooled, keep-alive transport. Bodies stream through end to end — nothing is buffered in full on either side, so a large upload or download costs constant memory regardless of size.

Forwarded headers#

The edge stamps X-Forwarded-For, X-Forwarded-Proto, and X-Forwarded-Host on every request before it reaches the agent, and the agent preserves them unmodified on the way to your local app.

Your local app can trust these headers. Inbound spoofed values are stripped and replaced at the edge before the request ever reaches the tunnel, so X-Forwarded-For always reflects the real public client, not something an attacker sent.

The Host header#

The original public Host header is preserved end to end — what most OAuth callback URLs and vhost routers expect. There is currently no flag to rewrite it to something like localhost:3000 instead; if your app is picky about the Host it receives, it needs to accept the public hostname (e.g. amber-fox-42.ngstone.site) for now.

When the local app isn't running#

If the agent can't dial your local port, it doesn't just fail silently — it synthesizes a 502 with a body that says what went wrong, so a request against a stopped dev server reads as an obvious, actionable error rather than a mystery.

502response
Local dial failed. Body includes a message like "nothing listening on localhost:3000".