Skip to content

fix(code-server): stop pinning both address families on 8080 - #208

Draft
robmry wants to merge 1 commit into
mainfrom
fix/code-server-default-port-protocol
Draft

fix(code-server): stop pinning both address families on 8080#208
robmry wants to merge 1 commit into
mainfrom
fix/code-server-default-port-protocol

Conversation

@robmry

@robmry robmry commented Aug 17, 2026

Copy link
Copy Markdown

code-server runs code-server --bind-addr 0.0.0.0:8080 inside the sandbox — IPv4 only — while the kit pinned protocol: tcp, which publishes both address families. On a host whose resolver answers localhost with ::1 first, opening http://localhost:<port>/ therefore reached the sandbox over IPv6, where nothing was listening, and the connection was accepted and then reset. That is a dead end no client recovers from, unlike a refusal, and it is the exact complaint behind docker/sbx-releases#342.

docker/sandboxes#4994 addresses that consumer-side, by publishing a single address family when no protocol is named — but a kit that spells out protocol: tcp opts back out of it, so this kit would keep the broken behaviour. Since the spec accepts only "", "tcp" and "udp" (until #163 is merged), omitting the field is how a kit stops demanding both, so the line is dropped and a comment records why it must stay dropped.

Safe to land before the consumer change ships

This kit goes live on merge, while docker/sandboxes#4994 is not in a release yet. Both cases are fine:

  • an sbx that resolves an empty protocol to dual-stack tcp reproduces exactly what the pinned value did, so nothing regresses for anyone running one today;
  • an sbx that resolves it to one family fixes the dead end, and this kit picks that up with no further edit.

That is also why none of the comments here name a version or state what the default is: the same spec is read by consumers on both sides of that change.

Spec documentation

The spec asserted an equivalence between an empty protocol and tcp in two places. Both now describe the contract instead — empty defers to the consumer, naming a protocol asks for both families and so needs a service listening on IPv6 — without claiming what any particular consumer does:

  • spec/types.go on PublishedPort.Protocol
  • the ports: example in spec/SPEC-v2.md

The validation rule is unchanged: protocol is still one of "", tcp, udp.

Other kits

I checked every kit that declares ports. codex-app-server also pins protocol: tcp, for sshd on 22 — left alone deliberately, since sshd listens on both families by default, so dual-stack publishing is correct there. nanoclaw omits the protocol already and picks up the new default with no change.

🤖 Raised by Claude Code on behalf of @robmry.

@robmry
robmry force-pushed the fix/code-server-default-port-protocol branch from 1525e20 to 368ed4d Compare August 17, 2026 12:54
code-server binds 0.0.0.0:8080 inside the sandbox — IPv4 only — while the
kit pinned `protocol: tcp`, which asks for both address families. A host
client whose resolver answers `localhost` with ::1 first therefore reached
the sandbox over IPv6, where nothing was listening, and had its connection
accepted and then reset: a dead end no client recovers from, unlike a
refusal.

Omit the protocol instead, so the consumer decides which families to
publish and the kit never asks for one this service cannot serve. The spec
accepts only "", "tcp" and "udp", so omitting the field is the only way to
stop demanding both.

This is safe to land ahead of any consumer change. A consumer that resolves
an empty protocol to dual-stack `tcp` reproduces exactly the behaviour the
pinned value had, so nothing regresses for anyone running one today; a
consumer that resolves it to a single family fixes the dead end, and the
kit picks that up with no further edit.

The spec's own documentation asserted an equivalence between an empty
protocol and "tcp". Since the same spec is read by consumers that publish
one family and consumers that publish both, `spec/types.go` and the
`SPEC-v2.md` example now describe the contract — empty defers to the
consumer, naming a protocol asks for both families — without claiming what
any particular consumer does.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: Rob Murray <rob.murray@docker.com>
@robmry
robmry force-pushed the fix/code-server-default-port-protocol branch from 368ed4d to 48b6fa0 Compare August 17, 2026 13:05
@robmry robmry changed the title fix(code-server): publish 8080 on the host's default protocol fix(code-server): stop pinning both address families on 8080 Aug 17, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant