Skip to content

Latest commit

 

History

History
99 lines (73 loc) · 5.81 KB

File metadata and controls

99 lines (73 loc) · 5.81 KB

Remote access

TermDeck Remote keeps the terminal server bound to localhost. The local TermDeck process authenticates with a hosted relay and opens an outbound tunnel only when an authenticated browser requests it. No inbound port, router rule, public IP, or local TLS certificate is required.

Local Wi-Fi access

For direct access from a phone or another computer on the same network, open Settings and enable Local Wi-Fi. TermDeck starts a separate listener on port 8532 and shows the local URL to open. This connection stays on the local network and does not use Google sign-in, the hosted relay, or the internet.

The listener accepts only loopback clients and clients inside a private subnet currently assigned to the computer. It is plain HTTP and, unless TERMDECK_ACCESS_TOKEN is configured, anyone on that local network can control terminals and access the files exposed by TermDeck. Enable it only on a trusted home or office network and disable it on public Wi-Fi. The port can be changed with TERMDECK_LAN_PORT or termdeck --lan-port.

Direct access with a bearer token

TermDeck can protect every local HTTP, API, and WebSocket route with TERMDECK_ACCESS_TOKEN. This mode is for an SSH-forwarded port, Tailscale/private VPN address, LAN listener, or your own HTTPS reverse proxy. Browsers get a token login page and a derived HttpOnly cookie; scripts use Authorization: Bearer <token>.

TERMDECK_READ_ONLY=1 can be used with or without the token. It preserves live terminal output, transcripts, file reads and searches, Git inspection, and session export, while rejecting terminal input, starting dormant terminals, and every mutating HTTP request. It is intended for dashboards and remote review, not as a sandbox: the viewer can still read files and session content.

This is separate from TermDeck Remote:

Direct bearer-token access remote.termdeck.workers.dev
Connection You expose or tunnel a local listener Local TermDeck opens an outbound relay connection on demand
Identity One server token shared with approved clients Google account login and per-computer pairing
Public infrastructure None unless you provide a proxy/VPN Managed Cloudflare/Cloud Run relay
Encryption Supplied by SSH, VPN, or HTTPS proxy HTTPS/WSS to and from the hosted relay
Read-only policy Optional server-wide mode Uses the same server-wide mode when enabled

When both modes are enabled, the local relay connector adds the configured bearer token to its forwarded local requests. The hosted browser still signs in with Google; it never receives the local token.

Connect a computer

Set the relay URL before installing or restarting the TermDeck background service:

export TERMDECK_REMOTE_URL=https://your-relay.example.com
termdeck service install

Open TermDeck, select Settings, then select Sign in beside Remote access. Complete Google sign-in in the new browser tab. The local credential is stored in ~/.termdeck/remote-credentials.json with owner-only file permissions. TermDeck stores no Google access or refresh token locally.

Once paired, sign into the relay from a phone or another browser with the same Google account. The relay matches the browser and computer using Google's stable account subject. A new computer pairing replaces the previous connector for that account.

The local connector polls for demand while idle. It opens its multiplexed WebSocket when a remote browser arrives and the relay closes it after the last browser channel disappears. This permits request-billed hosting platforms to scale down while remote access is unused.

The hosted browser pauses after ten minutes without keyboard, pointer, touch, or scroll interaction. It switches to an authenticated idle page with no polling or WebSockets, then reconnects through a fresh TermDeck page load on the next interaction. Terminals continue running locally while the remote browser is paused. Set TERMDECK_REMOTE_BROWSER_IDLE_SECONDS on the relay to change the timeout or set it to 0 to disable browser idling.

Security model

  • The relay validates Google ID token signature, issuer, audience, expiry, verified email, and stable subject.
  • Browser sessions and connector credentials use separate signed token domains and expiration periods.
  • Firestore stores only the Google subject, display email, and SHA-256 connector-token digest.
  • Pairing secrets are random, short-lived, rate-limited, and stored only as digests by the relay.
  • Browser mutations and WebSocket handshakes require the configured HTTPS origin.
  • The remote connector strips hosted cookies and WebSocket negotiation headers before forwarding locally.
  • Pairing another computer rotates the account's connector credential and disconnects the prior computer.
  • The hosted relay can observe proxied terminal traffic. This first version is encrypted in transit but is not end-to-end encrypted from the browser to the local computer.

Limits

The initial Cloud Run deployment must use one maximum instance because browser and connector WebSockets are paired in memory. Clients reconnect when Cloud Run reaches its WebSocket request timeout. A multi-instance version requires a shared connection router rather than relying on session affinity.

Remote HTTP request bodies are capped below Cloud Run's HTTP/1 request limit. Large local uploads should be made from the computer until chunked remote uploads are implemented.

Self-hosting the relay

The relay source is in remote_service/. It requires:

  • TERMDECK_REMOTE_GOOGLE_CLIENT_ID
  • TERMDECK_REMOTE_SESSION_SECRET
  • TERMDECK_REMOTE_PUBLIC_URL
  • GOOGLE_CLOUD_PROJECT for Firestore persistence

For local development without a Google Cloud project, omitting GOOGLE_CLOUD_PROJECT uses an in-memory connector token store. That mode loses pairings on restart and is not suitable for a public deployment.