fix(server): docker-runtime proxy handler hardcodes resolve_internal=True — server-proxy hangs when lifecycle server runs in a container with bridge sandboxes
name: Bug Report about: proxy handler ignores [proxy].resolve_internal and [docker].host_ip — server-proxy data plane hangs in containerized-server + bridge-sandbox topology title: "fix(server): docker-runtime proxy handler hardcodes resolve_internal=True — server-proxy hangs when lifecycle server runs in a container with bridge sandboxes" labels: '' assignees: ''
Why do you need it?
In release server/v0.2.3, the docker-runtime HTTP proxy handler hardcodes resolve_internal=True, so the forwarding target is always resolved to the sandbox's bridge container IP:
# server/opensandbox_server/api/proxy.py (v0.2.3)
async def _proxy_http_request(...):
endpoint = lifecycle.sandbox_service.get_endpoint(sandbox_id, port, resolve_internal=True)This breaks the exact topology that the repository's own server/docker-compose.example.yaml describes and claims to support:
- The lifecycle server runs in a container attached to a compose network (e.g.
192.168.48.x) - Sandboxes are created through the mounted docker.sock on Docker's default bridge (
172.17.0.x) - The example config sets
[proxy] resolve_internal = falseand[docker] host_ip = "host.docker.internal"(withextra_hosts: host-gateway) precisely so the proxy forwards via the host-mapped port instead of the unreachable sandbox IP
With resolve_internal=True hardcoded, the proxy forwards to 172.17.0.x:44772, which is unreachable from the server's compose network. The forwarding request hangs until the client times out. Since the Python SDK's connect() ready-check pings through this exact proxy route, every sandbox creation fails with SandboxReadyTimeoutException: Sandbox health check timed out after 30.0s (1 attempts) — the very first ping consumes the whole window.
Observed in our deployment (recent v0.2.3 image, both server and sandboxes on the same host):
| Probe | Result |
|---|---|
host → sandbox mapped port /ping (host.docker.internal:<mapped> and localhost:<mapped>) |
200 |
server container → host.docker.internal:<mapped> (httpx, same lib as proxy) |
200 |
client → server /v1/sandboxes/{id}/proxy/44772/ping |
hangs until client timeout |
Note that [proxy].resolve_internal = false and [docker].host_ip are already read by docker/networking.py::get_endpoint() when called with use_proxy_host=True — the config keys exist and are documented for this scenario; only the proxy handler never passes them.
How could it be?
Read the config in the proxy handler instead of hardcoding, i.e. what commit 93f7d2bc ("feat(server): make proxy resolve_internal configurable") already does on main:
resolve_internal = get_config().proxy.resolve_internal
endpoint = lifecycle.sandbox_service.get_endpoint(
sandbox_id,
port,
resolve_internal=resolve_internal,
use_proxy_host=not resolve_internal,
)However, 93f7d2bc has not been included in any release (the latest, server/v0.2.3, was tagged 2026-08-26 and diverged before the fix). Request: cut a patch release containing 93f7d2bc so containerized-server deployments can use the server-proxy data plane again.
Other related information
- Fix commit on main:
93f7d2bc— verified that it replaces the hardcodedresolve_internal=Truewithget_config().proxy.resolve_internal(plususe_proxy_host=not resolve_internal) server/docker-compose.example.yamlsets[proxy] resolve_internal = falsewith the comment "Route through host-published ports instead of unreachable sandbox IPs" — on v0.2.3 this setting has no effect on the forwarding path- Docs reference:
docs/architecture/single-host-network.mddescribes the host-mapped routing model that depends on this fix - Workaround: run the caller on the same host as the sandboxes and use direct (
use_server_proxy=False) +host.docker.internalresolution — works, but loses the single-host port-multiplexing benefit and requires the caller to resolvehost_ip
Source: opensandbox-group/OpenSandbox