WSL の playwright-cli からホスト Windows の Chrome にアタッチする
TL;DR — WSL2 ミラーモードなら
--cdp=chromeチャンネル名は使えないが、Chrome を--remote-debugging-port=9222で起動して--cdp=http://localhost:9222を使えばアタッチできる。Firewall ルールも不要。なお、--remote-debugging-addressは非 headless Chrome では無視され、Chrome は常に127.0.0.1にバインドする。localhostで繋がるのはミラーモードが127.0.0.1を通してくれるおかげ。
どっかで聞いたところによると…
playwright-cli(@playwright/cli)には、起動済みの Chrome にアタッチしてそのセッションをそのまま操作できる機能があり、SAML/SSO 認証済みのページを操作したいときにサンドボックスの Chrome にログインし直す手間が省ける、とのことです。
確かに便利そうなんだけど、この機能を WSL2 から使おうとしてハマったので記録しておきます。
ほんと大体ハマってんな俺。
やりたいこと
WSL 上の playwright-cli から、ホスト Windows で開いている Chrome(ログイン済み)にアタッチして操作する。
前提
- WSL2 ネットワークモード:ミラーモード(
networkingMode=mirrored) - playwright-cli:
0.1.9(mise use --global npm:@playwright/cli@latestでインストール)- 前回自宅でハマったので職場では間違えなかった
チャンネル名(--cdp=chrome)は WSL から使えない
そもそもこれが駄目だった。
以下は Claude さんの解説です。
playwright-cli には microsoft/playwright#40177(2026年4月マージ)で、チャンネル名でアタッチできる機能が追加された。
playwright-cli attach --cdp=chrome
これは DevToolsActivePort ファイルを読んでポートを自動解決する仕組みなのだが、WSL では動かない。
原因は process.platform。WSL 上では linux になるため、スクリプトは ~/.config/google-chrome/DevToolsActivePort(Linux のパス)を探しに行く。ホスト Windows の Chrome が書き込むのは %LOCALAPPDATA%\Google\Chrome\User Data\DevToolsActivePort なので、当然見つからない。
WSL からは URL 直指定(--cdp=http://localhost:9222)を使う。
Chrome をリモートデバッグモードで起動する
わざわざ、Windows ホスト側でスクリプト起動するのもどうかと思ったので、自分で調べたり、Claude さんに色々調査してもらったところ、WSL 側から、Windows の実行ファイルを指定して実行する方法を提案してもらった。
#!/bin/bash
# ~/scripts/run-host-chrome.sh
# 既に 9222 が開いていれば何もしない(冪等)
if curl -s --max-time 2 http://localhost:9222/json/version > /dev/null 2>&1; then
echo "[chrome-debug] already running"
exit 0
fi
CHROME_PATH="/mnt/c/Program Files/Google/Chrome/Application/chrome.exe"
CHROME_ARGS=(
--remote-debugging-port=9222
--no-first-run
--no-default-browser-check
--disable-gpu
--user-data-dir="C:\\chrome-cdp-profile"
)
"${CHROME_PATH}" "${CHROME_ARGS[@]}" > /dev/null 2>&1 &
# 起動待機(最大10秒)
WAIT=0
until curl -s --max-time 2 http://localhost:9222/json/version > /dev/null 2>&1; do
if [[ ${WAIT} -ge 10 ]]; then
echo "[chrome-debug] ERROR: Chrome did not start within 10 seconds." >&2
exit 1
fi
sleep 1
WAIT=$((WAIT + 1))
done
echo "[chrome-debug] started"
sleep 3 で固定待機するのではなく、curl でポーリングして最大10秒待つようにしたとのこと。えらい。
WSL から接続確認
ミラーモードなら localhost がそのままホスト側に転送されるので、Firewall ルールは不要。やっぱりミラーモード最強なんじゃないか?
curl http://localhost:9222/json/version
# Chrome のバージョン情報が JSON で返れば OK
アタッチ
playwright-cli attach --cdp=http://localhost:9222
playwright-cli snapshot
スナップショットが返れば接続成功。既存タブの状態がそのまま操作できる。
ハマりどころまとめ
chrome://inspect/#remote-debugging のトグルだけでは不十分
chrome://inspect で「Allow remote debugging」を有効にする方法もあるが、既存の Chrome プロセスが起動中の場合は反映されないことがあるので、確実なのはプロセスを終了してフラグ付きで起動し直すのがよいそうです。
要するに、普段使ってるプロファイルで起動してる Chrome を終了させてプロセスが残っていないことを確認してから、前述のスクリプトを起動した方がいいです。
ss -tnal で 9222 が見えない
ss は Linux カーネルのソケット情報を見るコマンドなので、Windows 側のポートは一切見えない。Windows 側の状態確認は PowerShell の netstat を使う。
言われてみればそりゃそうだわ、と納得。
--remote-debugging-address は無視される
Chrome は非 headless モードでは --remote-debugging-address を無視し、常に 127.0.0.1:9222 にバインドする。netstat で 127.0.0.1:9222 が見えていれば正常。
WSL2 ミラーモードでは localhost が Windows の 127.0.0.1 に届くため、そのまま curl http://localhost:9222 で疎通できる。--remote-debugging-address をあれこれ設定する必要はない。
一回 0.0.0.0 に設定してから「なんか動いてる」と思っていたが、試しに違う IP アドレスを指定してもつながるので「なんかおかしい」と思って Claude さんに調べてもらったら、フラグが無視されていたことが発覚した。
まとめ
| 確認項目 | コマンド |
|---|---|
| Chrome が 9222 を開いているか | PowerShell: netstat -ano | findstr :9222 |
| WSL から疎通確認 | curl http://localhost:9222/json/version |
| アタッチ | playwright-cli attach --cdp=http://localhost:9222 |
URL 直指定で動くので問題なし。
既存セッションを再利用できるのは便利なので、テスト自動化などで活用していければいいなと思いました。