CLI
The ngstone command is built on the stdlib flag package — no cobra, no subcommand framework. There are six verbs: auth, port, tcp, config, logout, and version.
Overview#
ngstone <command> [arguments] Commands: auth <token> verify and save an auth token port <port|url> expose a local port or URL through the tunnel tcp <port|host:port> expose a raw TCP service through the tunnel config view or set local configuration logout remove the saved auth token version print the ngstone versionngstone auth#
Verifies a token against the edge's control plane, then saves the token and server address to the config file. Nothing is written to disk until the edge has confirmed the token is valid.
$ ngstone auth <token>verified against ngstone.site:4443 and savedngstone.site:4443 if neither is set.ServerName/SNI to verify against. Ignored with --insecure.--pin sha256/BASE64, checked in addition to normal chain validation. Off by default.A bad token or an unreachable server exits non-zero with a specific, actionable message rather than a generic failure.
ngstone port#
Starts a tunnel to a local port or URL. This is the command that actually opens a connection to the edge and forwards traffic. When stdout is a terminal, it also opens a full-screen inspector dashboard showing every request and response live, with headers, decoded bodies, timing, and replay — see Using the request inspector.
$ ngstone port 3000$ ngstone port http://127.0.0.1:3000$ ngstone port 3000 --subdomain demo$ ngstone port 3000 --host-header demo.localhost:3000The positional argument is either a bare port number (forwarded to http://127.0.0.1:<port>) or a full target URL. Flags may appear before or after it.
--subdomain demo for demo.ngstone.site.--host-header demo.localhost:3000.ngstone.site:4443.NGSTONE_TOKEN or the token saved by ngstone auth.ServerName/SNI to verify against. Ignored with --insecure.&), so this flag mainly matters when stdoutis a terminal and you still want plain logs.user:pass. Repeatable for multiple valid credentials. Visible to other local users via ps//procfor the process's lifetime — prefer --basic-auth-file or NGSTONE_BASIC_AUTH. See Access control.user:pass credential per line. Safer than --basic-auth.--basic-auth takes precedence over --basic-auth-file, which takes precedence over NGSTONE_BASIC_AUTH— the first one present is used, and they don't merge. NGSTONE_BASIC_AUTH uses the same format as --basic-auth-file: one user:pass credential per line.
ngstone tcp#
Starts a raw TCP tunnel to a local port or host:port target — for SSH, Postgres, Redis, or anything else that isn't HTTP. See TCP tunnels for the full picture, including the encryption caveat.
$ ngstone tcp 22tcp://amber-fox-42.example.com:14201 -> 127.0.0.1:22 $ ngstone tcp db.local:5432 --remote-port 15432The positional argument is either a bare port number (forwarded to 127.0.0.1:<port>) or a host:port target used as-is.
0 means server-assigned.ngstone.site:4443.NGSTONE_TOKEN or the token saved by ngstone auth.ServerName/SNI to verify against. Ignored with --insecure.--basic-auth for tcp— the edge rejects it, since there's no HTTP request to attach credentials to inside a raw TCP stream.-tcp-ports. See Running the edge on a VPS for how to enable it.--allow-cidr behind a proxy needs an edge flag too
-proxy-protocol, --allow-cidr is only trustworthy when the edge is also started with -proxy-protocol-trusted <proxy CIDRs> — otherwise a direct client can forge a PROXY header and spoof an allowed source IP. See Behind an existing reverse proxy and Access control.ngstone config#
Read or change the local config file without hand-editing JSON.
$ ngstone config set server ngstone.site:4443server set to ngstone.site:4443 $ ngstone config gettoken: nst_a1b2…9f3dserver: ngstone.site:4443 $ ngstone config get tokennst_a1b2…9f3d $ ngstone config path/home/you/.config/ngstone/config.jsonconfig get always redacts the token — the middle of the value is replaced with …, only the first and last four characters are shown.
ngstone logout#
Clears the saved token from the config file. The server address is left untouched.
$ ngstone logoutlogged outngstone version#
Prints the build's version string, injected at compile time via -ldflags.
$ ngstone versionngstone v0.1.0 (commit 3f1a9c2, built 2026-06-01T12:00:00Z)No arguments and -h#
Running ngstone with no arguments does not start a tunnel — it prints usage to stderr and exits 1. -h, --help, and -help print the same usage to stdout and exit 0.
Generating a token#
There is no ngstone token command
TOKEN=$(openssl rand -base64 32 | tr '+/' '-_' | tr -d '=')HASH=$(printf '%s' "$TOKEN" | shasum -a 256 | cut -d' ' -f1) # sha256sum on LinuxKeep $TOKEN for ngstone auth on every machine that will run the agent, and pass $HASH to the edge as -token-sha256 (or $NGSTONE_TOKEN_SHA256). There is exactly one token per edge — rotating it invalidates every agent at once, since it changes what the edge accepts, not something per-agent.
The config file#
ngstone auth, ngstone port, ngstone config, and ngstone logout all read and write the same JSON file:
$XDG_CONFIG_HOME/ngstone/config.json# falls back to ~/.config/ngstone/config.json if XDG_CONFIG_HOME is unsetThe file holds token and server. It's written with mode 0600 inside a 0700 directory, and saved via a temp-file-plus-rename so a crash mid-write can't corrupt it.
Resolution order for both the token and the server address:
--token / --server on the command invoking it.NGSTONE_TOKEN. There is no environment override for the server address.ngstone auth or ngstone config set last saved.Legacy flag form#
A flat-flags invocation is still supported alongside the verbs above, mainly for scripts and the e2e test suite written against it. It starts a tunnel directly — there's no config file involved.
$ ngstone -control ADDR -token TOK -target URL -subdomain NAME \ -insecure -server-name NAME -pin SPKI -instance-id IDNGSTONE_TOKEN if unset.Prefer ngstone auth plus ngstone port for day-to-day use — the legacy form exists for compatibility, not as the recommended path.