開発環境で通信経路を分ける理由
GitHubのWebページは開けるのにgit cloneだけが遅い、SSH接続が22番ポートでタイムアウトする、Homebrewのダウンロードが途中で止まる。このような問題は、すべてを同じ「Clashの速度問題」として扱うと解決しにくくなります。ブラウザーはシステムプロキシを利用していても、ターミナル、Git、SSH、Homebrew、Dockerはそれぞれ異なる方法でネットワークへ接続するためです。
まず、Clashまたはmihomoが待ち受けるローカルポート、アプリケーションが実際に参照するプロキシ設定、そしてルールによって選ばれる出口を分けて考えます。一般的なデスクトップ環境では、mixed-port: 7890 がHTTPとSOCKS5を兼ねるローカルポートとして使われます。ただし、実際の番号はクライアントの設定画面やYAMLを確認してください。external-controller: 9090 は管理API用であり、GitやSSHのプロキシポートとして指定してはいけません。
mixed-port: 7890
allow-lan: false
mode: rule
log-level: info
接続テストの基本
まず通常のHTTPS通信をテストします。curlにプロキシを明示すれば、システムプロキシやシェルの環境変数に依存せず、Clashのローカルポートを経由できるか確認できます。
curl -I --connect-timeout 10 --max-time 30 \
-x http://127.0.0.1:7890 \
https://github.com
curl -I --connect-timeout 10 --max-time 30 \
--proxy socks5h://127.0.0.1:7890 \
https://api.github.com
socks5hの末尾のhは、ホスト名の解決もSOCKSプロキシ側で行う指定です。ローカルDNSで名前解決が失敗する環境では、socks5://よりsocks5h://のほうが切り分けに適しています。HTTPプロキシで成功し、SOCKS5で失敗する場合は、ポートの種類やクライアントの設定を確認してください。
TUNとルールで開発通信を整理する
システムプロキシだけを使う場合、アプリケーション側がHTTP、HTTPS、またはSOCKSプロキシを参照する必要があります。GitやHomebrewは環境変数を設定すれば対応できますが、SSHのように独自の接続方式を持つツールや、Docker Desktopのように別プロセスで動くサービスでは設定が別に必要です。
TUNモードは仮想ネットワークインターフェースを通じて、システムプロキシを参照しない通信もmihomoへ取り込む仕組みです。ターミナルから起動したバイナリ、SSH、コンテナ関連の通信を同じルール体系で扱える可能性がありますが、TUNを有効にしただけで必ずすべての通信が意図した出口になるわけではありません。OSの権限、ルーティング、DNS設定、除外ルートが影響します。
開発向けルールの考え方
開発環境では、GitHubのような開発サービス、コンテナレジストリ、言語パッケージの配布サイトを必要に応じて分類します。ルールは上から順に照合されるため、広すぎるルールを先に置くと、後ろに書いた細かいルールへ到達しません。業務ネットワークや社内ドメインを最初にDIRECTへ送るなど、例外を先に定義するのが安全です。
rules:
- DOMAIN-SUFFIX,corp.example,DIRECT
- DOMAIN-SUFFIX,github.com,Developer
- DOMAIN-SUFFIX,githubusercontent.com,Developer
- DOMAIN-SUFFIX,ghcr.io,Developer
- DOMAIN-SUFFIX,docker.io,Developer
- DOMAIN-SUFFIX,registry.npmjs.org,Developer
- DOMAIN-SUFFIX,api.github.com,Developer
- MATCH,DIRECT
上のドメインは構成例です。実際のプロキシグループ名、社内ドメイン、利用するレジストリに合わせて変更してください。github.comだけを登録しても、ソースコードの取得先、API、Git LFS、Releaseファイル、コンテナイメージの取得先が別ドメインである場合があります。接続ログを確認し、必要なホスト名を追加することが重要です。
GitのHTTPSとSSHを設定する
GitHubリポジトリをHTTPS URLで利用する場合、GitにはHTTPプロキシを直接設定できます。これはGitの通信だけに適用されるため、ターミナル全体の挙動を変えたくない場合に向いています。
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 --get http.proxy
git config --global --get https.proxy
SOCKS5を使う場合は、Gitのバージョンやビルドによって動作差があるため、まずHTTPプロキシ方式を推奨します。不要になったときは設定を削除してください。無効なポートを残すと、Clashを終了した後もGitだけが接続エラーになります。
git config --global --unset http.proxy
git config --global --unset https.proxy
git config --show-origin --get-regexp 'http\..*proxy|https\..*proxy'
GitHub SSHを443ポートで使う
SSH URLの[email protected]:owner/repository.gitは、通常TCP 22番ポートへ接続します。ネットワーク側で22番ポートが制限されている場合、Clashを起動していてもSSHはタイムアウトします。GitHubが提供するSSH over HTTPSの入口を利用すると、TCP 443番ポートへ接続できます。
macOSやLinuxでは、~/.ssh/configに次の設定を追加します。ファイルが存在しない場合は作成し、権限が広すぎないようにしてください。
Host github.com
HostName ssh.github.com
User git
Port 443
IdentityFile ~/.ssh/id_ed25519
IdentitiesOnly yes
この方式ではHTTPSプロキシを使っているのではなく、SSHの接続先とポートを443番へ変更しています。Clashのルールでssh.github.comを目的のプロキシグループへ送れることを確認してください。設定後は、詳細ログを有効にして認証とネットワークのどちらで失敗しているかを分けます。
ssh -T -p 443 [email protected]
ssh -vT [email protected]
git clone [email protected]:owner/repository.git
Permission denied (publickey)は、ネットワーク接続自体は成立したものの、SSH鍵の登録や選択に問題がある可能性を示します。一方、Connection timed outは到達性、ポート、ルーティング、プロキシ経路を先に確認すべきエラーです。秘密鍵の内容をログや問い合わせ画面へ貼り付けないでください。
SSHをSOCKSプロキシ経由にする
TUNを使わず、SSHだけをSOCKS5経由にしたい場合は、OpenSSHのProxyCommandを利用できます。macOSや多くのLinux環境では、利用可能なncがSOCKSオプションに対応しています。
Host github.com
HostName github.com
User git
Port 22
IdentityFile ~/.ssh/id_ed25519
IdentitiesOnly yes
ProxyCommand nc -x 127.0.0.1:7890 -X 5 %h %p
ただし、OSに付属するncの実装は環境によって異なり、-xや-Xをサポートしないことがあります。その場合は、TUNを使う、GitHubの443番ポートへ切り替える、または環境に合ったSOCKS対応の接続ヘルパーを用意する方法を選びます。コマンドを無理に変更して動かすより、ssh -vTでProxyCommandが実行されているか確認するほうが安全です。
Homebrewとパッケージ取得を安定させる
Homebrewの通信は、FormulaやCaskのメタデータ、Gitリポジトリ、バイナリボトルの保存先など複数のホストへ分かれることがあります。ブラウザーでGitHubが開けても、ターミナルのHomebrewが同じ経路を使うとは限りません。まずClashのHTTPプロキシを環境変数へ設定して、現在のシェルから起動するコマンドに適用します。
export HTTP_PROXY=http://127.0.0.1:7890
export HTTPS_PROXY=http://127.0.0.1:7890
export ALL_PROXY=socks5h://127.0.0.1:7890
export NO_PROXY=localhost,127.0.0.1,::1
brew update
brew config
brew doctor
プロキシを常用する場合は、使用しているシェルの設定ファイルに追記できます。ただし、会社内のGitサーバーやローカル開発環境まで外部プロキシへ送ると、認証や名前解決に失敗することがあります。NO_PROXYには、社内ドメイン、ローカルホスト、開発用IP範囲を環境に合わせて追加してください。
export NO_PROXY=localhost,127.0.0.1,::1,.corp.example,10.0.0.0/8
Homebrewが使用するGit操作とHTTPダウンロードは、同じ環境変数を参照するとは限りません。取得が途中で止まる場合は、brew update、個別のcurl、GitHub APIへの接続を別々にテストします。Homebrewの設定を恒久的に変更する前に、1つのターミナルセッションで環境変数を設定して結果を比較するのがよいでしょう。
Dockerのプロキシは別設定
Docker CLIでdocker pullを実行する場合、イメージ取得を担当するDocker EngineやDocker Desktopのバックグラウンドサービスが通信します。ターミナルでHTTPS_PROXYを設定しただけでは、デーモン側の通信に反映されないことがあります。Docker Desktopを利用している場合は、アプリの設定画面にあるResourcesまたはProxies関連の項目を確認し、ClashのローカルプロキシをDockerから到達できるアドレスで指定します。
127.0.0.1がDockerの仮想環境内でホスト自身を指さない場合もあります。Docker Desktopの実装やOSによってホストへの到達方法が異なるため、設定後は小さなイメージでテストしてください。LinuxでDocker Engineをsystemdサービスとして動かしている場合は、サービスの環境設定、再起動、ログ確認が必要です。
docker pull hello-world
docker info
docker system info
ログと段階的な検証
設定を変更した後は、Git、SSH、Homebrew、Dockerを一度に試すのではなく、下の順番で確認すると原因を絞り込めます。最初にClashの接続ログで対象ドメインが表示されるか確認し、次にルール名と出口ノードを確認します。接続先がログに現れない場合は、TUNが通信を取り込んでいない、またはアプリケーションが別のネットワーク名前空間を使っている可能性があります。
- ポート確認:
127.0.0.1:7890でClashが待ち受けているか確認します。ポート番号は実際の設定に合わせます。 - HTTPS確認:
curl -xまたは--proxy socks5h://でGitHub APIへ接続します。 - Git確認:HTTPSリポジトリを少量のデータで
git ls-remoteし、認証前の接続を確認します。 - SSH確認:
ssh -vTで名前解決、ポート接続、鍵認証の順番を確認します。 - パッケージ確認:
brew updateや小さなDockerイメージで取得を試します。
git ls-remote https://github.com/owner/repository.git
git ls-remote [email protected]:owner/repository.git
curl -sS --proxy http://127.0.0.1:7890 \
https://api.github.com/rate_limit | head
GitHubへの通信が遅い場合でも、常にプロキシを強制する必要はありません。自宅回線ではDIRECTのほうが速く、特定のネットワークだけプロキシが必要というケースもあります。ルールの出口を固定する代わりに、プロキシグループの遅延テスト、接続ログ、失敗率を確認し、開発サービスだけを対象にするほうが副作用を抑えられます。
よくある質問
Gitだけが失敗するのはなぜですか?
Gitがシステムプロキシを自動参照していない、またはhttp.proxyに停止したポートが残っている可能性があります。git config --show-origin --get-regexp 'proxy'で設定元を確認し、HTTPSプロキシを明示してから再テストしてください。
SSHの22番ポートが使えない場合はどうしますか?
GitHubではssh.github.comの443番ポートを使う方法があります。~/.ssh/configでHostName ssh.github.comとPort 443を指定し、ssh -vT [email protected]で接続先が正しいか確認します。
TUNを有効にすれば環境変数は不要ですか?
必ずしも不要ではありません。TUNは通信を取り込む仕組みですが、アプリケーションや仮想環境の構成によっては別のネットワーク経路を使います。Git、Homebrew、Dockerでは、まず環境変数やサービス固有のプロキシ設定を確認し、必要に応じてTUNと組み合わせます。
Dockerの取得だけが止まる場合はどうしますか?
Docker CLIではなく、Docker EngineまたはDocker Desktopのデーモンがレジストリへ接続しています。Docker側のプロキシ設定、Clashのルール、ホストへの到達アドレスを確認し、docker pull hello-worldで小さなイメージを使って検証してください。