システムプロキシが効かないときの対処法:ブラウザはプロキシ経由なのにターミナルが直結する原因と確認方法

システムプロキシは環境変数や設定項目にすぎず、ブラウザが従ってもターミナルのコマンドが読み取るとは限りません。2つの経路に分けて確認コマンドと解決方法を紹介し、全通信を制御するTUNモードへ切り替えるタイミングも解説します。

まずシステムプロキシと実際の通信経路を切り分ける

Clash クライアントの「システムプロキシ」は、通常すべてのプログラムを対象にするグローバルトンネルではありません。OSのHTTPおよびHTTPSプロキシアドレスを127.0.0.1に設定し、Clashが待ち受けているローカルポートを指定します。ブラウザはこの設定を読み取り、リクエストをClashへ渡します。一方、ターミナルのプログラムが設定を読み取るかどうかは、プログラム自体や起動環境、プロキシプロトコルによって異なります。

よくある初期値はHTTPポート7890、SOCKS5ポート7891、またはmixed-port: 7890でHTTPとSOCKS5の両方を受け付ける構成です。ポート番号に固定の規格はありません。設定ファイルやクライアントのバージョン、ユーザーによる上書きで変更される場合があります。確認時は、クライアントの「設定」→「ポート設定」または現在の設定ファイルにある項目を基準にしてください。

mixed-port: 7890
allow-lan: false
mode: rule

dns:
  enable: true
  enhanced-mode: fake-ip

Webページは開けるのに、curlgitnpm、またはコマンドラインのダウンローダーだけが直接接続する場合、通常はノード全体が停止しているわけではありません。より正確には、ブラウザの経路はClashに入っている一方、ターミナルの経路が入っていないか、入っていてもDNS、プロトコル、ルールが異なっています。

1つ目の経路:ブラウザがシステムプロキシを読み取る仕組み

Clashのローカルポートが待ち受け中か確認する

システムプロキシが待ち受けていないポートを指定していると、ブラウザには通常、接続拒否が表示されます。Windows PowerShellでは7890を確認し、macOSとLinuxでは該当するプロセスを調べます。実際のポートが7890でない場合は、コマンド内の数字を置き換えてください。

# Windows PowerShell
Get-NetTCPConnection -LocalPort 7890 -State Listen

# macOS
lsof -nP -iTCP:7890 -sTCP:LISTEN

# Linux
ss -lntp | grep 7890

期待される結果には、127.0.0.1:78900.0.0.0:7890のようなローカル待ち受けアドレスが含まれます。結果が表示されない場合はクライアントに戻り、設定が起動しているか、プロキシが有効か、ポートを別のプログラムが使用していないか確認します。ポートが競合している場合は一時的に7897へ変更し、システムプロキシとターミナルの変数も同じ番号に更新します。

OSのプロキシアドレスを確認する

  • Windows 11:「設定」→「ネットワークとインターネット」→「プロキシ」→「手動プロキシ設定」と進みます。アドレスは127.0.0.1、ポートはClashのHTTPまたはmixedポートと一致している必要があります。
  • macOS:「システム設定」→「ネットワーク」→現在のネットワークインターフェース→「詳細」→「プロキシ」と進みます。Webプロキシ(HTTP)と保護されたWebプロキシ(HTTPS)を確認します。
  • Firefox:「設定」→「一般」→「ネットワーク設定」と進みます。「手動でプロキシを設定する」が選ばれている場合、システムプロキシより優先されます。OSの設定に従わせるには「システムプロキシ設定を使用する」を選択してください。
  • ChromeとEdgeは通常、OSのプロキシ設定を読み取ります。ただし、拡張機能、企業ポリシー、ブラウザの起動オプションによって経路が書き換えられる場合があります。

ブラウザの検証では、ページの表示結果とClashの接続ログを同時に確認します。これまで開いていないサイトへアクセスし、クライアントの接続画面でドメイン名を絞り込みます。対象ドメイン、適用されたルール、出口ノードが表示されれば、リクエストはカーネルに入っています。ページが開くかどうかだけでは、プロキシ経由、キャッシュヒット、直接接続を区別できません。

ルールによってブラウザが直接接続していないか確認する

システムプロキシを有効にしても、必ずプロキシノードが使われるとは限りません。mode: ruleでは、リクエストがさらにルール判定を受けます。接続ログにDIRECTと表示される場合は、ドメインルール、ルールセット、最終ルールを確認します。一時的にグローバルモードへ切り替えて比較することはできますが、検証後はルールモードに戻してください。

