なぜコンテナだけホストの Clash を通れないのか

Docker Desktop on macOS は、Linux カーネルとコンテナ実行環境を軽量 VM 側で抱える構成です。コンテナのプロセスから見た 127.0.0.1 は「そのコンテナ自身」であり、メニューバーで動いている Clash が待ち受けている「Mac 本体のループバック」とは一致しません。そのため、ドキュメントに載っている http://127.0.0.1:7890 のような例をそのまま写しても、コンテナ内では接続拒否やタイムアウトになりやすいです。

また、macOS の「システムプロキシ」や Clash クライアントの「システム代理を設定」は、アプリやシェルには効いても、Docker デーモンが起動するコンテナのデフォルト環境には自動では入りません。外向き HTTP をプロキシに流したい場合は、コンテナ側に明示的に環境変数を渡すか、Docker Desktop の手動プロキシ設定(後述)を使う必要があります。

Windows と WSL2 で同種の話を追う場合は、WSL2 からホスト Clash を使う手順が対比になります。macOS ではホスト到達用の名前として host.docker.internal が定番です。

host.docker.internal とは何か

host.docker.internal は、Docker がコンテナからホスト OS に名前解決できるよう提供する特別なホスト名です(環境により無効化されているケースはありますが、Docker Desktop on macOS では標準的に利用できます)。コンテナ内でこの名前を解決すると、ホスト側のインターフェースに相当するアドレスへ向かいます。

実務上は「プロキシ URL のホスト部分を host.docker.internal に置き換える」だけで、http://host.docker.internal:7890 のように Clash の HTTP ポートへ届けられます。ポート番号はご利用のクライアント設定に合わせてください。MIXED や HTTP 専用ポートが 7890、SOCKS が 7891 といった構成が多いですが、ダッシュボードで実測値を確認するのが確実です。

事前準備:Clash 側で LAN からの接続を許可する

コンテナからホストのプロキシへ TCP で入るには、Clash が 127.0.0.1 だけでなく LAN 側でも待ち受けている必要があります。各 GUI クライアントでは Allow LAN(名称は製品により異なります)をオンにし、HTTP または MIXED ポートが外部(同一マシン内の別ネットワーク名前空間を含む)からも届く状態にします。

この考え方は、スマホや別 PC と共有するときの macOS での LAN プロキシ有効化と同じ系統です。初めて Clash 系クライアントを入れる場合は、先にClash Verge Rev の入門ガイドでポートと購読の流れを押さえると、以降の環境変数設定が迷いにくくなります。

ステップ 1:コンテナに渡す環境変数(コピペ用)

多くの CLI やパッケージマネージャは http_proxyhttps_proxy(大文字の HTTP_PROXYHTTPS_PROXY も)を参照します。コンテナ内では次のようにまとめて指定するのが扱いやすいです(ポートは環境に合わせて差し替えてください)。

export HTTP_PROXY="http://host.docker.internal:7890"
export HTTPS_PROXY="http://host.docker.internal:7890"
export http_proxy="http://host.docker.internal:7890"
export https_proxy="http://host.docker.internal:7890"
export NO_PROXY="localhost,127.0.0.1,::1,host.docker.internal"

NO_PROXY にローカル系を入れておくと、社内レジストリやローカル API への通信を誤ってプロキシに流さずに済みます。必要に応じて社内ドメインをカンマ区切りで追加してください。

SOCKS を直接使いたいツール向けには ALL_PROXY=socks5://host.docker.internal:7891 のような指定もありますが、aptnpm、Docker 公式デーモンのプロキシ設定は HTTP プロキシの方が相性がよい場面が多いです。

docker run で一時的に試す

まずは対話シェルで到達性を確認すると切り分けが早いです。次の例は Debian 系イメージでプロキシ環境変数を付与し、HTTPS の応答ヘッダだけを取得します。

