まず、エラーが発生しているリスニングポートを確認

Clashの起動時にポート使用中のエラーが表示される場合、多くはカーネルがローカルのリスナーを作成する段階で発生しています。ログの bind: address already in use は、指定されたアドレスとポートに現在の設定ではバインドできないことを示します。Windowsでは Only one usage of each socket address と表示されることもあります。これはサブスクリプションの期限切れやノードへの接続可否とは別の問題です。まずノードを変更しても解決しないことがほとんどです。

mixed-port は、同じポートでHTTPとSOCKSのプロキシ接続を受け付けます。この記事では旧ポートを7890、変更後を17890として説明しますが、どちらも例であり、実際にこの端末が7890を使用していることや、17890が空いていることを示すものではありません。まずクライアントのログを開き、エラー行にあるアドレス、ポート、プロトコルを控えてください。

項目用途対処方法
mixed-portHTTPとSOCKSの共用プロキシ入口変更後、システムプロキシとアプリのプロキシ設定も更新
port / socks-portHTTP/SOCKS専用の入口混合プロキシ入口と設定が重複していないか確認
external-controllerクライアントからカーネルに接続するための制御インターフェースクライアントの制御インターフェース設定と合わせて変更
dns.listenカーネルのDNSサービスが待ち受けるアドレスログに記録されたDNSポートを個別に確認

Windows:7890を使用しているプロセスと起動元を特定

PowerShellでリスニングPIDを調べる

PowerShellを開き、次のコマンドを実行します。OwningProcess はポートを使用しているプロセスIDであり、プログラム名ではありません。アクセスが拒否された場合は、管理者権限でターミナルを開いてください。正体の分からないシステムプロセスを安易に終了しないでください。

Get-NetTCPConnection -LocalPort 7890 -State Listen |
  Select-Object LocalAddress, LocalPort, State, OwningProcess

検索結果のPIDが1234だった場合は、続けてプロセス名、実行ファイルのパス、起動コマンドを確認します。以下の数字はコマンドの使い方を示す例です。実際に実行するときは、直前のコマンドで返されたPIDに置き換えてください。

Get-Process -Id 1234 |
  Select-Object Id, ProcessName, Path

Get-CimInstance Win32_Process -Filter "ProcessId = 1234" |
  Select-Object ProcessId, ExecutablePath, CommandLine

パスと起動引数から、別のクライアントが独立したカーネルを起動しているのか、同じクライアントのバックグラウンドサービスが残っているのかを見分けられます。名前がどちらもmihomo.exeでも、インストール先が異なる場合があります。タスクバーのウィンドウを閉じてもプロセスが終了したとは限りません。まず通知領域のメニューから該当クライアントを正常終了し、ポートをもう一度調べてください。

netstatでも照合する

netstat -ano -p tcp | findstr ":7890"
tasklist /FI "PID eq 1234"

findstr はテキストを絞り込むだけのため、リモートポートや同じ数字を含む別のポートが表示されることがあります。「ローカルアドレス」列が実際に:7890で終わっているか、状態がLISTENINGかを確認してください。通常のESTABLISHED接続だけでは、ローカルで7890番ポートを待ち受けるプロキシがあるとは判断できません。

  • 127.0.0.1:7890:IPv4ループバックで待ち受け。
  • 0.0.0.0:7890:IPv4の全インターフェースで待ち受け。ループバックアドレスへのバインドと競合する可能性があります。
  • [::]:7890:IPv6の全インターフェースで待ち受け。IPv4にも影響するかどうかはソケットの設定によります。

ログにUDPのバインド失敗が明記されている場合は、UDPエンドポイントを調べてください。UDPにはTCPのLISTENING状態がないため、TCPのリスニングだけを絞り込む方法では判断できません。

Get-NetUDPEndpoint -LocalPort 7890 |
  Select-Object LocalAddress, LocalPort, OwningProcess

macOS・Linux:リスニングプロセスとバックグラウンドサービスを確認

macOS:lsofを使う

「ターミナル」で次のコマンドを実行します。-nP は名前解決を避け、アドレスとポートを数字のまま表示します。-sTCP:LISTEN はリスニング中のソケットだけを表示します。権限不足で結果が不完全な場合は、コマンドの先頭にsudoを付けてください。

lsof -nP -iTCP:7890 -sTCP:LISTEN
ps -p 1234 -o pid,ppid,command

COMMAND、PID、起動コマンド全体を確認したら、該当クライアントのメニューから正常終了します。プロセスがすぐに再び現れる場合は、ログイン項目、クライアントのバックグラウンドコンポーネント、サービス管理ツールなどが起動を管理している可能性があります。該当する起動元を停止してからプロセスを終了してください。強制終了を繰り返しても、監視プロセスがカーネルを何度も再起動するだけです。

Linux:ssを使う

sudo ss -ltnp 'sport = :7890'
sudo ss -lunp 'sport = :7890'
ps -p 1234 -o pid,ppid,args

