Summary
When creating sandboxes with an egress sidecar, the randomly allocated host publish port can land in an OS-reserved port range that is invisible from inside the server container. Docker then fails the start with ports are not available / bind: ... forbidden by its access permissions, the whole sandbox creation returns HTTP 500, and there is no retry with a different port.
Environment
- OpenSandbox server 0.1.11 (Docker provider), running as a container
- Docker Desktop on Windows 11 (Linux containers) — host publish happens on the Windows host
- Multiple sandboxes created concurrently,
networkPolicy requiring an egress sidecar (each sandbox needs 2+ host ports)
Symptom
Sandbox creation intermittently fails (observed ~10–15% of concurrent batches), wrapped as:
Egress sidecar container failed to start.
Server logs (INFO/WARNING) show the real cause:
sandbox=44bee438-… | action=start egress sidecar | error=500 Server Error for http+docker://localhost/v1.55/containers/4e54dce2…/start:
Internal Server Error ("ports are not available: exposing port TCP 0.0.0.0:49870 -> 127.0.0.1:0:
listen tcp4 0.0.0.0:49870: bind: An attempt was made to access a socket in a way forbidden by its access permissions.")
On this host, netsh interface ipv4 show excludedportrange protocol=tcp shows Hyper-V/WinNAT reserved ranges such as 49845–49944, 50060–50359 — and the failing ports (49870, 50103 on two different attempts) both fell exactly inside those ranges. Retrying the same request succeeds.
Root cause
allocate_host_port() in server/opensandbox_server/services/docker/port_allocator.py probes availability with socket.bind() inside the server container (Linux network stack). On Docker Desktop/Windows the actual bind happens on the Windows host during docker start, where OS-reserved excluded port ranges make the bind fail with WSAEACCES — the container-side probe cannot see this.
_start_egress_sidecar() in networking.py only retries when the failure is the IPv6-sysctl rejection; any other start failure (including ports are not available) cleans up and raises HTTP 500 without re-allocating a new host port.
Suggested fix
- On
docker start failure with a port-publish error (ports are not available, bind: permission errors), re-allocate a different host port and retry the create/start once or twice before giving up — port conflicts are probabilistic on hosts with dynamic reserved ranges.
- Longer term: make the probe Docker-publish-aware (or allow configuring the host port pool so it can be kept clear of reserved ranges).
- Consider surfacing the original Docker error instead of only the generic message, so callers can distinguish port conflicts from other start failures.
Additional context
Host port allocation range is 40000–60000 (allocate_host_port defaults); OS-reserved ranges on Windows change between reboots, which is why the failure is intermittent and environment-dependent.
Summary
When creating sandboxes with an egress sidecar, the randomly allocated host publish port can land in an OS-reserved port range that is invisible from inside the server container. Docker then fails the
startwithports are not available/bind: ... forbidden by its access permissions, the whole sandbox creation returns HTTP 500, and there is no retry with a different port.Environment
networkPolicyrequiring an egress sidecar (each sandbox needs 2+ host ports)Symptom
Sandbox creation intermittently fails (observed ~10–15% of concurrent batches), wrapped as:
Server logs (INFO/WARNING) show the real cause:
On this host,
netsh interface ipv4 show excludedportrange protocol=tcpshows Hyper-V/WinNAT reserved ranges such as49845–49944,50060–50359— and the failing ports (49870,50103on two different attempts) both fell exactly inside those ranges. Retrying the same request succeeds.Root cause
allocate_host_port()inserver/opensandbox_server/services/docker/port_allocator.pyprobes availability withsocket.bind()inside the server container (Linux network stack). On Docker Desktop/Windows the actual bind happens on the Windows host duringdocker start, where OS-reserved excluded port ranges make the bind fail withWSAEACCES— the container-side probe cannot see this._start_egress_sidecar()innetworking.pyonly retries when the failure is the IPv6-sysctl rejection; any otherstartfailure (includingports are not available) cleans up and raises HTTP 500 without re-allocating a new host port.Suggested fix
docker startfailure with a port-publish error (ports are not available,bind:permission errors), re-allocate a different host port and retry the create/start once or twice before giving up — port conflicts are probabilistic on hosts with dynamic reserved ranges.Additional context
Host port allocation range is 40000–60000 (
allocate_host_portdefaults); OS-reserved ranges on Windows change between reboots, which is why the failure is intermittent and environment-dependent.