Featured image of post いわゆる「クライアント」を捨てて、Mihomo カーネルを直接使おう

いわゆる「クライアント」を捨てて、Mihomo カーネルを直接使おう

出来の悪い Mihomo クライアントに頼るくらいなら、自分で設定ファイルを作成・管理し、それをカーネルに直接渡して起動する方がはるかにクリーンで安定、かつコントロールしやすくなります。「ブラックボックス」のようなクライアントに依存せず、自由度の高い運用を目指しましょう。

Clash/Mihomo を使い始めた当初、ほとんどの方と同じく、カーネルをラップした GUI クライアントを使っていました。その方が手軽だからです。実際、Mihomo クライアント同士には大きな違いはありません。どれも同じカーネルを使い、主に使いやすい UI の提供や設定ファイル・サブスクリプションの管理、GUI ベースのシステムプロキシ設定を担っています。その意味では、クライアント選びの重要なポイントは「オーバーライド機能」(設定の上書き機能)がどれだけ出来が良いかだと考えています。

どの Mihomo クライアントも、サブスクリプションやダウンロードした設定ファイルを一連の「オーバーライド」処理(例:mixed-portの変更、sniffer設定の追加など)にかけ、最終的に Mihomo カーネルを起動する形です。

しかし、この一番大切な部分をちゃんとこなせていないクライアントも多々見かけます。例えば ShellCrash は、上書き機能にバグが多く、実装が雑な印象です。設定の上書きや編集すらまともにできないクライアントは、正直使う価値がありません。

出来の悪いひどいMihomo クライアントに頼るくらいなら、自分で設定ファイルを作成してカーネルに直接渡して起動する—そうした方がブラックボックスなクライアントに依存しない、クリーン・安定・高いコントロール性の運用が実現できます。

必要な予備知識

  • 基本的な Linux 操作
  • nano など CLI エディタが使えること
  • Substore 環境が用意できていればより便利(任意)

Mihomo カーネルのインストール

Debian 系の場合は、プリビルドの.debパッケージが利用できますが、その他の systemd 対応ディストリビューションでは、ビルド済みバイナリをダウンロードし、mihomoにリネームして/usr/local/binに配置します。

1
curl -o /usr/local/bin/mihomo <ダウンロードリンク>

次に、/etc/systemd/system/mihomo.serviceを新規作成します。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
[Unit]
Description=mihomo Daemon, Another Clash Kernel.
After=network.target NetworkManager.service systemd-networkd.service iwd.service

[Service]
Type=simple
LimitNPROC=500
LimitNOFILE=1000000
CapabilityBoundingSet=CAP_NET_ADMIN CAP_NET_RAW CAP_NET_BIND_SERVICE CAP_SYS_TIME CAP_SYS_PTRACE CAP_DAC_READ_SEARCH CAP_DAC_OVERRIDE
AmbientCapabilities=CAP_NET_ADMIN CAP_NET_RAW CAP_NET_BIND_SERVICE CAP_SYS_TIME CAP_SYS_PTRACE CAP_DAC_READ_SEARCH CAP_DAC_OVERRIDE
Restart=always
ExecStartPre=/usr/bin/sleep 1s
ExecStart=/usr/local/bin/mihomo -d /etc/mihomo
ExecReload=/bin/kill -HUP $MAINPID

[Install]
WantedBy=multi-user.target

次にsystemctl daemon-reloadで systemd をリロードします。この時点では設定ファイルがありませんので、起動できませんが、systemctl enable mihomoを先に実行して自動起動設定しておくと後が楽です。

設定ファイル

カーネル起動時には/etc/mihomo/config.yamlが読み込まれます。クライアントというブラックボックスが無いため、好みに合わせて自在にカスタマイズ可能です。一部のプロバイダ(いわゆる「空港」)は完全な設定ファイルを配布しているので、curl等で直接ダウンロードすれば OK です。

サブスクリプションの管理には、私は Substore を使っています。詳しくは以前の「最速 Substore サブスクリプション管理ガイド」を参考にしてください。内核単体起動を実現するため、現在は私の Substore JS オーバーライドfullパラメータも追加済みで、全ポート設定・共通遅延・外部コントローラ設定なども含めた「すぐ使える」完全な設定ファイルが生成できます。

Substore の設定が完了したら、設定ファイルをダウンロードしてカーネルを起動しましょう。

1
2
curl -o /etc/mihomo/config.yaml <設定ファイル配布リンク>
systemctl start mihomo

独自の上書き(オーバーライド)

私のルールだけでは満足できませんか?でも大丈夫、ご自身のニーズに合わせて上書きを追加しましょう。

私は色々なオーバーライドルールを試してきましたが、最終的には自作しています。99%のケースはカバーできますが、特定のプライベート環境(例:サーバのカスタム SSH ポート先へのプロキシ等)などは、市販や公開ルールには抜け漏れが多いものです。このようなプライベートな内容は、GitHub 等で公開したくないでしょうし、そうした場合は自分だけのオーバーライドを追加するのが最善です。

Substore は複数のスクリプト処理を追加できるため、ファイル生成時に好きなだけ追加オーバーライドを加えられます。