rules:
  - DOMAIN-SUFFIX,example.com,Proxy
  - GEOIP,CN,DIRECT
  - MATCH,Proxy

グローバルモードでは使えるのにルールモードでは使えない場合、問題はシステムプロキシのスイッチではなく、ルールの順序、プロキシグループの選択、またはサブスクリプションの生成内容にあります。Clashのルールは上から順に評価され、最初に一致した時点で停止します。範囲の広いDIRECTルールを前に置くと、後続のドメインルールが先に処理されてしまうことがあります。

2つ目の経路:ターミナルのプログラムが設定に従わない理由

ターミナルのウィンドウ自体がネットワーク通信を自動転送するわけではありません。実際にリクエストを送るのはcurl、Git、Node.js、Pythonのパッケージマネージャーなどのコマンドです。各プログラムには独自のプロキシ読み取り方式があります。HTTP_PROXYHTTPS_PROXYを読むもの、小文字の変数を読むもの、コマンド引数だけを受け付けるもの、独立した設定ファイルを使うものなどさまざまです。

curlでプロキシを明示して基準テストを行う

まず環境変数を使わず、curlからClashのHTTPポートへ直接接続します。この手順により、「ターミナルがシステム設定を読み取っていない」のか「Clashのローカルプロキシが使えない」のかを切り分けられます。

curl -v -x http://127.0.0.1:7890 https://api.ipify.org

curl -v --connect-timeout 10 \
  -x http://127.0.0.1:7890 \
  https://www.example.com/

出力にはまず127.0.0.1:7890への接続が現れ、その後HTTPSのCONNECT処理が続きます。プロキシを明示すると成功し、-xなしでは失敗する場合、ノード、ポート、Clashカーネルはおおむね正常です。以降はターミナルの設定だけを確認します。

SOCKS5のテストにはsocks5hを使用できます。末尾のhはドメイン名の解決をプロキシ側で行うことを示し、ローカルDNSの異常を切り分けるのに適しています。socks5では通常、ドメイン名を先にローカルで解決してからIPアドレスをプロキシへ渡します。

curl -v --proxy socks5h://127.0.0.1:7891 \
  https://api.ipify.org

現在のターミナルに環境変数を設定する

macOS、Linux、Git Bash、多くのUnix系シェルでは、現在のセッションに変数をエクスポートできます。ツールごとの読み取り仕様に対応するため、大文字と小文字の両方を設定するのがおすすめです。ターミナルを閉じると、これらの一時変数は無効になります。

export http_proxy=http://127.0.0.1:7890
export https_proxy=http://127.0.0.1:7890
export HTTP_PROXY=http://127.0.0.1:7890
export HTTPS_PROXY=http://127.0.0.1:7890
export NO_PROXY=localhost,127.0.0.1,::1

curl -v https://api.ipify.org

PowerShellでは、現在のプロセス環境に書き込めます。実行後に影響するのは、そのPowerShellウィンドウと、そこから起動した子プロセスだけです。すでに開いているエディターや別のターミナルは自動的に変更されません。

$env:HTTP_PROXY="http://127.0.0.1:7890"
$env:HTTPS_PROXY="http://127.0.0.1:7890"
$env:NO_PROXY="localhost,127.0.0.1,::1"

curl.exe -v https://api.ipify.org

検証が終わったらテスト用の変数を削除し、Clash終了後もプログラムが使えないローカルポートへ接続し続けないようにします。

# bash / zsh
unset http_proxy https_proxy HTTP_PROXY HTTPS_PROXY NO_PROXY

# PowerShell
Remove-Item Env:HTTP_PROXY
Remove-Item Env:HTTPS_PROXY
Remove-Item Env:NO_PROXY

Git、npm、Pythonの個別設定

環境変数は一時的な切り分けに適しています。継続して使う場合は、ツールに古いポートが保存されていないかも確認してください。Gitはグローバル設定とリポジトリ設定を個別に読み取り、リポジトリ内の項目が優先されます。

git config --global --get http.proxy
git config --global --get https.proxy
git config --local --get http.proxy

git config --global http.proxy http://127.0.0.1:7890
git config --global https.proxy http://127.0.0.1:7890

