---
title: "Remote Access"
type: concept
tags: [remote, foundational, well-established]
created: 2026-08-06
updated: 2026-08-06
sources: ["raw/github_doc-docs-user-remote-access-md.md", "raw/github_doc-docs-internals-remote-md.md"]
confidence: high
t3code_version: "0.0.32-nightly (2026-08-05)"
---

## Definition

Remote access is the ability to connect to a T3 Code server from a different device — a phone,
tablet, or separate desktop — rather than only from the machine running the server. T3 Code has a
single runtime boundary: a client talks to a T3 server over HTTP and WebSocket, and the server
alone owns orchestration, providers, terminals, git, and filesystem operations. Remoteness is
expressed entirely at the connection layer; the runtime itself is never split.

## How It Works

### The model

```text
Client (desktop / mobile / web)
  known environments, connection supervisor
        |  resolves one access endpoint
Access method
  direct ws/wss, relay tunnel, Tailscale serve, desktop-managed ssh
        |  connects to one T3 server
Execution environment = one T3 server
  identity, providers, projects/threads, terminals, git, filesystem
```

One running T3 server instance (an `ExecutionEnvironment`) owns provider availability/auth, model
availability, projects/threads, terminal processes, filesystem access, git operations, and server
settings. It is identified by a stable `environmentId` persisted at
`<stateDir>/environment-id` and generated on first start.

### Ways to enable network access

1. **Desktop app** — Settings → Connections → toggle **Network access** on (restarts the app,
   binds the backend to all network interfaces). The settings panel surfaces a default reachable
   endpoint plus alternatives (loopback, LAN, private-network, HTTPS); **Create Link** generates a
   shareable pairing link. If Tailscale is detected, Tailnet endpoints (a `100.x.y.z` IP, MagicDNS
   name, or an HTTPS MagicDNS endpoint via Tailscale Serve) are added to the list; the HTTPS
   MagicDNS endpoint must be opted into via **Enable Tailscale HTTPS**.
2. **Headless server (CLI)** — `npx t3 serve --host "$(tailscale ip -4)"` starts the server without
   a GUI and prints a connection string, a pairing token, a pairing URL, and a QR code. Add
   `--tailscale-serve` to advertise an HTTPS Tailnet endpoint (default port 443, or
   `--tailscale-serve-port` for another port).
3. **Desktop-managed SSH launch** — Settings → Connections → Remote Environments → Add
   environment → SSH launch flow. The desktop app probes the host, starts or reuses a remote T3
   server, opens a local port forward, and saves the environment. The remote host still owns the
   actual server, projects, files, git state, terminals, and provider sessions; the renderer just
   connects to a forwarded local endpoint. The remote host needs a Node.js version satisfying
   `^22.16 || ^23.11 || >=24.10` reachable from a non-interactive shell (T3 Code tries Volta, asdf,
   mise, fnm, nodenv, nvm if `node` isn't directly on `PATH`).

### Quick pairing

For an already-running server: `npx t3 pair` mints a fresh one-time pairing token and prints it as
a scannable QR code, without restarting anything. If the server is loopback-only, use
`npx t3 pair --tailscale` to publish it via Tailscale Serve HTTPS first. Flags include
`--tailscale-serve-port`, `--ttl` (token lifetime), and `--base-dir`.

### Connection targets and endpoints

Four target tags form the real access taxonomy (`connection/model.ts`): `PrimaryConnectionTarget`
(platform-managed local server — desktop backend or CLI-served web app), `BearerConnectionTarget`
(any manually paired direct HTTP/WebSocket endpoint), `RelayConnectionTarget` (managed T3 Connect
relay tunnels — see [[concepts/t3-connect]]), and `SshConnectionTarget` (desktop-managed SSH
environments). Tailscale is not a separate target kind — a Tailscale URL is paired through the
ordinary bearer path; Tailscale is an endpoint provider/transport, not a distinct runtime concept.
An `AdvertisedEndpoint` is a server- or desktop-authored candidate endpoint (HTTP+WS URL pair,
default/available marker, reachability hint, HTTPS-app compatibility hint); clients treat these as
hints, not proof a route works — the connection attempt itself decides.

### How pairing works

The remote device needs no long-lived secret up front: `t3 serve` issues a one-time owner pairing
token, the remote device exchanges it with the server, and the server creates an authenticated
session for that device. After pairing, access is session-based.

### Hosted web app pairing

`https://app.t3.codes` can save a remote backend from a URL like
`https://app.t3.codes/pair?host=https://backend.example.com:3773#token=PAIRCODE`. This only works
when the backend is reachable from the browser over HTTPS/WSS — browsers block an HTTPS page from
connecting to an insecure `http://`/`ws://` LAN backend. The hosted app does not proxy traffic; the
browser connects directly to the backend URL in the link. Hosted pairing is a client-side
convenience only: the hosted app never gets a server-side control plane or copy of session state,
and keeps the token in the URL hash so it is never sent to the hosted app's own server.

### Managing access afterward

`t3 auth` manages access after initial pairing: issuing additional pairing credentials, inspecting
active sessions, and revoking old pairing links or sessions.

For the underlying relay/pairing mechanism behind `RelayConnectionTarget`, see
[[concepts/t3-connect]].

## Key Parameters

- **Recommended setup**: a trusted private network / tailnet, for a stable address, transport
  security, and less exposure than the open internet.
- **Three network-access enablement paths**: desktop app toggle, headless `t3 serve`, or
  desktop-managed SSH launch.
- **Four connection target kinds**: Primary, Bearer, Relay, SSH.
- **WebSocket auth**: a dedicated short-lived ticket (not a query-string token), obtained via
  `POST /api/auth/websocket-ticket` and appended as `wsTicket`; tickets default to a five-minute
  TTL (`DEFAULT_WEBSOCKET_TOKEN_TTL`).
- **`t3 pair` flags**: `--tailscale`, `--tailscale-serve-port`, `--ttl`, `--base-dir`.

## When To Use

Use remote access whenever you want to direct an agent from a device other than the one running
the T3 Code server — controlling a desktop-hosted environment from the mobile app, from
`app.t3.codes`, or reaching a headless server on another machine over SSH or a tailnet.

## Risks & Pitfalls

- A loopback-bound server's pairing URL is not reachable from another device; pair over Tailscale
  or enable network access first.
- Hosted pairing links (`app.t3.codes`) do not work with plain HTTP LAN URLs due to browser
  mixed-content rules — use the direct pairing URL from the desktop app or CLI instead.
- Pairing URLs and tokens should be treated like passwords: anyone holding a valid credential can
  create a session until it expires or is revoked (via `t3 auth`).
- SSH launch can fail with `node: command not found` or a version-range error if a version manager
  only initializes from an interactive shell profile — it must be configured to work with
  `sh -lc "command -v node && node --version"` non-interactively.
- Binding `--host` broadly (rather than to a trusted private address) increases exposure
  unnecessarily.

## Related Concepts

- [[concepts/t3code-overview]]
- [[concepts/t3-connect]]
- [[concepts/background-service]]
- [[concepts/permission-modes]]

## Sources

- raw/github_doc-docs-user-remote-access-md.md
- raw/github_doc-docs-internals-remote-md.md