1つ目のコマンドでTCPのリスニングを、2つ目でUDPのバインドを確認します。ss は通常、ディストリビューションのiproute2パッケージに含まれています。インストールされていない場合は、インストール済みのlsofで調べてください。プロセス情報をすべて表示するには管理者権限が必要な場合があります。

カーネルをsystemdで起動している場合は、実際に使われているサービスユニットとExecStartを確認してください。デスクトップクライアントを閉じても、サービスは停止しないことがあります。Dockerのポート公開にも注意が必要です。ホストの7890番ポートをコンテナが使用している可能性があるため、現在ログイン中のユーザーが起動したプログラムだけを調べても不十分です。まずポートの使用元を確認し、元の管理手段から停止してください。

旧ポートを空けるか、mixed-portを変更するか

使用中のプロセスを特定しても、すぐに終了する必要はありません。まず、そのプロセスを動かし続ける必要があるか判断してください。古いクライアントや重複起動したカーネルであれば、重複したインスタンスを終了して1つだけ残します。別のサービスが使用中なら、そのサービスを中断するよりClashのプロキシ入口を変更するほうが適切です。

  1. 現在のポート、システムプロキシのアドレス、アプリ個別のプロキシアドレスを控えます。
  2. 候補の17890を、7890と同じ方法で確認します。
  3. 使用するクライアントとカーネルのインスタンスを決め、2組の設定を同時に変更しないようにします。
  4. 実際に適用されている設定を変更し、カーネルを再読み込みまたは再起動します。
  5. 新しいポートで待ち受けていることを確認してから、システムとアプリで使うポートを更新します。

YAMLとクライアント設定でmixed-portを変更する

設定ファイルを直接管理している場合

まず設定ファイルをバックアップし、YAMLの最上位にある既存のmixed-portを変更してください。ファイル末尾に同名の項目を追加してはいけません。以下はプロキシ入口に関する設定例の一部です。既存の完全な設定に取り込み、ノード、グループ、DNS、ルールはそのまま残してください。

# 既存の設定に追加する(サブスクリプション全体ではありません)
mixed-port: 17890
allow-lan: false
bind-address: "127.0.0.1"

この例は端末内だけで使用する場合を想定しています。以前からLAN内でプロキシを共有していた場合は、アクセス範囲の設定をそのまま流用せず、待ち受けアドレス、認証、ファイアウォールルールを別途確認してください。端末内のポート競合を解決するために、ついでにLANアクセスを有効にしないでください。ポート競合の解消にはなりません。

port: 17890 や socks-port: 17890 が設定されていないかも確認してください。専用の入口と混合入口で、同じアドレスとTCPポートを重複してバインドしないでください。混合入口だけを使う場合は、クライアントが専用入口に依存していないことを確認したうえで、該当する専用ポート項目を削除するか、カーネルの設定仕様に従って0にして無効化します。

mihomoを手動で起動する場合は、ターミナルで設定を確認できます。ここでは、現在のディレクトリにある実際のファイル名がconfig.yamlで、カーネルのコマンドがmihomoであるとします。

mihomo -t -f config.yaml

-t は設定のテストに使うもので、プロキシの待ち受け開始を確認する機能ではありません。テスト後は通常の起動方法でファイルを読み込み、起動ログを確認してください。クライアントが独自にダウンロードまたは生成する実行時設定は、このファイルとは異なる可能性があります。実際に使用されないコピーだけをテストしないようにしてください。

GUIクライアントで設定を管理している場合

まず、クライアント設定に「混合ポート」「Mixed Port」「プロキシポート」などの項目があるか確認してください。項目名はクライアントやバージョンによって異なります。これらは該当項目を見つけるための名称であり、共通のメニュー階層を示すものではありません。項目を変更して保存したら、クライアントの手順に従ってカーネルを再読み込みします。サブスクリプションの元データだけを編集しても、クライアントが生成するポート設定には反映されないことがあります。

  • 画面にポート設定がある:画面から変更し、実行ログに新しいポートが表示されることを確認します。
  • 該当項目が画面にない:クライアントがローカル上書き設定やマージ設定に対応しているか確認し、そこで最上位のmixed-portを設定します。
  • サブスクリプション更新後に7890へ戻る:上書きされるサブスクリプションのキャッシュを直接編集していないか確認し、クライアントが提供する永続設定の場所に変更を移します。
  • 保存後も旧ポートで待ち受けている:選択中の設定、実行ファイルのパス、クライアント設定の優先順位を確認してから、正しいカーネルのインスタンスを再起動します。

変更前にシステムプロキシを無効にしておくと、まだ待ち受けていないポートへの接続を避けられます。新しいポートで起動できたら、システムプロキシを再度有効にしてください。クライアントがシステムプロキシを自動設定する場合も、自動で同期されたと決めつけず、システムの設定画面で実際の値を確認します。

システムプロキシ、ブラウザー、コマンドラインのポートを更新