# グローバルプロキシを削除
git config --global --unset http.proxy
git config --global --unset https.proxy

npmではnpm config get proxynpm config get https-proxyで確認できます。値がnullの場合に限り、npmが環境変数を参照し続ける可能性があります。古い設定が127.0.0.1:7897を指していると、システムプロキシを7890に変更しても、npmは古いポートへ接続します。

npm config get proxy
npm config get https-proxy

npm config set proxy http://127.0.0.1:7890
npm config set https-proxy http://127.0.0.1:7890

npm config delete proxy
npm config delete https-proxy

Pythonのpipは環境変数を読み取れるほか、コマンド引数でもテストできます。1回だけインストールにプロキシを追加する場合は、設定へ恒久的に書き込むより引数を使うほうが元に戻しやすくなります。

python -m pip install --proxy http://127.0.0.1:7890 package-name

python -m pip config list
python -m pip config debug

DNS、IPv6、UDP:プロキシ経由でも失敗する場合

名前解決の失敗と接続の失敗を切り分ける

ターミナルのエラーメッセージに含まれるキーワードから、原因の範囲を絞り込めます。Could not resolve hostは名前解決の段階を示します。Connection refusedは通常、ローカルのプロキシポートが待ち受けていないことを意味します。Operation timed outは、ノードの経路、ルールの出口、ファイアウォール、対象サイトの応答遅延などが考えられます。TLS証明書エラーの場合は、システム時刻、証明書ストア、プログラムが使用するTLSバックエンドを確認してください。

HTTPプロキシ経由でHTTPSサイトへアクセスすると、クライアントは通常、まずプロキシへCONNECTを送信します。SOCKS5では、socks5hsocks5で名前解決を行う場所が異なります。通常のsocks5で失敗し、socks5hで成功する場合は、サブスクリプションをすぐに変更せず、まずローカルDNSを確認してください。

IPv4とIPv6の結果を確認する

ターミナルのプログラムによってはIPv6を優先しますが、現在のネットワークではIPv6の経路が不完全な場合があります。curl -4curl -6を別々に実行して比較してください。IPv4が2秒以内に返り、IPv6が10秒後にタイムアウトするなら、問題はHTTPプロキシ変数ではなくIPv6経路にあります。

curl -4 -I --connect-timeout 10 https://www.example.com/
curl -6 -I --connect-timeout 10 https://www.example.com/

curl -4 -I -x http://127.0.0.1:7890 https://www.example.com/
curl -6 -I -x http://127.0.0.1:7890 https://www.example.com/

なお、従来のHTTPシステムプロキシが主に扱うのは、TCP上のHTTPとHTTPSです。UDPベースのQUIC、ゲーム通信、音声アプリ、自作プロトコルなどは、この入口を通らない場合があります。ブラウザはプロキシ環境でTCPへフォールバックすることがありますが、他のアプリが同じ動作をするとは限りません。そのため、Webページは正常でも特定のアプリだけタイムアウトすることがあります。

TUNモードへ切り替えるタイミング

TUNモードは仮想ネットワークインターフェースとシステムルーティングを使い、より多くのIP通信を取り込みます。各アプリがHTTPプロキシを理解したり、HTTP_PROXYを読み取ったりする必要はありません。複数のターミナルツールやUDPアプリ、プロキシ設定に対応しないソフトを対象にしたい場合、またはプロキシ変数を個別に管理する手間を減らしたい場合は、通常システムプロキシよりTUNが適しています。

TUNへの切り替えが適しているケース

  • ブラウザは安定してClashへ接続できるのに、複数のコマンドラインツールがシステムプロキシを無視する。
  • アプリが独自のTCPまたはUDPプロトコルを使用し、HTTP、HTTPS、SOCKS5のプロキシ設定に対応していない。
  • 開発環境にコンテナ、パッケージマネージャー、バックグラウンドプロセスがあり、環境変数を1つずつ設定する負担が大きい。
  • DNSクエリと接続通信を同じルールに従わせ、ローカルの名前解決経路の違いを減らしたい。
  • システムプロキシを無効にしても、DIRECT、プロキシグループ、最終出口をルールで決めたい。

mihomoカーネルでよく使われる設定には、tun.enablestack、自動ルート、DNSハイジャックなどがあります。利用できる値は、クライアントに組み込まれたカーネルのバージョンとOSの権限によって異なります。変更前に動作中のProfileを保存し、クライアントが提供する設定画面から有効化してください。システムルートを別に手動作成するのは避けます。

