開発と AI · Clash 技術ブログ

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

Windows、WSL2、Docker エンジン、コンテナーには、それぞれ独自のネットワーク環境があります。そのため、ブラウザを利用できても docker pull がプロキシを使うとは限りません。リクエストを開始する場所に応じて、層ごとに設定してください。

  • Docker
  • WSL2
  • 開発環境
目次

docker pull、WSL コマンド、コンテナのリクエストはそれぞれ別の場所から発生する

Windows 上の Clash を Docker と WSL2 から使うには、単一のターミナルにプロキシを書くだけでは不十分です。docker pull、WSL 内の apt、イメージビルド中の RUN、起動後のコンテナは、それぞれ異なるコンポーネントからリクエストを送ります。エラーが出た階層に設定してください。

Windows 上で 127.0.0.1 をリッスンする Clash は、Windows 本体からのアクセスだけを保証します。WSL2 は既定で NAT 仮想ネットワーク内で動作し、コンテナには独自のネットワーク名前空間があります。そこから見える 127.0.0.1 は通常、ホストではなく自分自身です。

Docker のイメージ取得、docker build 中のダウンロード、実行中コンテナからの外部アクセスも、それぞれ異なるコンポーネントが行います。WSL shell だけで HTTP_PROXY を export しても、Docker Desktop のイメージ取得がプロキシを経由するとは限りません。

エラーが発生する階層

失敗した操作実際にリクエストを送るコンポーネント
WSL 内の curl / apt / git がタイムアウトするWSL ディストリビューション内のプロセス
docker pull がタイムアウトするDocker Desktop または Docker Engine のデーモン
ビルド中に RUN apt-get がタイムアウトするBuildKit / ビルドコンテナ
起動後にアプリのリクエストが失敗する実行中のコンテナ
Windows、WSL2、コンテナ間のプロキシ経路
  1. Windows 上の ClashLAN から到達可能な mixed-port でリッスンする
  2. WSL2ホストのアドレスを使ってそのポートへアクセスする
  3. Docker ビルドHTTP_PROXY と HTTPS_PROXY を明示的に受け取る
  4. コンテナ内のツール続いて Git、npm、またはパッケージマネージャーを設定する

127.0.0.1 は各階層でそれぞれ自身を指します。プロキシアドレスには、直前の階層から実際に到達できるホストアドレスを指定する必要があります。

ホストのプロキシポートは仮想ネットワークから到達できる必要がある

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

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

既定の WSL NAT ではホスト IP を使い、ミラーネットワークでは 127.0.0.1 を直接試せる

既定の 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 コマンドラインに環境変数を設定する

現在の 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

一時変数はターミナルを閉じると消えるため、トラブルシューティングに適しています。apt、git、curl で同じリクエストをやり直し、成功を確認してから、shell の種類に応じて自分の起動ファイルへ追加してください。

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

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

docker pull が失敗する場合は Docker Desktop のプロキシ設定を使う

Docker Desktop のイメージ取得と WSL shell のコマンドは、別のプロセスから実行されます。Docker Desktop の Settings を開き、Resources / Proxies にホストで利用できる HTTP、HTTPS プロキシを入力して設定を適用してください。バージョンによってラベルが多少異なる場合があります。

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

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

WSL の curl は成功するが、docker pull は timeout のまま

Docker Desktop の Proxies 設定と、再起動後の状態を確認してください。

Docker Desktop で daemon.json を変更しても効果がない

Desktop の画面設定へ移してください。この製品は daemon proxy 設定を参照しません。

ネイティブ Linux Engine でイメージ取得に失敗する

Windows のシステムプロキシではなく、daemon のプロキシ環境とサービスログを確認してください。

イメージを取得できても、ビルド手順や実行中コンテナにはプロキシが設定されていない場合がある

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

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 のネットワーク手順がタイムアウトしない
  • 実行中コンテナから外部へアクセスでき、内部サービスへは直接接続できる

四つの結果は、WSL、Docker エンジン、ビルド処理、実行中コンテナにそれぞれ対応します。まだ失敗する項目があれば、その階層の設定へ戻ってください。すでに通過したほかの三つの階層を変更し直す必要はありません。

参考資料