1
2
3
4
function main(config) {
  config["rules"].unshift("DOMAIN-SUFFIX,hzdwpx.com,DIRECT");
  return config;
}

注意:rulesをオーバーライドする時は.unshift()で先頭に挿入します。MATCH以降にルールを追加しても、マッチすることは一生ありません。

完全に独自の設定ファイル

私のオーバーライドが好きじゃない?Substore を使いたくない?それでももちろん問題ありません。Mihomo 公式ドキュメントを参照し、最初から自作するのもおすすめです。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
mode: rule
mixed-port: 7890
redir-port: 7892
tproxy-port: 7893
allow-lan: true
log-level: info
ipv6: true
external-controller: 127.0.0.1:8000
# secret: yoursecret
unified-delay: true
routing-mark: 7894
tcp-concurrent: true
disable-keep-alive: true # モバイル機器のバッテリー異常消耗対策として推奨

dns:
  # お好みのDNS設定

sniffer:
  # ドメインスニッファー(ドメイン抽出)の設定内容

geodata-mode: true
geox-url:
  # カスタムGeodataファイルURL

proxy-providers:
  # プロバイダ配布サブスクリプション

rule-providers:
  # 外部ルール

rules:
  # トラフィック分割ルール

proxy-groups:
  # カスタムプロキシグループ

管理パネル

管理パネルは好みによって選べます。ここでは Zashboard を例に紹介します。私は mihomo 標準のexternal-uiでなぜかおかしな挙動があったため、そのまま Docker コンテナで運用しています。管理パネルは単なる Web フロントエンドなので、カーネル API も Web パネルも HTTP 指定で動かせば OK です。もし Web パネル側を HTTPS にしてしまうと、CORS ポリシーによる API 接続エラーが出ますので注意しましょう。

1
2
3
$ mkdir zashboard && cd zashboard
$ nvim compose.yml
$ docker compose up -d

compose.ymlの内容はこちら:

1
2
3
4
5
6
services:
  zashboard:
    image: ghcr.io/zephyruso/zashboard:latest
    ports:
      - "8899:80"
    restart: "unless-stopped"

自動メンテナンス

カーネルが動き出したら、自動でサブスクリプション更新するにはどうしたらいいでしょう?

答えは、シェルスクリプト+ Crontab 一択です。たとえば深夜 3 時に自動更新&mihomo の再起動したいなら、以下のような/etc/mihomo/auto_update.shを作れば OK です。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
#!/bin/bash

# === 設定情報 ===
CONFIG_URL=""
CONFIG_PATH="/etc/mihomo/config.yaml"
BACKUP_DIR="/etc/mihomo"
BACKUP_PREFIX="config.yaml"
MAX_BACKUPS=7
TMP_PATH="/tmp/config.yaml.tmp"
LOG_FILE="/var/log/mihomo_update.log"

# === ログ関数 ===
log() {
    echo "$(date '+%F %T') $1" | tee -a "$LOG_FILE"
}

# === 現在の設定をバックアップ、古いバックアップは自動削除 ===
backup_config() {
    if [ -f "$CONFIG_PATH" ]; then
        backup_file="$BACKUP_DIR/${BACKUP_PREFIX}.$(date '+%Y%m%d_%H%M%S').bak"
        cp "$CONFIG_PATH" "$backup_file"
        log "設定ファイルを $backup_file にバックアップしました"
        # 古いバックアップを $MAX_BACKUPS 個だけ残して削除
        old_backups=$(ls -1t $BACKUP_DIR/${BACKUP_PREFIX}.*.bak 2>/dev/null | tail -n +$(($MAX_BACKUPS+1)))
        for f in $old_backups; do
            rm -f "$f" && log "古いバックアップ $f を削除しました"
        done
    else
        log "設定ファイルが見つかりません、バックアップ不要"
    fi
}

# === 新しい設定ファイルをダウンロード ===
download_config() {
    log "新しい設定ファイルのダウンロード開始..."
    curl -fsSL -o "$TMP_PATH" "$CONFIG_URL"
    if [ $? -ne 0 ]; then
        log "設定ファイルのダウンロードに失敗しました。ネットワークやURLを確認してください"
        return 1
    fi
    # 簡易チェック:ダウンロードファイルが空でないか確認
    if [ ! -s "$TMP_PATH" ]; then
        log "ダウンロードしたファイルが空です、更新中止"
        return 2
    fi
    log "設定ファイルのダウンロード完了"
    return 0
}

# === 設定ファイルの置き換え ===
replace_config() {
    mv "$TMP_PATH" "$CONFIG_PATH"
    log "設定ファイルを更新しました"
}

# === mihomo サービスを再起動 ===
restart_service() {
    systemctl restart mihomo
    if [ $? -eq 0 ]; then
        log "mihomoサービスを再起動しました"
    else
        log "mihomoサービスの再起動に失敗。手動でご確認ください"
    fi
}

main() {
    backup_config

    download_config
    DL_STATUS=$?
    if [ "$DL_STATUS" -ne 0 ]; then
        log "処理終了:設定ファイルは更新されず、旧設定をそのまま保持します"
        exit 1
    fi

    replace_config

    restart_service

    log "=== 更新プロセス完了 ==="
}

