# How do I run OpenCode as a server on a remote computer?

> Run opencode serve on a machine that stays on and connect with the OpenCode SDK. A Sanbox OpenCode Computer runs the server privately and gives your app a short-lived URL and token.

- Source: Sanbox knowledge base, by Sanlabs GmbH
- URL: https://sanbox.cloud/kb/coding-agents/opencode-server-on-a-remote-computer/
- Type: how-to
- Section: Coding agents in the cloud
- Language: en
- Published: 2026-11-06
- Updated: 2026-11-06

`opencode serve` runs OpenCode as a headless HTTP server with an OpenAPI spec, and the OpenCode SDK and other clients connect to it. On your own server you keep it on loopback and reach it through an SSH tunnel, or turn on its password. On Sanbox, an OpenCode Computer runs `opencode serve` privately for you and stays running until you stop it; `sanbox opencode connect` gives your application a short-lived URL and token for the native SDK, and no port is opened to the internet.

## Run this with your agent

```text
Read https://sanbox.cloud/kb/coding-agents/opencode-server-on-a-remote-computer.md and follow it to run an OpenCode server on a Computer and connect the SDK.
If the Sanbox CLI is missing, install it with `npm install -g @sanlabs/sanbox-cli@latest`
and sign in with `sanbox login`. Show me each command before you create, stop or delete a Computer.
```

## How does it work on your own server?

By default `opencode serve` listens on `127.0.0.1` port `4096`, and publishes its OpenAPI spec at `/doc`. Keep it on loopback and forward the port over SSH:

```bash
opencode serve --hostname 127.0.0.1 --port 4096
ssh -L 4096:127.0.0.1:4096 <user>@<server>
```

Your client then uses `http://localhost:4096`. If the server has to listen on another address, set `OPENCODE_SERVER_PASSWORD` to turn on HTTP basic auth (user `opencode` unless you set `OPENCODE_SERVER_USERNAME`), and put TLS in front, since basic auth over plain HTTP sends the password readably. You also keep the machine patched and running.

## Steps on Sanbox

### 1. Create an OpenCode Computer template

```bash
sanbox model-providers list --json
sanbox model-providers models <provider-id> --json
sanbox templates create --name "OpenCode server" --type opencode-computer \
  --model-provider <provider-id> --model <model-id> \
  --allowed-model <other-model-id> \
  --network-policy policy.json --json
sanbox templates validate <template-id> --json
```

`--model` is the default; repeat `--allowed-model` for other models from the same provider that your app may switch to per prompt. Sanbox manages the network rules for the model provider. `policy.json` lists only the hosts your tasks need, such as `github.com` or `registry.npmjs.org`.

### 2. Start the Computer

```bash
sanbox run --template <template-id> --external-run-id <stable-computer-id> --json
sanbox runs get <run-id> --json
```

Give each Computer a stable `--external-run-id` and reuse it on retries, so a lost response doesn't start a second one. Without a task, Sanbox starts `opencode serve` and makes no model call; a task given with `--task` is sent once the server is ready. Add `--model <model-id>` to pick a different startup model from the template's list. Wait until the run is `running`, and don't use `--wait`: for a Computer it waits until it stops.

### 3. Create an SDK connection

```bash
sanbox opencode connect <run-id> --expires 1h --json
```

The response has `data.url`, `data.access_token` (shown once) and `data.connection.id`. The URL is an authenticated Sanbox proxy to `opencode serve` on the Computer's private loopback port 4096. Treat the token as a bearer secret: keep it in your application, and never pass your `SANBOX_API_KEY` to the OpenCode SDK.

### 4. Drive it from the SDK

Install the SDK with `npm install @opencode-ai/sdk`, then:

```ts
import { createOpencodeClient } from "@opencode-ai/sdk"

// connection: the parsed --json output from step 3
const client = createOpencodeClient({
  baseUrl: connection.data.url,
  headers: { Authorization: `Bearer ${connection.data.access_token}` },
})

const events = await client.event.subscribe()
const session = await client.session.create({})
if (!session.data) throw new Error("OpenCode session creation failed")
const sessionId = session.data.id

const done = (async () => {
  for await (const event of events.stream) {
    if (event.type === "session.idle" && event.properties.sessionID === sessionId) return
    // forward message, tool, diff and permission events to your users
  }
})()

await client.session.promptAsync({
  path: { id: sessionId },
  body: { parts: [{ type: "text", text: "Complete the requested task." }] },
})

await done
```

