開発と AI · Clash 技術ブログ

Docker と WSL2 で Clash プロキシを使用する方法:イメージ取得のタイムアウトとネットワーク設定

docker pull、WSL2 の取得、コンテナ内の要求は異なるプロセスが行います。エラーの場所に応じてホストアドレスとプロキシ設定を確認し、ビルドやコンテナに個別の変数を渡して、NO_PROXY でデータベースと内部サービスの直接接続を維持します。

  • Docker
  • WSL2
  • 開発環境
目次

開発環境では、パソコンで使えるプロキシアドレスをすべてのターミナルやコンテナにコピーすると、設定を間違えやすくなります。確認すべきなのは、エラーを出したプロセスと、そのプロセスからプロキシを動かしているホストへ接続できるかです。接続テストが通ってから永続設定を保存し、データベースなどの内部サービスには直接接続できるようにしましょう。

docker pull、WSL のダウンロード、コンテナ要求のプロキシ設定

エラーになった要求を送ったプログラム

失敗した操作リクエストを送るプログラム
WSL 内の curl / apt / git がタイムアウトするWSL ディストリビューション内のプロセス
docker pull がタイムアウトするDocker Desktop または Docker Engine のデーモン
ビルド中に RUN apt-get がタイムアウトするBuildKit / ビルドコンテナ
起動後にアプリのリクエストが失敗する実行中のコンテナ

Windows 上の Clash が 127.0.0.1 で待ち受けていても、アクセスできると保証されるのはその Windows 端末だけです。WSL2 は標準では NAT の仮想ネットワークで動き、コンテナーにも独立したネットワーク環境があります。それらが 127.0.0.1 にアクセスすると、通常はホストではなく自分自身に接続します。

Windows、WSL2、コンテナ間のプロキシ経路
  1. Windows 上の ClashLAN から到達可能な mixed-port でリッスンする
  2. WSL2ホストのアドレスを使ってそのポートへアクセスする
  3. Docker ビルドHTTP_PROXY と HTTPS_PROXY を明示的に受け取る
  4. コンテナ内のツール続いて Git、npm、またはパッケージマネージャーを設定する

Windows、WSL2、各コンテナから 127.0.0.1 に接続すると、通常はそれぞれ自身のネットワーク環境に接続します。プロキシのアドレスには、利用する環境から到達できるホストのアドレスを指定してください。

WSL から Windows のプロキシポートに接続する

まず Clash で実際の HTTP または mixed-port を確認します。一般的な例は 7890 ですが、クライアントによって異なる場合があります。WSL からホスト IP を使ってアクセスすると LAN 接続として扱われるため、クライアントで LAN アクセスを許可し、WSL から到達可能なアドレスをリッスンする必要があります。

LAN アクセスを許可すると、ポートへ到達できる範囲が広がります。信頼できる自宅または職場のプライベートネットワークだけで使い、Windows ファイアウォールで接続元を制限してください。認証のないプロキシを公共 Wi-Fi やインターネットへ公開しないでください。テスト後に不要であれば、LAN アクセスを無効にできます。

既定の NAT とミラーモードのホストアドレス

既定の NAT モードでは、WSL からデフォルトルートのネクストホップを確認できます。通常、これが WSL 仮想ネットワーク内にある Windows ホストのアドレスです。Windows 11 22H2 以降で mirrored networking を有効にすると、WSL から 127.0.0.1 経由で Windows サービスへ直接アクセスできます。

WSL 既定 NAT のテスト。7890 は置き換える Clash ポート
HOST_IP=$(ip route show | grep -i default | awk '{ print $3 }')
CLASH_PORT=7890
echo "Windows host: $HOST_IP"
curl -I -x "http://${HOST_IP}:${CLASH_PORT}" https://example.com

この curl が HTTP 応答を受け取ってから、WSL の環境変数を設定する意味があります。プロキシポートがすぐ Connection refused を返す場合は、Clash のリッスン設定、LAN アクセス許可、ファイアウォールに問題があります。ポートへ到達できても外部リクエストが timeout になる場合は、ノードとルールを確認してください。

WSL shell に HTTP_PROXY と HTTPS_PROXY を設定する

現在の WSL shell で一時的に有効。7890 はポートのプレースホルダー
HOST_IP=$(ip route show | grep -i default | awk '{ print $3 }')
CLASH_PORT=7890
export HTTP_PROXY="http://${HOST_IP}:${CLASH_PORT}"
export HTTPS_PROXY="http://${HOST_IP}:${CLASH_PORT}"
export NO_PROXY="localhost,127.0.0.1,::1"
curl -I https://example.com

一時的な変数は、現在のターミナルから起動したプログラムが参照します。git または curl で同じ HTTPS リクエストを試し、成功した設定を使っている shell の起動ファイルに追加します。curl で HTTP URL にアクセスする場合は小文字の http_proxy が必要で、HTTP_PROXY だけでは機能しません。

