まずは運用方法を選ぶ:サーバーはコア、デスクトップは必要に応じてGUIクライアント

LinuxでClashを使うのに、必ずしもデスクトップ環境は必要ありません。mihomoはClashの設定形式に対応し、プロトコルやルール機能を拡張したコアです。以前はClash Metaという名称で知られていました。設定の読み込みやプロキシポートの待ち受け、通信の処理を担います。サブスクリプション管理画面やトレイアイコン、切り替えパネルは、通常GUIクライアントが提供します。

この記事では「mihomo単体のバイナリ+システムレベルのsystemdサービス」で運用します。SSH接続するサーバーや開発機、プロキシを常時稼働させたいデスクトップ環境に適した方法です。設定ファイルは/etc/mihomo/config.yaml、実行データは/var/lib/mihomoに配置し、HTTP/SOCKS混合ポートには7890を使用します。

  • デスクトップ環境のないサーバー:この記事の方法でコマンドとログから管理できます。デスクトップ環境をインストールする必要はありません。
  • 普段使いのデスクトップPC:プロキシノードの切り替えやルール編集を頻繁に行う場合は、内蔵コアを管理できるGUIクライアントを選ぶと便利です。
  • すでにクライアントを使用している場合:まず7890番ポートで待ち受けていないか確認してください。2つのコアが同じアドレスとポートを同時に使用することはできません。

システムのアーキテクチャを確認してmihomoバイナリをインストール

1. systemdとCPUアーキテクチャを確認する

ps -p 1 -o comm=
uname -m
command -v curl
command -v gzip

最初のコマンドでsystemdと表示されることを確認してください。コンテナや軽量システム、systemdが有効になっていない環境では、以降のsystemctlコマンドをそのまま使用できません。環境に合ったプロセス管理方法に置き換えてください。

アーキテクチャの出力リリースアセットの選び方注意点
x86_64Linux amd64では、まずv1互換のアセットを選択v1、v2、v3はCPU命令セットの互換レベルを表し、クライアントのバージョン番号ではありません。
aarch64Linux arm64ARM搭載のクラウドサーバーや、64ビットOSを実行する開発ボードでよく使われます。
armv7lデバイスに合ったLinux armv7アセットを選択ハードウェアとリリースノートを確認してください。arm64用ファイルで代用することはできません。

DebianやUbuntuで必要なツールが不足している場合は、sudo apt update && sudo apt install curl gzip ca-certificatesを実行してください。Fedoraではsudo dnf install curl gzip ca-certificatesを実行します。以降のダウンロードコマンドはBashを使用します。

2. ダウンロードしてインストールする

mihomo公式リリースページを開き、安定版リリースからアーキテクチャに合った.gzバイナリを選び、そのアセットのHTTPSダウンロードリンクをコピーしてください。リリースページのURLやソースコードのアーカイブを、バイナリのリンクとして使わないでください。以下のコマンドではリンクを入力するため、バージョン番号を固定する必要はありません。

mkdir -p "$HOME/mihomo-install"
cd "$HOME/mihomo-install"

read -r -p '公式Linux .gzアセットのHTTPSリンクを貼り付けてください:' download_url
curl --fail --location --proto '=https' \
  --output mihomo.gz "$download_url"
unset download_url

gzip -t mihomo.gz
gzip -dc mihomo.gz > mihomo
chmod 0755 mihomo
./mihomo -v

sudo install -m 0755 mihomo /usr/local/bin/mihomo
/usr/local/bin/mihomo -v

各コマンドを実行し、成功を確認してから次に進んでください。-vの出力でコアのバージョンとアーキテクチャを確認できます。Exec format errorが表示された場合は、通常アーキテクチャの選択ミスです。Illegal instructionが表示された場合はCPU命令セットの要件を確認し、amd64デバイスでは互換性の高い(要求の低い)アセットを選び直してください。

サーバーからリリースサイトにアクセスできない場合は、作業用PCでファイルをダウンロードし、mihomo.gzという名前で保存してから、SFTPでサーバーのインストール先にアップロードしてください。その後、gzip -tから作業を再開できます。ダウンロードのためにTLS証明書の検証を一時的に無効にしないでください。

実行用アカウントを作成し、最小構成で待ち受けを確認する

通常の7890番プロキシポートを使うだけなら、コアをrootで実行する必要はありません。専用のシステムアカウントを作り、設定ファイルと書き込み可能なデータを分けることで、誤操作の影響を抑えられます。ここでは、一般的なディストリビューションにあるuseraddを使います。アカウントがすでにある場合は、重複して作成せず、まずid mihomoで確認してください。

sudo useradd --system --user-group \
  --home-dir /var/lib/mihomo \
  --shell /usr/sbin/nologin mihomo

