Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions packages/opencode/src/cli/cmd/serve.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,7 @@ export const ServeCommand = cmd({
}
const opts = await resolveNetworkOptions(args)
const server = Server.listen(opts)
const displayUrl = opts.rootPath ? new URL(opts.rootPath, `http://${server.hostname}:${server.port}`).toString() : `http://${server.hostname}:${server.port}`
console.log(`opencode server listening on ${displayUrl}`)
console.log(`opencode server listening on http://${server.hostname}:${server.port}`)
await new Promise(() => {})
await server.stop()
},
Expand Down
9 changes: 4 additions & 5 deletions packages/opencode/src/cli/cmd/web.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,18 +44,17 @@ export const WebCommand = cmd({

if (opts.hostname === "0.0.0.0") {
// Show localhost for local access
const baseUrl = opts.rootPath ? new URL(opts.rootPath, `http://localhost:${server.port}`).toString() : `http://localhost:${server.port}`
UI.println(UI.Style.TEXT_INFO_BOLD + " Local access: ", UI.Style.TEXT_NORMAL, baseUrl)
const localhostUrl = `http://localhost:${server.port}`
UI.println(UI.Style.TEXT_INFO_BOLD + " Local access: ", UI.Style.TEXT_NORMAL, localhostUrl)

// Show network IPs for remote access
const networkIPs = getNetworkIPs()
if (networkIPs.length > 0) {
for (const ip of networkIPs) {
const networkUrl = opts.rootPath ? new URL(opts.rootPath, `http://${ip}:${server.port}`).toString() : `http://${ip}:${server.port}`
UI.println(
UI.Style.TEXT_INFO_BOLD + " Network access: ",
UI.Style.TEXT_NORMAL,
networkUrl,
`http://${ip}:${server.port}`,
)
}
}
Expand All @@ -69,7 +68,7 @@ export const WebCommand = cmd({
}

// Open localhost in browser
open(baseUrl.toString()).catch(() => {})
open(localhostUrl.toString()).catch(() => {})
} else {
const displayUrl = server.url.toString()
UI.println(UI.Style.TEXT_INFO_BOLD + " Web interface: ", UI.Style.TEXT_NORMAL, displayUrl)
Expand Down
13 changes: 1 addition & 12 deletions packages/opencode/src/cli/network.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,6 @@ const options = {
describe: "additional domains to allow for CORS",
default: [] as string[],
},
rootPath: {
type: "string" as const,
describe: "base path for reverse proxy",
default: "",
},
}

export type NetworkOptions = InferredOptionTypes<typeof options>
Expand All @@ -42,7 +37,6 @@ export async function resolveNetworkOptions(args: NetworkOptions) {
const hostnameExplicitlySet = process.argv.includes("--hostname")
const mdnsExplicitlySet = process.argv.includes("--mdns")
const corsExplicitlySet = process.argv.includes("--cors")
const rootPathExplicitlySet = process.argv.includes("--root-path")

const mdns = mdnsExplicitlySet ? args.mdns : (config?.server?.mdns ?? args.mdns)
const port = portExplicitlySet ? args.port : (config?.server?.port ?? args.port)
Expand All @@ -54,11 +48,6 @@ export async function resolveNetworkOptions(args: NetworkOptions) {
const configCors = config?.server?.cors ?? []
const argsCors = Array.isArray(args.cors) ? args.cors : args.cors ? [args.cors] : []
const cors = [...configCors, ...argsCors]
const rootPath = rootPathExplicitlySet ? args.rootPath : (config?.server?.rootPath ?? args.rootPath)

if (rootPath && !rootPath.startsWith("/")) {
throw new Error(`rootPath must start with '/' if provided (got: '${rootPath}')`)
}

return { hostname, port, mdns, cors, rootPath }
return { hostname, port, mdns, cors }
}
1 change: 0 additions & 1 deletion packages/opencode/src/config/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -854,7 +854,6 @@ export namespace Config {
hostname: z.string().optional().describe("Hostname to listen on"),
mdns: z.boolean().optional().describe("Enable mDNS service discovery"),
cors: z.array(z.string()).optional().describe("Additional domains to allow for CORS"),
rootPath: z.string().optional().describe("Base path for reverse proxy"),
})
.strict()
.meta({
Expand Down
10 changes: 3 additions & 7 deletions packages/opencode/src/server/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -563,17 +563,13 @@ export namespace Server {
return result
}

export function listen(opts: { port: number; hostname: string; mdns?: boolean; cors?: string[]; rootPath?: string }) {
export function listen(opts: { port: number; hostname: string; mdns?: boolean; cors?: string[] }) {
_corsWhitelist = opts.cors ?? []

// When rootPath is provided (for reverse proxy support), wrap the main app with a base path prefix.
// Hono's basePath() automatically prefixes all routes, including WebSocket upgrades.
const baseApp = opts.rootPath ? new Hono().basePath(opts.rootPath).route("/", App()) : App()

const args = {
hostname: opts.hostname,
idleTimeout: 0,
fetch: baseApp.fetch,
fetch: App().fetch,
websocket: websocket,
} as const
const tryServe = (port: number) => {
Expand All @@ -586,7 +582,7 @@ export namespace Server {
const server = opts.port === 0 ? (tryServe(4096) ?? tryServe(0)) : tryServe(opts.port)
if (!server) throw new Error(`Failed to start server on port ${opts.port}`)

_url = opts.rootPath ? new URL(opts.rootPath, server.url) : server.url
_url = server.url

const shouldPublishMDNS =
opts.mdns &&
Expand Down
67 changes: 0 additions & 67 deletions packages/opencode/test/server/rootpath.test.ts

This file was deleted.

2 changes: 0 additions & 2 deletions packages/web/src/content/docs/cli.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -368,7 +368,6 @@ This starts an HTTP server that provides API access to opencode functionality wi
| `--hostname` | Hostname to listen on |
| `--mdns` | Enable mDNS discovery |
| `--cors` | Additional browser origin(s) to allow CORS |
| `--root-path` | Base path for reverse proxy |

---

Expand Down Expand Up @@ -465,7 +464,6 @@ This starts an HTTP server and opens a web browser to access OpenCode through a
| `--hostname` | Hostname to listen on |
| `--mdns` | Enable mDNS discovery |
| `--cors` | Additional browser origin(s) to allow CORS |
| `--root-path` | Base path for reverse proxy |

---

Expand Down
4 changes: 1 addition & 3 deletions packages/web/src/content/docs/config.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -190,8 +190,7 @@ You can configure server settings for the `opencode serve` and `opencode web` co
"port": 4096,
"hostname": "0.0.0.0",
"mdns": true,
"cors": ["http://localhost:5173"],
"rootPath": "/proxy"
"cors": ["http://localhost:5173"]
}
}
```
Expand All @@ -202,7 +201,6 @@ Available options:
- `hostname` - Hostname to listen on. When `mdns` is enabled and no hostname is set, defaults to `0.0.0.0`.
- `mdns` - Enable mDNS service discovery. This allows other devices on the network to discover your OpenCode server.
- `cors` - Additional origins to allow for CORS when using the HTTP server from a browser-based client. Values must be full origins (scheme + host + optional port), eg `https://app.example.com`.
- `rootPath` - Base path for reverse proxy. All routes will be prefixed with this path.

[Learn more about the server here](/docs/server).

Expand Down
9 changes: 1 addition & 8 deletions packages/web/src/content/docs/server.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ The `opencode serve` command runs a headless HTTP server that exposes an OpenAPI
### Usage

```bash
opencode serve [--port <number>] [--hostname <string>] [--cors <origin>] [--root-path <path>]
opencode serve [--port <number>] [--hostname <string>] [--cors <origin>]
```

#### Options
Expand All @@ -24,20 +24,13 @@ opencode serve [--port <number>] [--hostname <string>] [--cors <origin>] [--root
| `--hostname` | Hostname to listen on | `127.0.0.1` |
| `--mdns` | Enable mDNS discovery | `false` |
| `--cors` | Additional browser origins to allow | `[]` |
| `--root-path` | Base path for reverse proxy | (empty) |

`--cors` can be passed multiple times:

```bash
opencode serve --cors http://localhost:5173 --cors https://app.example.com
```

Use `--root-path` when running behind a reverse proxy:

```bash
opencode serve --root-path /jupyter/proxy/opencode
```

---

### Authentication
Expand Down