apt の HTTP 通信は、小文字の http_proxy、no_proxy、または独自の Acquire::http::Proxy 設定を参照します。sudo で起動する場合は環境が引き継がれるかも確認してください。上の変数設定をすべてのツールで使えるものと考えないでください。

対応する Windows バージョンの WSL では、.wslconfig に autoProxy=true を設定し、Windows の HTTP プロキシ情報を WSL へ取り込むこともできます。有効化後は WSL を再起動し、実際の変数値を確認してください。

NO_PROXY には WSL 内部だけで提供されるサービスを含め、localhost へのアクセスが Windows プロキシを遠回りしないようにしてください。社内ドメインやプライベートアドレス範囲を加えるかは、実際のネットワークに合わせて決めます。

Docker Desktop と独立した Engine のプロキシ設定場所

Docker Desktop のイメージ取得と WSL shell のダウンロードは異なるプロセスが行います。WSL で export HTTP_PROXY を実行するだけでは、Desktop のイメージ取得は自動設定されません。

Docker Desktop の Settings を開き、Resources / Proxies(名称はバージョンで変わる場合があります)にホストから使える HTTP、HTTPS プロキシを入力して適用します。

画面に Docker Desktop proxy と Containers proxy が分かれている場合、イメージの取得では Containers proxy を確認します。Docker Desktop proxy は Containers proxy が未設定のときだけ代わりに使われます。変更後は docker pull で確認してください。

Docker の公式ドキュメントには、Desktop が daemon.json のデーモンプロキシ設定を参照しないことが明記されています。WSL ターミナルからアクセスできるようになっても、Docker Desktop 自身のプロキシ設定を省略しないでください。

Docker Desktop ではなく独立した Linux Docker Engine を使用している場合に限り、Engine のドキュメントに従い daemon.json または systemd 環境でデーモンプロキシを設定し、Docker サービスを再起動します。まず実行形態を確認し、まったく参照されないファイルを変更しないようにしてください。

イメージのビルドと実行中コンテナに別々のプロキシ設定を渡す

Docker のクライアント設定では、新しいコンテナとビルドへプロキシ環境を自動注入することも、単発コマンドで明示的に渡すこともできます。ビルド時は --build-arg、実行時は --env を使います。認証情報を含むプロキシアドレスを Dockerfile の ENV で固定しないでください。イメージ履歴や設定に残る可能性があります。

この例は Dockerfile があるプロジェクトのディレクトリで実行します。demo-app は今回ビルドするイメージ名で、必要に応じて自分のプロジェクトに合わせます。単独の接続テストではないため、プロキシポートに届くかは前述の curl で先に確認してください。

Docker Desktop の既存プロジェクト用の例。7890 は実際の Clash ポートに置き換える
CLASH_PROXY=http://host.docker.internal:7890

docker build \
  --build-arg HTTP_PROXY="$CLASH_PROXY" \
  --build-arg HTTPS_PROXY="$CLASH_PROXY" \
  -t demo-app .

docker run --rm \
  --env HTTP_PROXY="$CLASH_PROXY" \
  --env HTTPS_PROXY="$CLASH_PROXY" \
  --env NO_PROXY="localhost,127.0.0.1" \
  demo-app

Docker Desktop は通常、ホストへ到達するための host.docker.internal を提供します。ネイティブ Linux Engine で利用できるかは環境によって異なり、明示的なホストゲートウェイまたは追加の host-gateway 設定が必要な場合があります。コマンド実行前に、コンテナ内の curl またはアプリログから、このホスト名とポートへ実際に到達できることを確認してください。

NO_PROXY:データベースと内部サービスを直接接続に保つ

データベース名、Compose のサービス名、localhost、内部ネットワークは通常、外部プロキシに送るべきではありません。実際の内部ドメインを NO_PROXY に加え、db:5432 や redis:6379 へのアクセスが先に Windows のプロキシへ送られないようにします。ワイルドカードと CIDR の対応はツールごとに異なるため、設定後は対象プロセスで変数を表示し、実際にリクエストを送ってください。

プロキシアドレスにユーザー名またはパスワードが含まれる場合は、公開される compose.yaml、Dockerfile、イメージへ書き込まないでください。ローカル環境ファイルまたはプロジェクトの secret 管理方法を使い、ログに完全な URL が出力されないことを確認します。

実際の用途に合わせて四つの検証を完了する

  • WSL 内の curl が Windows Clash 経由で応答を受け取る
  • docker pull で小さなイメージを取得できる
  • docker build のネットワーク手順がタイムアウトしない
  • 実行中コンテナから外部へアクセスでき、内部サービスへは直接接続できる

参考資料