sudo install -d -o root -g mihomo -m 0750 /etc/mihomo
sudo install -d -o mihomo -g mihomo -m 0750 /var/lib/mihomo

sudo tee /etc/mihomo/config.yaml > /dev/null <<'YAML'
mixed-port: 7890
allow-lan: false
bind-address: 127.0.0.1
mode: rule
log-level: info
ipv6: false

rules:
  - MATCH,DIRECT
YAML

sudo chown root:mihomo /etc/mihomo/config.yaml
sudo chmod 0640 /etc/mihomo/config.yaml

sudo -u mihomo /usr/local/bin/mihomo -t \
  -d /var/lib/mihomo \
  -f /etc/mihomo/config.yaml

-fで読み込むファイルを明示し、-dでコアの実行データディレクトリを指定します。相対パスで指定されたデータファイル、キャッシュ、providerファイルは、このディレクトリを基準に確認してください。コアが常に現在のターミナルのディレクトリから設定を読み込むとは限りません。設定テストで多くの構文エラーや参照先の問題を見つけられますが、実際のノード接続テストの代わりにはなりません。

systemdサービスを作成し、起動時に自動起動するよう設定

サービスファイルでは絶対パスを使用し、実行アカウントを固定します。以下の保護設定は、ローカルの明示的なプロキシ運用に適しています。コアによるデータディレクトリへの書き込みを許可しつつ、システムディレクトリを自由に変更できないようにします。

sudo tee /etc/systemd/system/mihomo.service > /dev/null <<'UNIT'
[Unit]
Description=mihomo local proxy service
Wants=network-online.target
After=network-online.target

[Service]
Type=simple
User=mihomo
Group=mihomo
WorkingDirectory=/var/lib/mihomo
ExecStartPre=/usr/local/bin/mihomo -t -d /var/lib/mihomo -f /etc/mihomo/config.yaml
ExecStart=/usr/local/bin/mihomo -d /var/lib/mihomo -f /etc/mihomo/config.yaml
Restart=on-failure
RestartSec=5s
UMask=0027
NoNewPrivileges=true
PrivateTmp=true
ProtectHome=true
ProtectSystem=strict
ReadWritePaths=/var/lib/mihomo

[Install]
WantedBy=multi-user.target
UNIT

sudo systemctl daemon-reload
sudo systemctl enable --now mihomo.service
systemctl status mihomo.service --no-pager
sudo journalctl -u mihomo.service -n 80 --no-pager
sudo ss -lntp 'sport = :7890'

正常に動作していれば、サービスの状態はactive (running)となり、7890番ポートは127.0.0.1で待ち受けます。enableは起動時の自動起動を設定し、--nowを付けると同時にサービスを起動します。network-online.targetで実際に待機するかどうかは、ディストリビューションのネットワーク管理機能やwait-onlineサービスに依存します。外部サイトへの接続が保証されるわけではありません。

  • 設定を変更した後:先ほどのmihomo -tを実行し、問題がなければsudo systemctl restart mihomoを実行してください。
  • サービスファイルを変更した後:まずsudo systemctl daemon-reloadを実行し、その後サービスを再起動してください。
  • ログをリアルタイムで確認:sudo journalctl -u mihomo -fを実行します。Ctrl+Cを押すとログ表示が終了しますが、サービスは停止しません。
  • 停止して自動起動を無効化:sudo systemctl disable --now mihomoを実行してください。

この記事のサービスにはExecReloadを設定していません。そのため、systemctl reload mihomoを一般的な設定反映コマンドとして使わないでください。再起動すると、このプロセスを経由する既存の通信が一時的に切断されます。リモート作業では更新のタイミングに注意してください。

サブスクリプションを取り込む前に、完全な設定ファイルとノード一覧を区別する

「サブスクリプションURL」が常に同じ形式のデータを返すとは限りません。Clash/mihomoの完全な設定ファイルには、通常proxiesまたはproxy-providers、proxy-groups、rulesが含まれます。ノードだけのprovider YAML、Base64形式のノード一覧、単一の共有リンクは、この記事で使うメイン設定ファイルとしてそのまま利用できません。

完全な設定ファイルを安全に置き換える

サービスが完全なmihomo設定を提供している場合は、まず一時ファイルにダウンロードし、内容を確認してからテストしてください。以下は対話型BashでサブスクリプションURLの入力を非表示にし、トークン付きURLがコマンド履歴に残らないようにします。一時ファイルは終了時に削除されます。ただし、サーバーのアクセスログやローカルの高権限ユーザーから情報が見える可能性はあります。サブスクリプションURLを公開しないでください。