カーネルを17890に変更した後も、システムが7890に接続していると、「ポート競合は解消したのにWebページが開かない」原因になります。端末内のHTTPプロキシの接続先は127.0.0.1:17890に変更してください。混合ポートはSOCKS接続も受け付けますが、入力時はアプリが求めるプロキシの種類と形式に従ってください。

設定箇所確認する設定画面・方法新しい値の例
Windows 11「設定」→「ネットワークとインターネット」→「プロキシ」→「手動プロキシ セットアップ」→「編集」アドレス:127.0.0.1、ポート:17890
近年のmacOS「システム設定」→「ネットワーク」→使用中のネットワークの「詳細」→「プロキシ」WebプロキシとセキュアWebプロキシのアドレスとポートを確認
Firefoxの個別プロキシ設定「設定」→「一般」→「ネットワーク設定」→「設定」システムプロキシを使うか、手動プロキシのポートを更新
コマンドラインツールHTTP_PROXY、HTTPS_PROXY、ALL_PROXYと各ツール独自の設定を確認新しいポートに変更し、必要に応じてターミナルを開き直す

Linuxのデスクトップ環境には、共通のシステムプロキシ設定メニューがありません。GNOME、KDE、各アプリがそれぞれ設定を管理している場合があります。WindowsのシステムプロキシとWinHTTPプロキシも別の設定です。後者はnetsh winhttp show proxyで個別に確認できます。WinHTTPのリセットを、すべてのブラウザー不具合に使える一般的な対処法と考えないでください。

次のPowerShellコマンドが変更するのは、現在のセッションのHTTPプロキシ環境変数だけです。すべてのアプリの設定が変わるわけではありません。HTTPSの宛先へローカルHTTPプロキシ経由でトンネル接続する場合も、プロキシのアドレスにはhttp://を指定できます。宛先がHTTPSだからといって、ローカルの入口をTLSにする必要はありません。

$env:HTTP_PROXY = "http://127.0.0.1:17890"
$env:HTTPS_PROXY = "http://127.0.0.1:17890"

macOS・Linuxでは、シェルで一時的に設定できます:

export http_proxy=http://127.0.0.1:17890
export https_proxy=http://127.0.0.1:17890

以前にALL_PROXY、Gitのhttp.proxy、エディター内蔵のプロキシを設定していた場合は、それらも個別に確認してください。環境変数の読み取り方法はツールごとに異なります。また、環境変数を変更しても、起動中のアプリには通常、新しい値が自動反映されません。

待ち受け、リクエスト、再起動を確認して完了

まずローカルの待ち受けを確認し、次にリクエストをテスト

前述のポート確認をもう一度実行し、7890を17890に置き換えて、使用予定のカーネルが待ち受けていることを確認します。次にプロキシを明示してリクエストを送り、システムプロキシの設定が反映されているかどうかに左右されない形でテストします。Windowsではcurl.exeを使うと、PowerShell環境によって同名のエイリアスが引数の解釈に影響するのを避けられます。

# Windows
curl.exe --noproxy "" --proxy http://127.0.0.1:17890 --connect-timeout 5 --max-time 15 -I https://example.com

# macOS / Linux
curl --noproxy "" --proxy http://127.0.0.1:17890 --connect-timeout 5 --max-time 15 -I https://example.com

ここでの5秒は接続タイムアウトの上限、15秒はリクエスト全体のタイムアウトです。性能測定の結果ではありません。--noproxy "" は今回のリクエストでプロキシのバイパス設定を空にします。結果はノード、ルール、DNS、接続先サイトの状態にも左右されます。

  • すぐに接続拒否になる:新しいポートで待ち受けているか、アドレスが正しいか、カーネルが終了していないかを確認します。
  • ローカルの入口には接続できるが、リクエストがタイムアウトする:カーネルのログでノードへの接続、適用されたルール、DNSエラーを確認します。
  • 明示的なプロキシリクエストは成功するが、ブラウザーでは失敗する:ブラウザー独自のプロキシ設定、古いシステムプロキシのポート、拡張機能の設定を重点的に確認します。
  • コマンドラインのリクエストは成功するが、想定したノードを経由していない:適用されたルールと選択中のポリシーを確認します。リクエストの成功だけでは、通信がプロキシノードを経由したとは限りません。

最後に再起動とサブスクリプション更新を確認

クライアントを終了して再起動し、引き続き17890で待ち受けていることを確認します。続けて通常どおりサブスクリプションを更新し、ポートが7890に戻っていないか確認してください。再起動後にポートが再び使用中になる場合は、別クライアントのスタートアップ項目やバックグラウンドサービスを調べます。その場しのぎで毎回ポート番号を変えるのは避けてください。

TUNモードも切り分けて考えてください。TUNが処理するのはシステムのネットワーク通信であり、アプリの通信が必ずmixed-portを経由するわけではありません。TUNを有効にしてWebページが開いても、古いシステムプロキシのポートが修正された証拠にはなりません。クライアントによっては、混合入口の競合により一部機能の起動に失敗することもあります。完了を確認する際は、ログ、ローカルの待ち受け、リクエストの経路をそれぞれ確認してください。