From 3c98e9f1ef6c81cd44f9f6f20687f4df8ddea749 Mon Sep 17 00:00:00 2001 From: Benjamin Date: Mon, 8 Jun 2026 23:43:50 +0200 Subject: [PATCH] fix: probe container bridge network IP in healthcheck (#3151) (#3434) Integrated into release/v3.8.17 --- scripts/dev/healthcheck.mjs | 33 ++++++++++++++++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) diff --git a/scripts/dev/healthcheck.mjs b/scripts/dev/healthcheck.mjs index c54e876e27..56acaae205 100644 --- a/scripts/dev/healthcheck.mjs +++ b/scripts/dev/healthcheck.mjs @@ -11,13 +11,36 @@ * error, so the container was reported `unhealthy` with an empty, undiagnosable * `State.Health[].Output`. We now try an ordered list of hosts and surface the * last error on total failure. + * + * Bridge Network Fix: Also probes the container's internal bridge IP (e.g., 172.17.0.2) + * to handle Docker network setups that isolate loopback interfaces. */ import { pathToFileURL } from "node:url"; +import { networkInterfaces } from "node:os"; const DEFAULT_HOSTS = ["127.0.0.1", "localhost", "::1"]; const DEFAULT_TIMEOUT_MS = 4000; +/** + * Get the primary non-loopback IPv4 address (container internal IP). + * Falls back to null if unable to determine. + */ +function getContainerInternalIP() { + try { + const interfaces = networkInterfaces(); + for (const [name, addrs] of Object.entries(interfaces)) { + // Skip loopback and docker0, prioritize eth0/veth interfaces + if (name.startsWith("lo") || name === "docker0") continue; + const ipv4 = addrs?.find((a) => a.family === "IPv4" && !a.internal); + if (ipv4) return ipv4.address; + } + } catch { + // silently ignore if unable to read interfaces + } + return null; +} + /** * Build the health URL for a host, bracketing IPv6 literals (e.g. `::1`). * @param {string} host @@ -64,8 +87,16 @@ export async function probeHealth({ async function main() { const port = process.env.DASHBOARD_PORT || process.env.PORT || "20128"; + + // Build host list: defaults + detected container bridge IP + const hosts = [...DEFAULT_HOSTS]; + const containerIP = getContainerInternalIP(); + if (containerIP && !hosts.includes(containerIP)) { + hosts.push(containerIP); + } + try { - await probeHealth({ port }); + await probeHealth({ port, hosts }); process.exit(0); } catch (err) { // Surface the failure so `docker inspect ... .State.Health[].Output` is