(
  umask 077
  tmp=$(mktemp) || exit 1
  trap 'rm -f "$tmp"' EXIT

  read -r -s -p '完全な設定ファイルのサブスクリプションURLを入力してください:' sub_url
  printf '\n'
  curl --fail --location --proto '=https' \
    --output "$tmp" "$sub_url" || exit 1
  unset sub_url

  sudo install -o root -g mihomo -m 0640 \
    "$tmp" /etc/mihomo/config.next.yaml || exit 1
  sudoedit /etc/mihomo/config.next.yaml

  sudo -u mihomo /usr/local/bin/mihomo -t \
    -d /var/lib/mihomo \
    -f /etc/mihomo/config.next.yaml || exit 1

  sudo cp -p /etc/mihomo/config.yaml /etc/mihomo/config.previous.yaml || exit 1
  sudo mv /etc/mihomo/config.next.yaml /etc/mihomo/config.yaml || exit 1
  sudo systemctl restart mihomo
)

エディターでmixed-port: 7890、allow-lan: false、bind-address: 127.0.0.1を確認してください。外部向けのコントロールインターフェース、DNSの待ち受け、TUNの有効化、ローカルファイルのパスも確認します。この構成では外部向けコントロールインターフェースやDNSの待ち受けは不要で、TUNも使用しません。不要な設定を削除または無効にしてからテストしてください。

ルールが参照するポリシーグループが実在し、グループ内のノードも存在することを確認してください。ルールデータベースやproviderファイルのダウンロードに失敗した場合は、ログに記録されたURLとエラーを確認します。YAMLを解析できただけで、サブスクリプションが利用可能だと判断しないでください。設定がユーザーのホームディレクトリ内のファイルを必要とする場合、この記事のサービスではProtectHome=trueによりアクセスできません。必要なファイルをデータディレクトリに移し、パスを修正してください。

ノードproviderと自動更新の範囲

proxy-providersでは、各providerのurl、path、intervalを使ってノードを更新できます。たとえばinterval: 3600は3600秒間隔を意味します。更新されるのは該当providerであり、メイン設定内のルールやポリシーグループがすべて自動で置き換わるわけではありません。providerの保存先に相対パスを指定する場合は、書き込み可能なデータディレクトリ内にしてください。

完全なメイン設定を定期的に更新する場合は、ダウンロード、構文テスト、バックアップ、置き換え、失敗時のロールバックを含む手順を別途設計し、systemd timerで実行してください。使用中のconfig.yamlを、定期ダウンロードのコマンドで直接上書きしないでください。サブスクリプションの取得に失敗したときは、空のファイルで再起動するより、前回の正常な設定を残すほうが安全です。

ターミナルのプロキシ環境変数を設定し、HTTPとSOCKSを個別にテスト

systemdサービスが起動しただけでは、コアが動作していることしか確認できません。すべてのターミナルアプリが自動的にプロキシを使うわけではありません。まず明示的なオプションを使ってテストし、環境変数による影響を除外してください。以下では接続確認の例として公開サイトにリクエストしますが、実測結果ではありません。所要時間や接続元は、ネットワーク、ルール、ノードによって異なります。

curl --noproxy "" --proxy http://127.0.0.1:7890 \
  --connect-timeout 10 --max-time 30 \
  -I https://www.kernel.org/

curl --noproxy "" --proxy socks5h://127.0.0.1:7890 \
  --connect-timeout 10 --max-time 30 \
  -I https://www.kernel.org/

socks5hでは、接続先ドメインの名前解決をcurlからSOCKSプロキシに任せます。socks5では通常、アプリ側で先に名前解決します。HTTPプロキシでHTTPSサイトにアクセスする場合は、通常CONNECTトンネルを使います。そのため、プロキシのアドレスはhttp://127.0.0.1:7890とし、プロキシの入口をHTTPSに変更する必要はありません。

現在のターミナルだけでプロキシを有効にする

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

curl --connect-timeout 10 --max-time 30 -I https://www.kernel.org/

環境変数が渡されるのは、現在のシェルから後で起動する子プロセスだけです。すでに起動しているアプリには反映されず、ほかのsystemdサービスにも自動では適用されません。環境変数の大文字・小文字や優先順位の扱いはアプリによって異なります。curlでHTTPプロキシを使う場合は、小文字のhttp_proxyを設定してください。設定を長期間有効にするには、現在のユーザーの~/.bashrcなど、使用中のシェル設定ファイルに追記できます。ただし、プロキシサービスの停止中は関連コマンドも失敗する可能性があります。

sudoでは、プロキシ環境変数がデフォルトで引き継がれないことがよくあります。一般ユーザーでテストに成功しても、すべての管理コマンドにプロキシが設定されたとは限りません。別のsystemdサービスでプロキシを使う場合は、そのサービスのdrop-inにEnvironment=を設定し、アプリが対象の環境変数に対応していることも確認してください。

