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.9mise 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 にバインドする。netstat127.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 直指定で動くので問題なし。

既存セッションを再利用できるのは便利なので、テスト自動化などで活用していければいいなと思いました。