From f5f26d36f207544847ebf3e14672a0547e66bc7e Mon Sep 17 00:00:00 2001 From: Rob Murray Date: Mon, 17 Aug 2026 12:51:49 +0100 Subject: [PATCH] Sandboxes: published ports now default to IPv4 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Docker Sandboxes 0.39 publishes a port on IPv4 only when no protocol is named, where it previously bound both address families. That removes a dead end: a dual-stack binding forwarded a host connection arriving on ::1 to the sandbox's IPv6 address, where a service listening only on IPv4 never answered, and the connection was accepted and then reset — which no client recovers from, unlike a refusal. Three pages described the old behaviour: - the kit reference said an empty `protocol` meant `tcp`, and its example spelled out `protocol: tcp`, which now opts a kit out of the default and back into the dead end; - the workflows guide told readers to work around dual-stack publishing by pinning `/tcp4` themselves; - both the workflows and usage pages showed `sbx ls` reporting `/tcp` for a defaulted publish. --- .../ai/sandboxes/customize/kit-reference.md | 11 +++++++---- content/manuals/ai/sandboxes/usage.md | 2 +- content/manuals/ai/sandboxes/workflows.md | 16 +++++++++------- 3 files changed, 17 insertions(+), 12 deletions(-) diff --git a/content/manuals/ai/sandboxes/customize/kit-reference.md b/content/manuals/ai/sandboxes/customize/kit-reference.md index c1261960b4e8..f6e8543b982d 100644 --- a/content/manuals/ai/sandboxes/customize/kit-reference.md +++ b/content/manuals/ai/sandboxes/customize/kit-reference.md @@ -346,18 +346,21 @@ Use `ports` to expose sandbox services to the host: ```yaml ports: - container: 8080 - protocol: tcp name: web ``` | Field | Description | | ----------- | ------------------------------------------------------------------- | | `container` | Container port, 1 to 65535. | -| `protocol` | `tcp` or `udp`. Empty means `tcp`. | +| `protocol` | `tcp` or `udp`. Empty publishes one family; see below. | | `name` | Optional label surfaced by tools that list published port bindings. | -Host ports are allocated ephemerally on `127.0.0.1`. Users can pin host ports -with `sbx ports --publish :`. +Host ports are allocated ephemerally. Leave `protocol` empty unless the service +listens on IPv6: an empty value publishes IPv4 only (`127.0.0.1`), which is what +a service bound to `0.0.0.0` needs, while `tcp` publishes both `127.0.0.1` and +`::1` — and a client arriving over `::1` is accepted and then reset if nothing +in the sandbox is listening there. Users can pin host ports with +`sbx ports --publish :`. ## Environment diff --git a/content/manuals/ai/sandboxes/usage.md b/content/manuals/ai/sandboxes/usage.md index ef4286e39b6b..0d372f8a4ce2 100644 --- a/content/manuals/ai/sandboxes/usage.md +++ b/content/manuals/ai/sandboxes/usage.md @@ -248,7 +248,7 @@ them in detail. ```console $ sbx ls SANDBOX AGENT STATUS PORTS WORKSPACE -my-sandbox claude running 127.0.0.1:8080->3000/tcp /home/user/proj +my-sandbox claude running 127.0.0.1:8080->3000/tcp4 /home/user/proj ``` To stop forwarding a port: diff --git a/content/manuals/ai/sandboxes/workflows.md b/content/manuals/ai/sandboxes/workflows.md index a6548de97f40..2414fd121905 100644 --- a/content/manuals/ai/sandboxes/workflows.md +++ b/content/manuals/ai/sandboxes/workflows.md @@ -330,7 +330,7 @@ lists them in detail: ```console $ sbx ls SANDBOX AGENT STATUS PORTS WORKSPACE -my-sandbox claude running 127.0.0.1:8080->3000/tcp /home/user/proj +my-sandbox claude running 127.0.0.1:8080->3000/tcp4 /home/user/proj ``` To stop forwarding a port: @@ -342,12 +342,14 @@ $ sbx ports my-sandbox --unpublish 8080:3000 For a service to be reachable, it must listen on all interfaces inside the sandbox, not only `127.0.0.1`. Bind it to `0.0.0.0` for IPv4 or `[::]` for both IPv4 and IPv6. Most dev servers need a flag like `--host 0.0.0.0` to do this. -On the host, `--publish` listens on both `127.0.0.1` and `::1`, so a client -resolving `localhost` might pick IPv6 and fail with "connection reset by peer" -if the sandboxed service only listens on IPv4, even when -`http://127.0.0.1:/` works. To fix that, bind the service to `[::]`, or -pin the published port to one family with `--publish 8080:3000/tcp4` or -`/tcp6`. + +On the host, a published port binds IPv4 (`127.0.0.1`) unless you name another +protocol, so `http://localhost:/` reaches a service listening on IPv4 +whichever address your resolver picks for `localhost`. To publish on both +families use `--publish 8080:3000/tcp`, and for IPv6 alone `/tcp6`. Both of +those require the sandboxed service to listen on IPv6 as well — bind it to +`[::]` — or a client arriving over `::1` has its connection accepted and then +reset. Published ports survive restarts: `sbx` re-publishes them when the sandbox or the daemon restarts. Explicit host ports are reused, while a port published with