プロキシ環境変数を解除して直接接続に戻す

unset http_proxy https_proxy all_proxy no_proxy
unset HTTP_PROXY HTTPS_PROXY ALL_PROXY NO_PROXY

git config --global --get http.proxy

Gitには、独立したグローバルプロキシ設定がある場合もあります。最後のコマンドで設定を確認できます。以前の設定が不要だと確認できた場合に限り、git config --global --unset http.proxyを実行してください。環境変数を消しても、アプリが独自に保存したプロキシ設定は削除されません。

サービスは動作中なのに通信できない場合:4つの層で確認

  1. プロセス:systemctl status mihomoを実行します。再起動を繰り返す場合は、「再起動回数の上限に達した」という最後の行だけでなく、最初に終了する直前のエラーをjournalctlで確認してください。
  2. 待ち受け:sudo ss -lntp 'sport = :7890'を実行します。待ち受けがない場合は、起動失敗またはポート設定の違いが考えられます。address already in useと表示されたら、別のクライアントや手動で起動したコアがポートを使用していないか確認してください。
  3. プロキシ:--proxyを指定したcurlリクエストでテストします。接続を拒否された場合はローカルポートを確認し、ハンドシェイクがタイムアウトする場合はノード、サーバーの外向き通信制限、プロトコルの互換性を確認してください。
  4. ルール:ログで適用されたルールと選択されたポリシーを確認します。HTTPリクエストが成功しても、リクエストが完了したことしか分かりません。MATCH,DIRECTのままなら、プロキシノードが動作している証拠にはなりません。

設定テストでpermission deniedが表示された場合は、/etc/mihomoのディレクトリに実行権限があるか、ファイルの所属グループ、providerの保存先が読み取り専用ではないかを確認してください。systemdでstart-limit-hitが報告された場合は、まず原因を修正してからsudo systemctl reset-failed mihomoとsudo systemctl start mihomoを実行します。

リモートのSSHセッションで使う127.0.0.1はサーバー自身を指し、作業用PCではありません。この記事の構成では、クラウドのセキュリティグループで7890番ポートを開放する必要はありません。作業用PCから一時的にサーバーのプロキシを使う場合は、PC上でssh -N -L 17890:127.0.0.1:7890 サーバーのログイン先を実行してください。最後の引数は、普段使っているSSHの接続先に置き換えます。その後、PCのアプリでプロキシを127.0.0.1:17890に設定します。

デスクトップ環境とTUN:2つの通信制御方式を併用しない

GNOMEデスクトップでは、「設定」→「ネットワーク」→「ネットワークプロキシ」を開き、手動設定を選択します。HTTPとHTTPSのプロキシホストを127.0.0.1、ポートを7890に設定してください。メニュー名はディストリビューションによって多少異なる場合があります。デスクトップのプロキシ設定は、その設定に従うアプリにのみ適用されます。ターミナル、ゲーム、バックグラウンドサービスもプロキシを使うとは限りません。

サブスクリプションやノードをGUIクライアントで管理する場合は、まずこの記事の独立したサービスを停止してから、クライアント内蔵のコアを起動することをおすすめします。ポート、設定ファイルの参照元、ログの確認先をそれぞれ1つにでき、問題の切り分けが容易になります。「GUIクライアントのシステムプロキシ設定」と「systemdによるコアの起動」は別の機能であり、互いに代用できません。

TUNを検討するタイミング

  • 対象のアプリが明示的なプロキシに対応していない場合や、より広範囲の通信を経由させる必要がある場合に、TUNの導入を検討してください。
  • まず/dev/net/tunが存在することと、コンテナまたはホスト側で仮想ネットワークインターフェースを作成できることを確認してください。
  • この記事の非特権サービスには、ネットワークインターフェースやルートの設定に必要な権限を付与していません。tun.enableを追加するだけでは動作しません。
  • Linux capabilitiesを使う場合は、実際の機能に応じてCAP_NET_ADMINなどの権限を検討し、systemdの制限設定もあわせて確認してください。保護設定をすべて無効にするのは避けてください。
  • 自動ルーティング、ポリシールーティング、DNSのリダイレクトは、まとめて動作確認してください。リモートサーバーのネットワークを変更する前に、SSH接続をもう1つ開き、クラウドの管理コンソールにもアクセスできる状態にしておきましょう。

導入完了の目安は、設定テストが成功し、サービスが起動時に自動起動し、7890番ポートがローカルでのみ待ち受け、明示的なプロキシリクエストが成功し、ログから通信が想定したポリシーに一致したことを確認できる状態です。まずこの流れを完成させてから自動更新やTUNを追加すれば、問題を特定しやすくなります。