tun:
  enable: true
  stack: mixed
  auto-route: true
  auto-detect-interface: true
  dns-hijack:
    - any:53

tun.enable: true · stack: mixed · auto-route: true

有効化したら、まずシステムプロキシを無効にして比較テストを行います。同じリクエストがシステムプロキシに入り、さらにTUNで二重に取り込まれるのを防ぐためです。多くのカーネルはこの組み合わせに対応しますが、トラブル対応中は経路を1つにしたほうが判断しやすくなります。その後、ブラウザ、curl、Git、対象アプリを個別にテストし、接続ログで適用ルールを確認します。

AndroidにおけるシステムプロキシとVPN経路

Androidクライアントは通常、デスクトップOSで一般的なHTTPプロキシ設定ではなく、システムのVpnServiceを使ってローカルVPNインターフェースを作成します。初回起動時に表示される接続リクエストは、Androidシステムによる許可確認です。許可すると、アプリがVPNインターフェースを作成し、そこへルーティングされた通信を受け取れるようになります。

Androidのブラウザは使えるのにTermuxのコマンドが使えない場合は、まずクライアントでアプリごとのプロキシ、アプリのバイパス、または選択したアプリのみのプロキシが有効になっていないか確認します。メニュー名はクライアントによって異なりますが、よくある入口は「設定」→「ネットワーク」→「アクセス制御」、または「設定」→「詳細設定」→「アプリごとのプロキシ」です。プロキシ対象アプリの一覧にTermuxが含まれていなければ、その通信は物理ネットワークへ直接出ている可能性があります。

  • 接続ログでTermuxからのリクエスト先ドメインを検索する。
  • アクセス制御が「選択したアプリのみプロキシ」なのか「選択したアプリをバイパス」なのか確認する。
  • プライベートDNSを短時間だけ無効にして比較し、その後元の設定に戻して結果を記録する。
  • 画面消灯後にVPNサービスを終了させる省電力設定がないか確認する。
  • 現在のProfileでDNS、TUN、ルールグループが実際に適用されているか確認する。

Termuxではexport HTTPS_PROXY=http://127.0.0.1:ポートも使えますが、ループバックアドレスとポートはAndroidクライアントが本当にローカルアプリ向けに開放している必要があります。クライアントが主にVPNインターフェースで動作し、ローカルHTTP待ち受けを開放していない場合、この変数を設定しても有効な接続にはなりません。その場合はデスクトップのポート設定を流用せず、まずVPNの対象アプリ範囲を修正してください。

順番に実行する最終チェックリスト

  1. ClashクライアントでProfileが起動し、プロキシグループに利用可能なノードが選択されていることを確認する。
  2. 現在のmixed-portportsocks-portを読み取り、必ず7890だと決めつけない。
  3. 待ち受け確認コマンドでローカルポートの存在を確認し、ポート競合を除外する。
  4. ブラウザで新しいページを開き、Clashの接続ログと適用ルールを同時に確認する。
  5. -x付きのcurlを実行し、プロキシを明示した基準テストを行う。
  6. 明示的なプロキシ接続が成功したら、現在のターミナルにプロキシ環境変数を設定する。
  7. Git、npm、pipなどのツールに保存された個別のプロキシ設定と古いポートを確認する。
  8. socks5h-4-6を使い、DNSとIPの経路を切り分ける。
  9. HTTP以外の通信、UDP、大量のバックグラウンドプログラムを取り込みたい場合は、TUNへ切り替えて単一経路で検証する。
  10. 検証後は一時変数を削除し、ルールモードと元のDNS設定に戻す。

最も重要なのは「プロキシのスイッチがオンか」ではなく、リクエストが実際にどの経路を通っているかです。ブラウザではシステムプロキシとルールを、ターミナルではプログラムの引数、環境変数、個別設定を確認し、複雑なアプリではTUN、ルーティング、DNSも確認します。待ち受けポート、明示的なプロキシ、環境変数、ツール設定、TUNの順に調べれば、サブスクリプションを変更せずに原因を特定できることが多いでしょう。

クライアントとトラブル対応の入口

プラットフォームに対応したClashクライアントを選ぶか、初回設定、システム権限、接続手順を確認します。

Clashをダウンロード