From 72f9ba8a99777af06e12e5aeb448399fbd2eac75 Mon Sep 17 00:00:00 2001 From: redshift <213178690+1ftredsh@users.noreply.github.com> Date: Sat, 25 Jul 2026 22:05:13 +0100 Subject: [PATCH] refactor: trim host binding changes --- README.md | 8 ++------ src/daemon/args.ts | 3 +-- src/daemon/index.ts | 13 ------------- src/start-daemon.ts | 9 +++------ src/utils/config.ts | 2 -- src/utils/daemon-client.ts | 7 +------ 6 files changed, 7 insertions(+), 35 deletions(-) diff --git a/README.md b/README.md index 9433e01..4b85baf 100644 --- a/README.md +++ b/README.md @@ -74,15 +74,12 @@ With custom port: routstrd start --port 9000 ``` -With a specific bind address (default is `127.0.0.1` for security): +The daemon binds to `127.0.0.1` by default. To expose it on another interface: ```sh routstrd start --host 0.0.0.0 ``` -> ⚠️ **Security note:** By default, routstrd binds to `127.0.0.1` (localhost only). -> Several endpoints (e.g. `/balance`, `/status`, `/providers`) do not require -> authentication and will leak sensitive information if exposed. Only bind to -> `0.0.0.0` if you have a firewall or reverse proxy in place. +Only expose the daemon behind appropriate network controls. With specific provider: ```sh @@ -160,7 +157,6 @@ Configuration is stored in `~/.routstrd/config.json`: - `ROUTSTRD_DIR` - Config directory (default: `~/.routstrd`) - `ROUTSTRD_SOCKET` - Socket path (default: `~/.routstrd/routstrd.sock`) - `ROUTSTRD_PID` - PID file path (default: `~/.routstrd/routstrd.pid`) -- `ROUTSTRD_HOST` - Bind address override (default: `127.0.0.1`) ## Development diff --git a/src/daemon/args.ts b/src/daemon/args.ts index 77226f6..79edeb4 100644 --- a/src/daemon/args.ts +++ b/src/daemon/args.ts @@ -14,10 +14,9 @@ export function parseArgs(argv: string[]): { ? Number.parseInt(argv[portFlagIndex + 1] || "8008", 10) : 8008; - // --host flag takes precedence, then ROUTSTRD_HOST env var const hostValue = hostFlagIndex !== -1 ? argv[hostFlagIndex + 1] : undefined; - const host = hostValue ? hostValue.trim() : (process.env.ROUTSTRD_HOST || null); + const host = hostValue?.trim() || null; const providerValue = providerFlagIndex !== -1 ? argv[providerFlagIndex + 1] : undefined; diff --git a/src/daemon/index.ts b/src/daemon/index.ts index 02470bc..52e1422 100644 --- a/src/daemon/index.ts +++ b/src/daemon/index.ts @@ -305,19 +305,6 @@ async function main(): Promise { process.once("SIGINT", shutdownForSignal); process.once("SIGTERM", shutdownForSignal); - // Warn when binding to all interfaces — unauthenticated endpoints expose - // balance info, provider lists, and internal state to anyone who can reach - // the port. - if (host === "0.0.0.0") { - logger.warn( - "⚠️ WARNING: Daemon is bound to 0.0.0.0 (all network interfaces). " + - "Several endpoints (e.g. /balance, /status, /providers) do not require " + - "authentication and will leak sensitive information to anyone on the " + - "network. Consider binding to 127.0.0.1 unless you have a firewall or " + - "reverse proxy in place.", - ); - } - server.listen(port, host, async () => { logger.log(`Routstr daemon listening on http://${host}:${port}/v1`); if (requestResponseLogDir) { diff --git a/src/start-daemon.ts b/src/start-daemon.ts index 2bfcf46..c3ac308 100644 --- a/src/start-daemon.ts +++ b/src/start-daemon.ts @@ -27,7 +27,7 @@ function readDaemonOutput(offset: number): string { } } -async function isDaemonHealthy(port: string, host: string = "localhost"): Promise { +async function isDaemonHealthy(port: string, host = "127.0.0.1"): Promise { const controller = new AbortController(); const timeoutId = setTimeout(() => controller.abort(), 2000); try { @@ -42,11 +42,8 @@ async function isDaemonHealthy(port: string, host: string = "localhost"): Promis } } -/** When the daemon binds to 0.0.0.0, the CLI must still connect via - * localhost (or 127.0.0.1) since 0.0.0.0 is not a connectable address. */ -function clientHost(host: string | undefined): string { - if (!host || host === "0.0.0.0") return "localhost"; - return host; +function clientHost(host?: string): string { + return !host || host === "0.0.0.0" ? "127.0.0.1" : host; } async function startDaemonUnlocked( diff --git a/src/utils/config.ts b/src/utils/config.ts index 8e160bf..2ebe28f 100644 --- a/src/utils/config.ts +++ b/src/utils/config.ts @@ -32,8 +32,6 @@ export interface NwcConfig { export interface RoutstrdConfig { port: number; - /** Bind address for the HTTP server. Defaults to 127.0.0.1 (localhost only) - * for security — set to 0.0.0.0 to listen on all interfaces. */ host: string; provider: string | null; cocodPath: string | null; diff --git a/src/utils/daemon-client.ts b/src/utils/daemon-client.ts index f3177a3..ff27906 100644 --- a/src/utils/daemon-client.ts +++ b/src/utils/daemon-client.ts @@ -33,12 +33,7 @@ export function getDaemonBaseUrl(config: RoutstrdConfig): string { if (config.daemonUrl) { return config.daemonUrl.replace(/\/$/, ""); } - // When bound to 0.0.0.0, connect via localhost since 0.0.0.0 is not - // a connectable address from a client perspective. - const host = - !config.host || config.host === "0.0.0.0" - ? "localhost" - : config.host; + const host = config.host === "0.0.0.0" ? "127.0.0.1" : config.host; return `http://${host}:${config.port}`; }