main "$@"

crontab -e で以下のタスクを設定すれば、毎日 3 時に自動更新+再起動します。

1
0 3 * * * /etc/mihomo/update_config.sh

ファイアウォール設定

Mihomo カーネルへトラフィックをリダイレクトするファイアウォール設定も、実は全然難しくありません。過去記事「入門から応用まで:Tailscale + ShellCrash でリモート VPN 構築&Great Firewall 回避」で解説した通り、今回は手順だけ簡単に記述します。

筆者の場合はtailscale0インターフェース上の全トラフィックを Mihomo へ流したい状況ですが、ローカル代理の場合も考え方は同じです。単に TCP だけリダイレクトするならiptablesの REDIRECT で十分ですが、UDP や QUIC などすべてのプロトコルをリダイレクトしたい場合は Tproxy が必要です。また、IPv6 対応も忘れずに。

サンプル構成は下記です。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
# カスタムチェインを作成
iptables -t mangle -N MIHOMO

# 必要に応じてローカル宛流量を除外
iptables -t mangle -A MIHOMO -d 127.0.0.1/8 -j RETURN
iptables -t mangle -A MIHOMO -d 100.64.0.0/10 -j RETURN
iptables -t mangle -A MIHOMO -d 192.168.1.0/24 -j RETURN
iptables -t mangle -A MIHOMO -d 172.17.0.0/16 -j RETURN

# UDP / TCP マーク → プロキシへ
iptables -t mangle -A MIHOMO -p tcp -j TPROXY --on-port 7893 --tproxy-mark 233
iptables -t mangle -A MIHOMO -p udp -j TPROXY --on-port 7893 --tproxy-mark 233

# インターフェースからチェインジャンプ
iptables -t mangle -A PREROUTING -i tailscale0 -j MIHOMO

# ルーティングテーブル設定
echo "233 mihomo" | tee -a /etc/iproute2/rt_tables
ip rule add fwmark 233 lookup mihomo
ip route add local 0.0.0.0/0 dev lo table mihomo

# IPv6対応
# チェイン作成
ip6tables -t mangle -N MIHOMO6

# ローカル宛除外
ip6tables -t mangle -A MIHOMO6 -d ::1/128 -j RETURN
ip6tables -t mangle -A MIHOMO6 -d fd7a:115c:a1e0::/48 -j RETURN

# TCP/UDP マーク
ip6tables -t mangle -A MIHOMO6 -i tailscale0 -p tcp -j TPROXY --on-port 7893 --tproxy-mark 233
ip6tables -t mangle -A MIHOMO6 -i tailscale0 -p udp -j TPROXY --on-port 7893 --tproxy-mark 233

# インターフェースチェインジャンプ
ip6tables -t mangle -A PREROUTING -i tailscale0 -j MIHOMO6

# ルーティングテーブル設定
echo "233 mihomo" | tee -a /etc/iproute2/rt_tables
ip -6 rule add fwmark 233 lookup mihomo
ip -6 route add local ::/0 dev lo table mihomo

ほとんどのシステムはデフォルトで iptables ルール等を永続化しません。ルールの永続化については、前述の記事の「ルーティングルールの永続化」「iptables ルールの永続化」を参照してください。

ローカルプロキシ設定例

多くのプロキシソフトや(実際 ShellCrash のデフォ設定も)、REDIRECT を使います。これでたいていのケースは十分です。たとえば

1
2
3
4
5
# IPv4 eth0 トラフィックをリダイレクト
iptables -t nat -A PREROUTING -i eth0 -p tcp -j REDIRECT --to-ports 7892

# IPv6 eth0 トラフィック
ip6tables -t nat -A PREROUTING -i eth0 -p tcp -j REDIRECT --to-ports 7892

7892 は Mihomo 設定のredir-porteth0はリダイレクトしたいインターフェースを指定します。Tproxy より圧倒的にシンプルです。

個人的には、全トラフィックを防火壁で強制キャプチャする使い方は好きではありません。必要な時だけ、環境変数・proxychains・各種ソフトのプロキシ機能で Mihomo に向けて設定する方がスマートです。たとえば Docker のプロキシを通すなら/etc/docker/daemon.jsonを編集すれば OK、わざわざ全体劫持する必要はありません。

1
2
3
4
5
6
7
{
  "proxies": {
    "http-proxy": "http://127.0.0.1:7890",
    "https-proxy": "http://127.0.0.1:7890",
    "no-proxy": "127.0.0.0/8"
  }
}

こんなに手間かけるより、普通にクライアント使えば良くない?

それを聞くか…。答えは「虚無のターミナル遊び」に決まってるでしょ。

本ウェブページの日本語版は、生成系大規模言語モデル(LLM)によって簡体字中国語版の内容を翻訳したものです。その内容は「乱筆」による確認、校正および承認を経ておりません。ご利用の際には、いかなる場合でも本日本語版を簡体字中国語版または英語版と同等と見なさないようご注意ください。
Hugo で構築されています。
テーマ StackJimmy によって設計されています。