Skip to content

fix(docker): derive the HEALTHCHECK probe address from HOST - #2504

Merged
cliffhall merged 4 commits into
v2/mainfrom
v2/fix/2424-healthcheck-host
Sep 26, 2026
Merged

cliffhall merged 4 commits into
v2/mainfrom
v2/fix/2424-healthcheck-host

Conversation

@cliffhall

Copy link
Copy Markdown
Member

Closes #2424

What

The Docker HEALTHCHECK fetched a hardcoded http://127.0.0.1:$CLIENT_PORT/. That agrees with the image's default HOST=0.0.0.0 only because a wildcard bind also listens on loopback. Overriding HOST to one interface (-e HOST=172.17.0.2) left the server running fine while the container reported unhealthy. This is the narrowed diagnosis from the maintainer comment. Of the two shapes it proposed, this PR takes the first: derive the probe address from HOST.

How

  • scripts/docker-healthcheck.mjs (new): builds the probe URL from HOST and CLIENT_PORT. HOST is a bind address, so a wildcard is mapped to the loopback of its own address family: 0.0.0.0, ::ffff:0:0 and an empty value go to 127.0.0.1, and :: goes to [::1]. Any other host is probed as given, with IPv6 bracketed and a zone id stripped. Legacy spellings (HOST=0, 0x0, ::0) are canonicalized with new URL(), the same primitive core/node/hostUrl.ts uses. The image installs only the packed tarball and cannot import core/. A HOST no server could bind makes the probe exit 1 (unhealthy) rather than crash.
  • Dockerfile: copies the script from the builder stage into the runtime stage and runs it as HEALTHCHECK CMD ["node", …]. The probe is a file rather than the old node -e one-liner so that it can be tested.
  • Docs: docs/docker.md says the healthcheck follows HOST. The README scripts/ entry mentions the probe.

Verification

  • scripts/docker-healthcheck.test.mjs (24 tests, runs under test:scripts):
    • a HOST → URL table
    • probe() against a real listener: 2xx, 503, nothing listening, and an unparseable host
    • a Dockerfile check that the HEALTHCHECK runs the exact path the runtime stage copies to
  • Built the image and ran it on a user-defined network:
Container Health
--ip 172.30.0.10 -e HOST=172.30.0.10 healthy
default (HOST=0.0.0.0) healthy
old inline probe, docker exec in the pinned container exit 1 (the bug)
new probe, same container exit 0
  • npm run local:gate is green.

🤖 Generated with Claude Code

The probe fetched a hardcoded 127.0.0.1, which agrees with the image's
default HOST=0.0.0.0 only because a wildcard bind also listens on
loopback. Pinning HOST to one interface left the server healthy but the
container reported unhealthy.

Move the probe into scripts/docker-healthcheck.mjs, copied into the
runtime stage, and connect to the address HOST binds, mapping a wildcard
to the loopback of its own family. Covered by node --test.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Signed-off-by: cliffhall <cliff@futurescale.com>
@cliffhall cliffhall added the v2 Issues and PRs for v2 label Sep 26, 2026
@cliffhall cliffhall linked an issue Sep 26, 2026 that may be closed by this pull request
2 tasks done
@cliffhall
cliffhall requested a balanced review from Copilot September 26, 2026 03:53

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

🟡 Changes recommended

Port whitespace handling and scoped IPv6 addresses can still make a running container unhealthy.

Review effort: Balanced
Findings: 2 Medium severity

Open (2)
What changed in this PR

Fixes #2424 by deriving the Docker healthcheck target from the configured bind address.

Changes:

  • Adds a tested healthcheck probe with wildcard handling.
  • Runs the probe from the Docker runtime image.
  • Documents HOST-aware healthchecks.
File Description
scripts/​docker-healthcheck.mjs Builds and probes the healthcheck URL.
scripts/​docker-healthcheck.test.mjs Tests address derivation, probing, and Docker wiring.
Dockerfile Installs and runs the new probe.
docs/​docker.md Documents healthcheck behavior.
README.md Adds the probe to the repository map.

💡 Add a code-review agent skill for context-aware, tailored reviews. Learn more in the docs.

Comment thread scripts/docker-healthcheck.mjs Resolved
Comment thread scripts/docker-healthcheck.mjs Resolved
cliffhall and others added 3 commits September 25, 2026 23:57
…does (#2504 review)

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Signed-off-by: cliffhall <cliff@futurescale.com>
@cliffhall

Copy link
Copy Markdown
Member Author

Copilot round 1: 2 findings, replied inline in each thread.

  • CLIENT_PORT whitespace (fixed, 8841ea9): now trimmed, with an empty value treated as unset, as the server does. Tests added.
  • IPv6 zone ids (declined as out of scope): a link-local bind was unhealthy before this PR too. Supporting it needs a different HTTP API, which is a new capability. The header comment now documents the limitation.

The branch also picked up the v2/main update (#2499, CLI files only). Requesting round 2.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

🟢 Approval recommended

The implementation addresses the linked issue with focused tests and consistent documentation.

Review effort: Balanced
Findings: None

Resolved since last review (2)

@cliffhall
cliffhall merged commit b26b8fa into v2/main Sep 26, 2026
5 checks passed
@cliffhall
cliffhall deleted the v2/fix/2424-healthcheck-host branch September 26, 2026 04:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

v2 Issues and PRs for v2

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Docker HEALTHCHECK hardcodes 127.0.0.1 while HOST defaults to 0.0.0.0

2 participants