fix: bind web server to 127.0.0.1 by default and add --host CLI flag (#750)

## Summary

Fixes #736 — OpenChamber listens on `0.0.0.0` (all interfaces) by default, exposing the server to the network without warning. The log output shows `visit: http://127.0.0.1:...` which is misleading.

## Changes

- **Default bind address changed to `127.0.0.1`** — server is only accessible locally unless explicitly configured otherwise
- **New `--host` CLI flag** — `openchamber --host 0.0.0.0 -p 8080` to listen on all interfaces
- **`OPENCHAMBER_HOST` env var** — documented in help text and docker-compose.yml as an alternative to `--host`
- **Docker entrypoint** defaults to `OPENCHAMBER_HOST=0.0.0.0` so container port mapping continues to work
- **Startup logs** show the actual bind address instead of hardcoded `localhost`

### Resolution priority

```
--host flag  >  OPENCHAMBER_HOST env var  >  127.0.0.1 (default)
```

### What doesn't break

- **Desktop app** — already forces `OPENCHAMBER_HOST=127.0.0.1` via Tauri
- **VS Code extension** — doesn't use the web server
- **Docker** — entrypoint sets `OPENCHAMBER_HOST=0.0.0.0`, preserving current behavior
- **Tunnels** — cloudflared connects to `127.0.0.1` origin internally, works regardless of bind address

## Testing

Automated:
- `bun run type-check` / `bun run lint` — pass

Manual (CLI, direct `node` execution):
- Default bind → `127.0.0.1` (verified via `lsof`/netstat)
- `--host 0.0.0.0` → binds all interfaces
- `--host=0.0.0.0` (inline) → works
- `--host` without value → error exit 2
- `OPENCHAMBER_HOST` env var → respected
- `--host` flag overrides env var
- IPv6 `::1` → correct bracketed URL, health check 200
- CLI daemon start/stop → works
- `visit:` URL → correct
- Help text → `--host` in OPTIONS, `OPENCHAMBER_HOST` in ENVIRONMENT
- Browser UI → loads and works
- Tunnel via UI → works
- Desktop app → no regression

Docker (tested on Ubuntu with native Docker):
- SSH key generated successfully
- `OpenChamber server listening on 0.0.0.0:3000`
- Health check 200
- `uid=1000(openchamber)` confirmed
This commit is contained in:
Iuliia Ivashko
2026-03-23 15:07:16 +02:00
committed by GitHub
parent fb57ee4cc3
commit dc100ed0da
5 changed files with 46 additions and 12 deletions
+17
View File
@@ -570,6 +570,7 @@ function parseArgs(argv = process.argv.slice(2)) {
const args = Array.isArray(argv) ? [...argv] : [];
const options = {
port: DEFAULT_PORT,
host: undefined,
uiPassword: process.env.OPENCHAMBER_UI_PASSWORD || undefined,
json: false,
all: false,
@@ -658,6 +659,15 @@ function parseArgs(argv = process.argv.slice(2)) {
options.explicitPort = true;
break;
}
case 'host': {
const { value, nextIndex } = consumeValue(i, inlineValue);
i = nextIndex;
if (typeof value !== 'string' || value.trim().length === 0) {
throw new TunnelCliError('Missing value for --host.', EXIT_CODE.USAGE_ERROR);
}
options.host = value.trim();
break;
}
case 'ui-password': {
const { value, nextIndex } = consumeValue(i, inlineValue);
i = nextIndex;
@@ -842,11 +852,13 @@ COMMANDS:
OPTIONS:
-p, --port Web server port (default: ${DEFAULT_PORT})
--host Bind address (default: 127.0.0.1)
--ui-password Protect browser UI with single password
-h, --help Show help
-v, --version Show version
ENVIRONMENT:
OPENCHAMBER_HOST Bind address (e.g. 0.0.0.0 for all interfaces)
OPENCHAMBER_UI_PASSWORD Alternative to --ui-password flag
OPENCHAMBER_DATA_DIR Override OpenChamber data directory
OPENCODE_HOST External OpenCode server base URL, e.g. http://hostname:4096
@@ -2730,6 +2742,10 @@ const commands = {
}
}
const serverArgs = [serverPath, '--port', String(targetPort)];
const effectiveHost = typeof options.host === 'string' && options.host.length > 0 ? options.host : undefined;
if (effectiveHost) {
serverArgs.push('--host', effectiveHost);
}
const serveSpin = showOutput ? createSpinner(options) : null;
@@ -2741,6 +2757,7 @@ const commands = {
...process.env,
OPENCHAMBER_PORT: String(targetPort),
OPENCODE_BINARY: opencodeBinary,
...(effectiveHost ? { OPENCHAMBER_HOST: effectiveHost } : {}),
...(effectiveUiPassword ? { OPENCHAMBER_UI_PASSWORD: effectiveUiPassword } : {}),
...(process.env.OPENCODE_SKIP_START ? { OPENCHAMBER_SKIP_OPENCODE_START: process.env.OPENCODE_SKIP_START } : {}),
},