Skip to main content

Server Mode

OpenCode can run as a headless HTTP server, enabling remote access, CI/CD integration, web-based UIs, and programmatic control. Two subcommands are available: serve for API-only mode and web for a built-in web interface.

Quick Start

# Start the API server
opencode serve

# Start with web UI
opencode web

By default the server listens on http://127.0.0.1:4096.

Configuration

Server settings are defined in the server section of opencode.json:

{
"server": {
"port": 4096,
"hostname": "0.0.0.0",
"mdns": true,
"mdnsDomain": "myproject.local",
"cors": ["http://localhost:5173"]
}
}

Options

OptionTypeDefaultDescription
portnumber4096TCP port for the HTTP server
hostnamestring"127.0.0.1"Interface to bind to. Use "0.0.0.0" for all interfaces
mdnsbooleanfalseEnable mDNS discovery on the local network
mdnsDomainstring"opencode.local"mDNS hostname for discovery
corsstring[][]Allowed CORS origins for browser-based clients

Authentication

Set the OPENCODE_SERVER_PASSWORD environment variable to require HTTP Basic authentication for all API requests:

export OPENCODE_SERVER_PASSWORD="my-secret-key"
opencode serve

When set, clients must include the Authorization header:

curl -u "opencode:my-secret-key" http://localhost:4096/api/status

API Endpoints

The headless server exposes a RESTful API:

MethodEndpointDescription
GET/api/statusServer health and configuration info
POST/api/chatSend a message and receive a response
POST/api/chat/streamSend a message and stream the response via SSE
GET/api/sessionsList active sessions
GET/api/sessions/:idGet session details and message history
DELETE/api/sessions/:idDelete a session
GET/api/modelsList available models
GET/api/providersList configured providers
GET/api/agentsList configured agents

Chat Example

curl -X POST http://localhost:4096/api/chat \
-H "Content-Type: application/json" \
-d '{
"message": "Write a Python script to parse a CSV file",
"sessionId": null,
"agent": "build",
"model": "anthropic/claude-sonnet-4"
}'

Streaming Chat Example

curl -X POST http://localhost:4096/api/chat/stream \
-H "Content-Type: application/json" \
-d '{
"message": "Explain how React hooks work",
"sessionId": null
}'

The streaming endpoint uses Server-Sent Events (SSE):

data: {"type":"text","content":"React hooks are functions that..."}
data: {"type":"text","content":" allow you to use state and..."}
data: {"type":"tool_start","tool":"read_file","args":{"path":"..."}}
data: {"type":"tool_end","tool":"read_file","result":"..."}
data: {"type":"done"}

WebSocket Communication

For real-time bidirectional communication, the server supports WebSocket connections at /ws. This is the protocol used by the TUI attach feature and web UI.

const ws = new WebSocket('ws://localhost:4096/ws');

ws.onopen = () => {
ws.send(JSON.stringify({
type: 'chat',
message: 'What is the capital of France?',
sessionId: null
}));
};

ws.onmessage = (event) => {
const data = JSON.parse(event.data);
if (data.type === 'text') {
console.log(data.content);
}
};

Attaching the TUI to a Remote Server

Connect your local terminal UI to a running OpenCode server:

opencode attach http://hostname:4096

If the server requires authentication:

OPENCODE_SERVER_PASSWORD="my-secret-key" opencode attach http://hostname:4096

Scripted Access

Run prompts non-interactively while attaching to a running server:

opencode run --attach http://localhost:4096 "Refactor the auth module to use JWT"

This sends the prompt through the server, streams the response to stdout, then exits. Combine with shell scripts for automation:

#!/bin/bash
result=$(opencode run --attach http://localhost:4096 "$1")
echo "$result" | grep -A5 '```' | head -20

mDNS Discovery

When mdns is enabled, OpenCode advertises itself on the local network. Other OpenCode instances and tools can discover the server automatically:

opencode attach opencode://myproject.local

This is especially useful in team environments where multiple developers share a build server or when running OpenCode on a workstation from a laptop.

CORS

When building web applications that communicate with the OpenCode server, list allowed origins in the cors array:

{
"server": {
"cors": ["http://localhost:5173", "https://my-app.example.com"]
}
}

The server responds with the appropriate Access-Control-Allow-Origin header for matching origins. Credentials (cookies, auth headers) are supported when the origin is explicitly listed.

Docker Deployment

FROM node:20-alpine
RUN npm install -g opencode-ai
EXPOSE 4096
ENV OPENCODE_SERVER_PASSWORD="change-me"
CMD ["opencode", "serve"]
docker build -t opencode-server .
docker run -d -p 4096:4096 --name opencode opencode-server

Systemd Service

[Unit]
Description=OpenCode Server
After=network.target

[Service]
Type=simple
User=opencode
Environment=OPENCODE_SERVER_PASSWORD=change-me
ExecStart=/usr/bin/opencode serve
Restart=on-failure
RestartSec=5

[Install]
WantedBy=multi-user.target