docker run --rm -it \
  -e HTTP_PROXY="http://host.docker.internal:7890" \
  -e HTTPS_PROXY="http://host.docker.internal:7890" \
  -e NO_PROXY="localhost,127.0.0.1,host.docker.internal" \
  debian:stable-slim bash -lc 'apt-get update && apt-get install -y curl && curl -I https://registry-1.docker.io'

curl がタイムアウトする場合は、Clash のログで対象ドメインが期待するポリシーに乗っているか、Allow LAN が有効か、ポート番号の誤りがないかを順に確認します。TLS まわりで詰まるときは、ルール順や DNS 設定の影響もあり得るため、トラブルシューティング記事も併用してください。

ステップ 2:Docker Compose で常時適用する

開発用スタックでは docker-compose.ymlenvironment に同じキーを並べる方法が一般的です。複数サービスで共有するなら、リポジトリ直下に .env を置き、env_file: .env で読み込むとチーム内の差分管理がしやすくなります。

services:
  app:
    image: node:20-bookworm
    environment:
      HTTP_PROXY: http://host.docker.internal:7890
      HTTPS_PROXY: http://host.docker.internal:7890
      NO_PROXY: localhost,127.0.0.1,host.docker.internal

ビルド段階でパッケージ取得が必要な場合は、docker compose build にビルド引数として渡すか、Compose の build.argsHTTP_PROXY を書くパターンがあります。マルチステージビルドではステージごとに値が必要になる点に注意してください。

Docker Desktop の「手動プロキシ」設定(任意)

Docker Desktop の設定画面に、デーモンや一部のトラフィック向けの HTTP/HTTPS プロキシ欄があるバージョンでは、そこに http://host.docker.internal:7890 を入れると、docker pull などホスト側デーモンが行う取得が安定する場合があります。一方で、コンテナ内部apt やアプリの通信は、引き続きコンテナの環境変数側の設定が必要になることが多いです。「pull は速くなったがコンテナ内だけ遅い」というときは、その切り分けを意識してください。

企業ネットワークではプロキシ認証や PAC ファイルが絡むことがあります。その場合は資格情報の扱い(平文環境変数に載せない、シークレット機能を使う等)を情報システムの方針に合わせて設計してください。

Linux ホストを使う場合の一言(対比)

Linux ネイティブの Docker では host.docker.internal がデフォルトで無いことがあり、--add-host=host.docker.internal:host-gateway のような指定を追加するパターンが知られています。本稿の主題は macOS 上の Docker Desktop ですが、CI やリモート Linux に同じ Compose を流用するときは、この差だけ押さえておくと手戻りが減ります。

よくある落とし穴

127.0.0.1 のままにしている

コンテナ内のループバックはホストの Clash ではありません。host.docker.internal へ寄せるのが第一歩です。

HTTPS_PROXY を忘れる

ツールによっては HTTPS だけ別変数を見ます。両方そろえておくと再現性が上がります。

NO_PROXY が広すぎる/狭すぎる

広すぎると社内リソースまでプロキシに流れて失敗します。狭すぎるとローカル開発サーバーまでプロキシに吸われます。チームでホワイトリストを共有すると安全です。

docker build だけ失敗する

実行時用の environment とビルド時の ARG--build-arg は別経路です。Dockerfile 内の RUN apt-getnpm ci が詰まるならビルド引数を疑います。

まとめ

macOS の Docker Desktop では、コンテナとホストの「ループバックの取り違え」がプロキシ不達の最大要因です。host.docker.internal に Clash の HTTP ポートを合わせ、Allow LAN を有効にし、HTTP_PROXYHTTPS_PROXYNO_PROXY をセットで渡す——この組み合わせが、イメージ取得やパッケージインストールの詰まりを解く再現性の高い型になります。

GUI でルールやログを扱いやすいクライアントでホスト側を整えておくと、コンテナ側は環境変数の機械的な適用に集中でき、開発体験がかなり楽になります。同種ツールと比較しても、設定の見通しと安定性のバランスで Clash 系スタックは扱いやすい部類に入るはずです。→ Clash を無料ダウンロードし、macOS のホストと Docker の両方で快適に回す