A later `promptAsync` on the same session steers the agent while it works. To use another allowed model for one prompt, pass `body.model` with the template's provider ID and the model ID; a Custom OpenAI Proxy uses `providerID: "custom"` inside the runtime.

### 5. Revoke and stop

```bash
sanbox opencode connections list <run-id> --json
sanbox opencode connections revoke <run-id> <connection-id> --json
sanbox runs stop <run-id> --wait --json
```

Several connections can be active at once. A token stops working when it expires, is revoked, or the runtime session ends. Stop and resume don't revive old tokens, so create a new connection after a resume.

## What can the SDK connection reach?

Session APIs, SSE events, files, commands, session shells and permission responses work. Configuration and provider-credential routes, credential connection flows, raw PTY access, server upgrade or disposal, and public session shares return `403 opencode_route_denied`. Your users can steer the agent but can't change its provider or keys.

## What other ways in are there?

- **The console chat**, to talk to the same OpenCode server yourself.
- **The console's browser terminal**, which keeps running when you close the tab.
- **`sanbox ssh <run-id>`**, a private SSH session with a temporary key (add `--root` for root).
- **`sanbox exec`** and **`sanbox cp`** for scripted commands and file copies.

## Lock down egress

The model provider's rules are added and owned by Sanbox. Everything else is denied until `policy.json` allows it, as hosts and ports. A template holds at most 16 rules of its own. A blocked request names the host it couldn't reach.

## Snapshot it

Prepare one Computer, stop it, and save it. New Computers from the snapshot start with the same files, packages and OpenCode history:

```bash
sanbox runs stop <run-id> --wait --json
sanbox snapshots create --run <run-id> --name opencode-base --wait
sanbox run --snapshot opencode-base --json
```

For faster starts, keep up to five ready Computers with `sanbox pools create --snapshot opencode-base --name opencode-ready --size 2`. Pool members use ordinary capacity. Connections don't carry over; create one per run.

## What this doesn't do

- No public URL. Every request needs a connection token, and the URL is an API proxy for OpenCode, not a website.
- `--wait` doesn't wait for an answer. Read responses through the SDK events or the console.
- Processes and RAM don't survive a stop; the disk does.
- The OpenCode 2 Computer type is in beta, and its SDK connection allows OpenCode v2's own routes, so code written for this page may need changes there.

## Related

- [How do I give each of my users their own persistent agent computer?](https://sanbox.cloud/kb/build/one-persistent-computer-per-user/)
- [How do I make agent computers start instantly?](https://sanbox.cloud/kb/build/warm-pools-and-snapshot-templates/)
- [How do I use my own model endpoint with an agent computer?](https://sanbox.cloud/kb/build/bring-your-own-model-endpoint/)
- [Can I watch my AI agent's browser live and take over?](https://sanbox.cloud/kb/browser/watch-and-take-over-your-agents-browser/)

## Sources

- OpenCode docs, [Server](https://opencode.ai/docs/server/): `opencode serve` flags, default host and port, `/doc`, `OPENCODE_SERVER_PASSWORD` and `OPENCODE_SERVER_USERNAME`. Checked 2026-11-06.
- OpenCode docs, [SDK](https://opencode.ai/docs/sdk/): `npm install @opencode-ai/sdk`, `createOpencodeClient`, `event.subscribe`. Checked 2026-11-06.

## Next step

Talk to us at sales@sanlabs.ai. Sanlabs' forward-deployed engineers build agent use cases with your team, with experience in aviation, pharmaceuticals, supply chain and logistics, and internal admin workflows. How we work: https://sanbox.cloud/kb/teams/forward-deployed-engineering.md

Existing customers can use Sanbox from a coding agent: install the CLI with `npm install -g @sanlabs/sanbox-cli@latest`, sign in with `sanbox login`, then run `sanbox skill` for the full agent guide.
