Skip to content

Chrome CDP unreachable from host even with --remote-debugging-address=0.0.0.0 + --remote-allow-origins=* #10

Description

@todie

Summary

Chrome 100+ refuses CDP HTTP requests where the SOURCE IP is not loopback, even when launched with `--remote-debugging-address=0.0.0.0` AND `--remote-allow-origins=*`. This breaks the obvious approach of "just publish 9222 to the host and curl it."

Repro:

```bash
reach create --name probe --extra-port 9222
docker exec -d -u sandbox -e DISPLAY=:99 probe google-chrome \
--no-sandbox --disable-dev-shm-usage \
--remote-debugging-address=0.0.0.0 \
--remote-debugging-port=9222 \
--remote-allow-origins=* \
--user-data-dir=/tmp/chrome-profile about:blank

From inside the container — works:

docker exec probe curl -s http://127.0.0.1:9222/json/version

{"Browser": "Chrome/146.0.7680.177", ...}

From the host — fails:

curl -sv http://localhost:9222/json/version

Connected to localhost (127.0.0.1) port 9222

> GET /json/version HTTP/1.1

> Host: localhost:9222

* Recv failure: Connection reset by peer

```

The TCP connection succeeds (the docker port mapping works) but Chrome closes the HTTP request mid-flight because the source IP is the docker bridge gateway (172.17.0.1 in my case), not 127.0.0.1.

Workaround in use

Run a localhost forwarder inside the container:

  1. Launch Chrome bound to loopback only: `--remote-debugging-address=127.0.0.1 --remote-debugging-port=9224`
  2. Run socat as a 0.0.0.0:9222 → 127.0.0.1:9224 forwarder so the docker-published port reaches Chrome through a loopback hop:
    ```bash
    docker exec -d socat TCP-LISTEN:9222,bind=0.0.0.0,reuseaddr,fork TCP:127.0.0.1:9224
    ```

This works. The host can now `curl http://localhost:9222/json/version\` and get a real CDP response. But it requires:

Suggested fixes

  1. Bake socat into the image (separate from net-tools, since this one is load-bearing for any CDP-from-host workflow).
  2. Add a reach create --cdp flag (or env var) that, when set, automatically launches Chrome with the loopback bind + spins up the socat forwarder + publishes 9222 to the host. The caller gets a working `http://localhost:9222\` for free.
  3. Document the loopback bridge pattern in `docs/cdp-access.md` so the next person doesn't burn an hour rediscovering it.

I'd push for (2). The reach pitch is "AI-drivable containerized desktop sandbox." A working CDP endpoint is the single most useful host-facing primitive after VNC.

Discovered while

Wiring todie/revenant's todie-daemon to drive Chrome inside reach via CDP, for posting Threads.com chains. Same workflow PR #4 was scoped for; the auth handoff piece works perfectly, the CDP access piece needed this dance.

The full working invocation is captured in todie/revenant start-daemon.sh for reference.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingstaleNo activity for 14+ days

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions