Files
adolf/docs/tools/browser-wsl2-windows-remote-cdp-troubleshooting.md
alvis bedb527145
Some checks failed
ClawSweeper Dispatch / dispatch (push) Has been cancelled
CodeQL / Security High (actions) (push) Has been cancelled
CodeQL / Security High (channel-runtime-boundary) (push) Has been cancelled
CodeQL / Security High (core-auth-secrets) (push) Has been cancelled
CodeQL / Security High (mcp-process-tool-boundary) (push) Has been cancelled
CodeQL / Security High (network-ssrf-boundary) (push) Has been cancelled
CodeQL / Security High (plugin-trust-boundary) (push) Has been cancelled
CodeQL / Security High (process-exec-boundary) (push) Has been cancelled
Docs Sync Publish Repo / sync-publish-repo (push) Has been cancelled
Docs / docs (push) Has been cancelled
OpenClaw Stable Main Closeout / Resolve stable release closeout inputs (push) Has been cancelled
OpenClaw Stable Main Closeout / Verify stable main closeout (push) Has been cancelled
Workflow Sanity / no-tabs (push) Has been cancelled
Workflow Sanity / actionlint (push) Has been cancelled
Workflow Sanity / generated-doc-baselines (push) Has been cancelled
CI / runner-admission (push) Has been cancelled
CI / preflight (push) Has been cancelled
CI / security-fast (push) Has been cancelled
CI / pnpm-store-warmup (push) Has been cancelled
CI / build-artifacts (push) Has been cancelled
CI / native-i18n (push) Has been cancelled
CI / ${{ matrix.check_name }} (push) Has been cancelled
CI / ${{ matrix.checkName }} (push) Has been cancelled
CI / checks-node-compat-node22 (push) Has been cancelled
CI / check-bundled-channel-config-metadata (push) Has been cancelled
CI / check-dependencies (push) Has been cancelled
CI / check-guards (push) Has been cancelled
CI / check-lint (push) Has been cancelled
CI / check-prod-types (push) Has been cancelled
CI / check-shrinkwrap (push) Has been cancelled
CI / check-test-types (push) Has been cancelled
CI / check-additional-boundaries-a (push) Has been cancelled
CI / check-additional-boundaries-bcd (push) Has been cancelled
CI / check-additional-extension-bundled (push) Has been cancelled
CI / check-additional-extension-channels (push) Has been cancelled
CI / check-additional-extension-package-boundary (push) Has been cancelled
CI / check-additional-runtime-topology-architecture (push) Has been cancelled
CI / check-session-accessor-boundary (push) Has been cancelled
CI / check-session-transcript-reader-boundary (push) Has been cancelled
CI / check-docs (push) Has been cancelled
CI / skills-python (push) Has been cancelled
CI / macos-swift (push) Has been cancelled
CI / ios-build (push) Has been cancelled
CI / ci-timings-summary (push) Has been cancelled
Native App Locale Refresh / Refresh native fa (push) Has been cancelled
Native App Locale Refresh / Refresh native fr (push) Has been cancelled
Native App Locale Refresh / Refresh native hi (push) Has been cancelled
Native App Locale Refresh / Refresh native id (push) Has been cancelled
Native App Locale Refresh / Refresh native it (push) Has been cancelled
Native App Locale Refresh / Refresh native ja-JP (push) Has been cancelled
Control UI Locale Refresh / plan (push) Has been cancelled
Control UI Locale Refresh / Refresh ${{ matrix.locale }} (push) Has been cancelled
Control UI Locale Refresh / Commit control UI locale refresh (push) Has been cancelled
Live Media Runner Image / Build live media runner image (push) Has been cancelled
Native App Locale Refresh / Refresh native ar (push) Has been cancelled
Native App Locale Refresh / Refresh native de (push) Has been cancelled
Native App Locale Refresh / Refresh native es (push) Has been cancelled
Native App Locale Refresh / Refresh native ko (push) Has been cancelled
Native App Locale Refresh / Refresh native nl (push) Has been cancelled
Native App Locale Refresh / Refresh native pl (push) Has been cancelled
Native App Locale Refresh / Refresh native pt-BR (push) Has been cancelled
Native App Locale Refresh / Refresh native ru (push) Has been cancelled
Native App Locale Refresh / Refresh native sv (push) Has been cancelled
Native App Locale Refresh / Refresh native th (push) Has been cancelled
Native App Locale Refresh / Refresh native tr (push) Has been cancelled
Native App Locale Refresh / Refresh native uk (push) Has been cancelled
Native App Locale Refresh / Refresh native vi (push) Has been cancelled
Native App Locale Refresh / Refresh native zh-CN (push) Has been cancelled
Native App Locale Refresh / Refresh native zh-TW (push) Has been cancelled
Native App Locale Refresh / Commit native locale refresh (push) Has been cancelled
Plugin Init Scaffold Validation / Validate provider scaffold (push) Has been cancelled
Plugin NPM Release / preview_plugins_npm (push) Has been cancelled
Plugin NPM Release / Validate release publish approval (push) Has been cancelled
Plugin NPM Release / preview_plugin_pack (push) Has been cancelled
Plugin NPM Release / publish_plugins_npm (push) Has been cancelled
Sandbox Common Smoke / sandbox-common-smoke (push) Has been cancelled
Website Installer Sync / static (push) Has been cancelled
Website Installer Sync / linux-docker (push) Has been cancelled
Website Installer Sync / macos-installer (push) Has been cancelled
Website Installer Sync / windows-installer (push) Has been cancelled
Website Installer Sync / sync-website (push) Has been cancelled
Vendor OpenClaw source as Adolf fork baseline
Adolf is a fork/vendored clone of github.com/openclaw/openclaw (v2026.6.11),
free to diverge. Tree copied sans upstream .git; upstream remote added for
future syncs. Node pinned to 24 (.nvmrc); engines already require >=22.19.
Preserves docs/ARCHITECTURE.md.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LeqyaxJF2nbRXJtae2kNB2
2026-07-05 09:36:54 +00:00

184 lines
8.1 KiB
Markdown

---
summary: "Troubleshoot WSL2 Gateway + Windows Chrome remote CDP in layers"
read_when:
- Running OpenClaw Gateway in WSL2 while Chrome lives on Windows
- Seeing overlapping browser/control-ui errors across WSL2 and Windows
- Deciding between host-local Chrome MCP and raw remote CDP in split-host setups
title: "WSL2 + Windows + remote Chrome CDP troubleshooting"
---
In the common split-host setup, OpenClaw Gateway runs inside WSL2, Chrome runs
on Windows, and browser control must cross the WSL2/Windows boundary. Several
independent problems can surface at once (see
[issue #39369](https://github.com/openclaw/openclaw/issues/39369)): CDP
transport, Control UI origin security, and token/pairing can each fail on
their own while producing similar-looking errors. Work through the layers
below in order instead of guessing which one is broken.
## Choose the right browser mode first
### Option 1: raw remote CDP from WSL2 to Windows
Use a remote browser profile pointing from WSL2 to a Windows Chrome CDP
endpoint. Choose this when the Gateway stays inside WSL2, Chrome runs on
Windows, and browser control needs to cross the WSL2/Windows boundary.
### Option 2: host-local Chrome MCP
Use the `existing-session` driver (`user` profile) only when the Gateway runs
on the same host as Chrome, you want the local signed-in browser state, you do
not need cross-host browser transport, and you do not need `responsebody`,
PDF export, download interception, or batch actions (Chrome MCP profiles do
not support these).
For WSL2 Gateway + Windows Chrome, use raw remote CDP. Chrome MCP is
host-local, not a WSL2-to-Windows bridge.
## Working architecture
- WSL2 runs the Gateway on `127.0.0.1:18789`
- Windows opens the Control UI in a normal browser at `http://127.0.0.1:18789/`
- Windows Chrome exposes a CDP endpoint on port `9222`
- WSL2 can reach that Windows CDP endpoint
- OpenClaw points a browser profile at the address reachable from WSL2
## Critical rule for the Control UI
When the UI is opened from Windows, use Windows localhost unless you have a
deliberate HTTPS setup:
```text
http://127.0.0.1:18789/
```
Do not default to a LAN IP. Plain HTTP on a LAN or tailnet address can
trigger insecure-origin/device-auth behavior unrelated to CDP itself. See
[Control UI](/web/control-ui).
## Validate in layers
Work top to bottom; do not skip ahead. Fixing one layer can still leave a
different error visible from a layer further down.
### Layer 1: verify Chrome is serving CDP on Windows
```powershell
chrome.exe --remote-debugging-port=9222
```
From Windows, verify Chrome itself first:
```powershell
curl http://127.0.0.1:9222/json/version
curl http://127.0.0.1:9222/json/list
```
If this fails on Windows, OpenClaw is not the problem yet.
### Layer 2: verify WSL2 can reach that Windows endpoint
From WSL2, test the exact address you plan to use in `cdpUrl`:
```bash
curl http://WINDOWS_HOST_OR_IP:9222/json/version
curl http://WINDOWS_HOST_OR_IP:9222/json/list
```
Good result:
- `/json/version` returns JSON with Browser / Protocol-Version metadata
- `/json/list` returns JSON (an empty array is fine if no pages are open)
If this fails, Windows is not exposing the port to WSL2 yet, the address is
wrong for the WSL2 side, or firewall/port-forwarding/proxying is missing. Fix
that before touching OpenClaw config.
### Layer 3: configure the correct browser profile
Point OpenClaw at the address reachable from WSL2:
```json5
{
browser: {
enabled: true,
defaultProfile: "remote",
profiles: {
remote: {
cdpUrl: "http://WINDOWS_HOST_OR_IP:9222",
attachOnly: true,
color: "#00AA00",
},
},
},
}
```
Notes:
- use the WSL2-reachable address, not whatever only works on Windows
- keep `attachOnly: true` for externally managed browsers
- `cdpUrl` can be `http://`, `https://`, `ws://`, or `wss://`
- use HTTP(S) when you want OpenClaw to discover `/json/version`
- use WS(S) only when the browser provider gives you a direct DevTools
socket URL
- test the same URL with `curl` before expecting OpenClaw to succeed
### Layer 4: verify the Control UI layer separately
Open `http://127.0.0.1:18789/` from Windows, then verify:
- the page origin matches what `gateway.controlUi.allowedOrigins` expects
- token auth or pairing is configured correctly
- you are not debugging a Control UI auth problem as if it were a browser
problem
Helpful page: [Control UI](/web/control-ui).
### Layer 5: verify end-to-end browser control
From WSL2:
```bash
openclaw browser --browser-profile remote open https://example.com
openclaw browser --browser-profile remote tabs
```
Good result:
- the tab opens in Windows Chrome
- `browser tabs` returns the target
- later actions (`snapshot`, `screenshot`, `navigate`) work from the same
profile
## Common misleading errors
| Message | Meaning |
| --------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `control-ui-insecure-auth` | UI origin/secure-context problem, not a CDP transport problem |
| `token_missing` | auth configuration problem |
| `pairing required` | device approval problem |
| `Remote CDP for profile "remote" is not reachable` | WSL2 cannot reach the configured `cdpUrl` |
| `Browser attachOnly is enabled and CDP websocket for profile "remote" is not reachable` | the HTTP endpoint answered, but the DevTools WebSocket could not be opened |
| stale viewport / dark-mode / locale / offline overrides after a remote session | run `openclaw browser --browser-profile remote stop` to close the session and release the cached Playwright/CDP connection without restarting the Gateway or the external browser |
| timeout around `remoteCdpTimeoutMs` (default 1500ms) | usually still CDP reachability, or a slow/unreachable remote endpoint |
| `No Chrome tabs found for profile="user"` | local Chrome MCP profile selected where no host-local tabs are available |
## Fast triage checklist
1. Windows: does `curl http://127.0.0.1:9222/json/version` work?
2. WSL2: does `curl http://WINDOWS_HOST_OR_IP:9222/json/version` work?
3. OpenClaw config: does `browser.profiles.<name>.cdpUrl` use that exact
WSL2-reachable address?
4. Control UI: are you opening `http://127.0.0.1:18789/` instead of a LAN IP?
5. Are you trying to use `existing-session` across WSL2 and Windows instead
of raw remote CDP?
Verify the Windows Chrome endpoint locally first, verify the same endpoint
from WSL2 second, and only then debug OpenClaw config or Control UI auth.
## Related
- [Browser](/tools/browser)
- [Browser login](/tools/browser-login)
- [Browser Linux troubleshooting](/tools/browser-linux-troubleshooting)