fix(server): honor --host binding

Fixes #75
This commit is contained in:
Shantur Rathore
2026-01-20 18:43:54 +00:00
parent 9683f90f7e
commit e08ebb2057
3 changed files with 32 additions and 10 deletions

View File

@@ -127,10 +127,18 @@ function parsePort(input: string): number {
} }
function resolveHost(input: string | undefined): string { function resolveHost(input: string | undefined): string {
if (input && input.trim() === "0.0.0.0") { const trimmed = input?.trim()
if (!trimmed) return DEFAULT_HOST
if (trimmed === "0.0.0.0") {
return "0.0.0.0" return "0.0.0.0"
} }
return DEFAULT_HOST
if (trimmed === "localhost") {
return DEFAULT_HOST
}
return trimmed
} }
async function main() { async function main() {
@@ -149,11 +157,13 @@ async function main() {
const eventBus = new EventBus(eventLogger) const eventBus = new EventBus(eventLogger)
const isLoopbackHost = (host: string) => host === "127.0.0.1" || host === "::1" || host.startsWith("127.")
const serverMeta: ServerMeta = { const serverMeta: ServerMeta = {
httpBaseUrl: `http://${options.host}:${options.port}`, httpBaseUrl: `http://${options.host}:${options.port}`,
eventsUrl: `/api/events`, eventsUrl: `/api/events`,
host: options.host, host: options.host,
listeningMode: options.host === "0.0.0.0" ? "all" : "local", listeningMode: isLoopbackHost(options.host) ? "local" : "all",
port: options.port, port: options.port,
hostLabel: options.host, hostLabel: options.host,
workspaceRoot: options.rootDir, workspaceRoot: options.rootDir,

View File

@@ -93,6 +93,7 @@ export function createHttpServer(deps: HttpServerDeps) {
}) })
const allowedDevOrigins = new Set(["http://localhost:3000", "http://127.0.0.1:3000"]) const allowedDevOrigins = new Set(["http://localhost:3000", "http://127.0.0.1:3000"])
const isLoopbackHost = (host: string) => host === "127.0.0.1" || host === "::1" || host.startsWith("127.")
app.register(cors, { app.register(cors, {
origin: (origin, cb) => { origin: (origin, cb) => {
@@ -113,10 +114,17 @@ export function createHttpServer(deps: HttpServerDeps) {
return return
} }
if (allowedDevOrigins.has(origin)) { if (allowedDevOrigins.has(origin)) {
cb(null, true) cb(null, true)
return return
} }
// When we bind to a non-loopback host (e.g., 0.0.0.0 or LAN IP), allow cross-origin UI access.
if (deps.host === "0.0.0.0" || !isLoopbackHost(deps.host)) {
cb(null, true)
return
}
cb(null, false) cb(null, false)
}, },
@@ -275,13 +283,13 @@ export function createHttpServer(deps: HttpServerDeps) {
} }
} }
const displayHost = deps.host === "0.0.0.0" ? "127.0.0.1" : deps.host === "127.0.0.1" ? "localhost" : deps.host const displayHost = deps.host === "127.0.0.1" ? "localhost" : deps.host
const serverUrl = `http://${displayHost}:${actualPort}` const serverUrl = `http://${displayHost}:${actualPort}`
deps.serverMeta.httpBaseUrl = serverUrl deps.serverMeta.httpBaseUrl = serverUrl
deps.serverMeta.host = deps.host deps.serverMeta.host = deps.host
deps.serverMeta.port = actualPort deps.serverMeta.port = actualPort
deps.serverMeta.listeningMode = deps.host === "0.0.0.0" ? "all" : "local" deps.serverMeta.listeningMode = deps.host === "0.0.0.0" || !isLoopbackHost(deps.host) ? "all" : "local"
deps.logger.info({ port: actualPort, host: deps.host }, "HTTP server listening") deps.logger.info({ port: actualPort, host: deps.host }, "HTTP server listening")
console.log(`CodeNomad Server is ready at ${serverUrl}`) console.log(`CodeNomad Server is ready at ${serverUrl}`)

View File

@@ -17,7 +17,7 @@ function buildMetaResponse(meta: ServerMeta): ServerMeta {
return { return {
...meta, ...meta,
port, port,
listeningMode: meta.host === "0.0.0.0" ? "all" : "local", listeningMode: meta.host === "0.0.0.0" || !isLoopbackHost(meta.host) ? "all" : "local",
addresses, addresses,
} }
} }
@@ -35,6 +35,10 @@ function resolvePort(meta: ServerMeta): number {
} }
} }
function isLoopbackHost(host: string): boolean {
return host === "127.0.0.1" || host === "::1" || host.startsWith("127.")
}
function resolveAddresses(port: number, host: string): NetworkAddress[] { function resolveAddresses(port: number, host: string): NetworkAddress[] {
const interfaces = os.networkInterfaces() const interfaces = os.networkInterfaces()
const seen = new Set<string>() const seen = new Set<string>()