OpenWrtのバイパスルーターでmihomoを動かす方法|透過プロキシの設定
OpenWrtのメインルーターとバイパスルーターの役割分担、mihomoの配置とサービス設定、透過プロキシとDNS転送の要点、通信障害時の復旧手順を解説します。
1. ネットワーク構成:まず1台の端末をバイパスルーター経由にする
OpenWrtのバイパスルーターでmihomoを使うには、3つの工程が必要です。端末からバイパスルーターへ通信を送り、ファイアウォールからカーネルへ接続を渡し、カーネルのルールに従って通信先を選びます。mihomoを起動しただけ、あるいはDNSを変更しただけでは、透過プロキシの設定は完了しません。
この記事では、同一サブネットの単一LANポートを使うIPv4テスト環境を例に、OpenWrt 23.05/24.10系列で一般的なfirewall4とnftablesを前提として説明します。記載するアドレスは一貫した設定例です。実行前に、実際のネットワーク構成と照合してください。OpenClashやほかの透過プロキシプラグイン、独自のポリシールーティングを使用中の機器に、これらのルールをそのまま追加しないでください。
| 機器 | アドレスまたは設定 | 役割 |
|---|---|---|
| メインルーター | 192.168.10.1/24 | PPPoE接続、WAN側NAT、DHCPの提供を継続 |
| OpenWrtバイパスルーター | 192.168.10.2/24 | mihomoを実行し、テスト端末からの通信を受け取る |
| バイパスルーターのデフォルトゲートウェイ | 192.168.10.1 | カーネルからノードや直接接続先への通信に使用 |
| テスト端末 | 192.168.10.100/24 | ゲートウェイとDNSをどちらも 192.168.10.2 に設定 |
| バイパスルーターのLANインターフェース | br-lan | 同じLAN内のテスト通信を受け取る |
ゲートウェイとDHCPの役割分担
- OpenWrtの「ネットワーク」→「インターフェース」→「LAN」→「編集」で、固定アドレス、IPv4ゲートウェイ、DNSを設定します。バイパスルーター自身がインターネットに接続できることを確認してください。
- 同じ画面の「DHCPサーバー」→「一般設定」で「このインターフェースを無視」にチェックを入れ、メインルーターとバイパスルーターの両方がアドレスを配布しないようにします。
- まずテスト端末だけ、IPv4ゲートウェイとDNSを変更します。メインルーターのDHCPゲートウェイ設定を、すぐにバイパスルーターのアドレスへ変更しないでください。
- 「ネットワーク」→「ファイアウォール」で、LANゾーンのポリシーを確認します。この記事では、一般的なLAN入力・出力・ゾーン内転送が許可されている環境を想定しています。制限のあるネットワークでは、必要な許可ルールを別途設計してください。
同一サブネットのバイパスルーターでは、直接接続への応答がメインルーターから端末へ直接返り、再びバイパスルーターを経由しない場合があります。この非対称な経路は、接続統計やステートフルファイアウォールの判定に影響します。初回テストではメインルーターの既存のWAN側NATを維持し、「経路を対称にする」目的でLAN全体に安易なマスカレードを追加しないでください。
2. カーネルの配置:バイナリと最小構成を先に確認
mihomoはClash Metaから発展したプロキシカーネルであり、OpenWrtの管理プラグインではありません。カーネルを直接実行する場合、設定ディレクトリ、プロセス監視、サブスクリプション更新、ファイアウォールルールは管理者が保守する必要があります。CPUアーキテクチャに合ったLinuxバイナリを選び、機器の商品名だけで判断しないでください。
ubus call system board
uname -m
df -h /overlay
free -m
mkdir -p /etc/mihomo
chmod 700 /etc/mihomo
chmod 755 /usr/bin/mihomo
/usr/bin/mihomo -v
以下のコマンドは、展開したカーネルを /usr/bin/mihomo に配置済みであることを前提としています。たとえば aarch64 は通常ARM64に対応しますが、ARMv7やMIPSの機器では命令セット、エンディアン、浮動小数点ABIも確認が必要です。Exec format error が発生したら、ファイアウォールを変更するのではなく、まずアーキテクチャを確認してください。バージョンは端末上で実行した mihomo -v の出力を基準とし、後のトラブルシューティングに備えて出力を保存しておきます。
設定ファイル:まずDIRECTで通信経路を確認
以下の内容を /etc/mihomo/config.yaml として保存します。これは接続確認用の最小構成で、プロキシノードを設定していないため、通信はプロキシサーバーへ送られません。まず通信がカーネルに届くことを確認してからノードとルールグループを追加すると、ネットワークの問題とサブスクリプションの問題を切り分けやすくなります。
mixed-port: 7890
tproxy-port: 7893
allow-lan: true
bind-address: 192.168.10.2
mode: rule
log-level: info
ipv6: false
dns:
enable: true
listen: 0.0.0.0:1053
ipv6: false
enhanced-mode: redir-host
nameserver:
- udp://223.5.5.5:53
- udp://119.29.29.29:53
rules:
- MATCH,DIRECT
7890 はHTTP/SOCKS混合プロキシのポート、7893 はTPROXYのポート、1053 はmihomoのDNS待受ポートです。初回設定でFake-IPアドレスプールや追加ルートを同時に導入しないよう、ここでは redir-host を使います。上流DNSは例として指定した直接接続用のリゾルバーであり、暗号化DNSではありません。
chmod 600 /etc/mihomo/config.yaml
/usr/bin/mihomo -t -d /etc/mihomo -f /etc/mihomo/config.yaml
通信を受け渡す前に、必ず設定ファイルをテストしてください。この記事の基本構成にはGEOIP、GEOSITE、ルールセットへの依存関係はありません。サブスクリプションの設定に置き換える場合は、必要なデータファイル、ルールプロバイダーのダウンロード先、ルールグループの参照先も確認してください。デスクトップクライアント向けのサブスクリプションには、ルーターに適さないDNS、TUN、コントロールインターフェースの設定が含まれることがあります。
3. プロセス監視:procdでmihomoを起動
OpenWrtではprocdがサービスを管理します。SSHセッションに長時間プロセスをぶら下げたり、cronから毎分起動したりしないでください。以下のスクリプトは起動、異常終了後の再起動、ログ連携を行いますが、透過プロキシのルールは設定しません。
以下の内容を /etc/init.d/mihomo として保存します。
#!/bin/sh /etc/rc.common
START=95
STOP=10
USE_PROCD=1
start_service() {
/usr/bin/mihomo -t -d /etc/mihomo \
-f /etc/mihomo/config.yaml || return 1
procd_open_instance
procd_set_param command /usr/bin/mihomo \
-d /etc/mihomo -f /etc/mihomo/config.yaml
procd_set_param respawn 3600 5 5
procd_set_param stdout 1
procd_set_param stderr 1
procd_set_param file /etc/mihomo/config.yaml
procd_close_instance
}
chmod 755 /etc/init.d/mihomo
/etc/init.d/mihomo enable
/etc/init.d/mihomo start
logread -e mihomo
ss -lnptu | grep -E ':(7890|7893|1053)\b'
システムに ss がない場合は、netstat -lnptu で待受状態を確認できます。ポート競合のログが出たら、古いプロキシプロセス、重複サービス、DNSプラグインを先に調べてください。防火壁の設定変更と同時にポートだけを変更し、設定の同期を忘れないようにします。
4. 透過プロキシ:TPROXY・ポリシールーティング・ファイアウォールの役割
LinuxのTPROXYはTCPとUDPを受け取り、元の宛先アドレスを保持できます。動作には、nftablesで接続を選別し、ポリシールーティングでマーク付きパケットをローカルへ送り、mihomoの透過プロキシ用待受で接続を受け取る、という3つの要素が必要です。tproxy-port を設定しただけで、前の2つがなければ端末の通信は自動的にカーネルへ届きません。
以下の例は 192.168.10.100 のみを対象とし、競合がないことを確認したテスト環境でのみ使用します。実行前に ip -4 rule show、ip -4 route show table 100、nft list ruleset を実行し、ルーティングテーブル100、優先度100のルール、マーク 0x1 がほかのサービスで使われていないことを確認してください。マルチWAN、VPN、ほかのプロキシがこれらをすでに使用している場合があります。
カーネルモジュールと転送設定
使用中のファームウェアに対応したパッケージソースから、nftablesのTPROXYをサポートするモジュールをインストールします。opkgを使うファームウェアでは、通常 kmod-nft-tproxy を確認できます。パッケージは実行中のカーネルバージョンと一致している必要があります。Operation not supported が表示される、またはTPROXYの式が見つからない場合は、まずモジュールの問題を解消してください。
sysctl -w net.ipv4.ip_forward=1
sysctl -w net.ipv4.conf.all.send_redirects=0
sysctl -w net.ipv4.conf.br-lan.send_redirects=0
ip -4 rule add priority 100 fwmark 0x1/0x1 lookup 100
ip -4 route add local 0.0.0.0/0 dev lo table 100
ICMP Redirectの送信を無効にすると、バイパスルーターが端末に同一サブネットのメインルーターへ切り替えるよう通知するのを防げます。インターフェースごとの設定も忘れずに確認してください。厳格な逆方向パスフィルタリングが有効な場合は、net.ipv4.conf.all.rp_filter と net.ipv4.conf.br-lan.rp_filter も確認します。ポリシールーティング環境では、厳格モードが正当なパケットを破棄することがあるため、ネットワークのセキュリティ要件に応じてlooseモードへの変更または無効化を検討してください。
送信元アドレスを1つだけ対象にするnftablesルール
以下の内容を /etc/mihomo/test-tproxy.nft として保存します。これは独立したテスト用テーブルです。firewall4のテーブル内includeファイルにそのまま貼り付けないでください。初回の読み込み前に構文を確認してから適用し、同名のテーブルがすでにある場合は重複して読み込まないでください。
table inet mihomo_test {
chain ingress_proxy {
type filter hook prerouting priority mangle; policy accept;
iifname != "br-lan" return
ip saddr != 192.168.10.100 return
meta l4proto { tcp, udp } th dport 53 return
ip daddr {
0.0.0.0/8,
10.0.0.0/8,
100.64.0.0/10,
127.0.0.0/8,
169.254.0.0/16,
172.16.0.0/12,
192.168.0.0/16,
224.0.0.0/4,
240.0.0.0/4
} return
meta l4proto { tcp, udp } counter \
tproxy to :7893 meta mark set 0x1 accept
}
chain ingress_dns {
type nat hook prerouting priority dstnat; policy accept;
iifname "br-lan" ip saddr 192.168.10.100 \
meta l4proto { tcp, udp } th dport 53 \
counter redirect to :1053
}
}
nft -c -f /etc/mihomo/test-tproxy.nft
nft -f /etc/mihomo/test-tproxy.nft
nft list table inet mihomo_test
DNSの53番ポートへの通信は、まず透過プロキシのチェーンから返し、その後ろのNATチェーンで1053番ポートへリダイレクトします。これにより通常のDNS問い合わせが先にTPROXYへ渡るのを防げます。プライベートアドレスとマルチキャストアドレスは直接通し、ルーターの管理やLAN機器へのアクセスなど基本機能を維持します。組織内で公開アドレス帯や専用ルートを使っている場合は、それらも除外対象に加えてください。
nftablesのテストチェーンで使う accept は、後続のfirewall4のベースチェーンをスキップしません。TPROXYのパケットは元の宛先ポートを保持するため、「宛先ポート7893を許可」するだけでは入力ポリシーの代わりになりません。この記事ではLAN入力が許可された環境を想定しています。LAN入力を拒否する設定では、firewall4でLANを送信元とする対象マーク付きのTCP/UDPパケットに限定した入力許可ルールを作り、DNSの1053番ポートも別途許可してください。
5. DNS転送:通常のDNS・暗号化DNS・名前解決ループを区別する
端末のゲートウェイとDNSをどちらもバイパスルーターに向けても、すべての名前解決がmihomoを通るとは限りません。上記のルールが対象とするのは、バイパスルーターを通るTCP/UDPの53番ポートへの通信です。ブラウザーのセキュアDNS、OSのプライベートDNS、アプリ内蔵のDoHは、443番や853番ポートを使って別のリゾルバーへ接続することがあります。
- 基本テスト:テスト端末の暗号化DNSを一時的に無効にし、通常のDNS経路を明確に確認してから、機能を元に戻してポリシーを検証します。
- ポートの使い分け:OpenWrtのdnsmasqは53番ポートを使い、mihomoは1053番ポートを使います。同じ待受アドレスとポートを2つのプロセスで取り合わないようにしてください。
- 上流DNSのループ:mihomoの上流DNSをdnsmasqに向け、さらにdnsmasqの上流をmihomoに向ける設定は避けてください。名前解決のループやタイムアウトが発生します。
- ノードのホスト名:プロキシノードを追加したら、ノードサーバーのホスト名がどの経路で解決されるか確認します。
proxy-server-nameserverを使うと、ノードのホスト名を解決するリゾルバーを個別に指定でき、プロキシ接続前の名前解決がそのプロキシに依存するのを防げます。 - LAN内のホスト名:DHCPのホスト名を名前解決する必要がある場合は、内部ドメイン用の専用ルールを設定し、前述のループが発生しないことを確認してください。
この例では、テスト端末の送信元アドレスだけをDNS転送の対象にしているため、バイパスルーター自身が送信するDNSは同じルールで再度捕捉されません。対象を全送信元へ広げる場合は、カーネルの上流DNS、ノード接続、ルーター自身の通信に対する除外条件を見直してください。送信元アドレスの制限を単純に削除してはいけません。
TUNモードを単に追加で有効にすればよいわけではない理由
mihomoはTUNにも対応していますが、TUNを使うにはカーネル側のデバイス対応に加え、ルーティングとDNS転送の設計が必要です。auto-route や auto-redirect などの設定は、既存のルートやnftablesルールを変更することがあります。この記事の手動TPROXY構成とそのまま併用しないでください。単一LANポートのバイパスルーターでは、ルーター自身の通信だけでなく、転送通信も実際にTUNへ入ることを確認する必要があります。
TUNを使う場合は、まずこの記事のテストテーブルとポリシールーティングを削除し、使用中のmihomoバージョンに合ったTUN設定を改めて適用してください。どちらも必要な接続をカーネルへ渡す目的は同じです。複数の入口を同時に有効にするより、経路を1つに明確化したほうがトラブルシューティングしやすくなります。
6. 動作確認の順序:直接接続からプロキシルールまで
まずバイパスルーター自身がインターネットに接続できることを確認し、その後で端末の通信を検証します。基本構成の最終ルールは MATCH,DIRECT なので、外部IPアドレスが通常の直接接続と同じでも正常です。それだけで通信がカーネルに届いていないとは判断できません。カウンターとカーネルログをあわせて確認してください。
- 設定ファイルの確認:
mihomo -tを実行し、YAMLのインデントエラー、未定義のルールグループ、ルールプロバイダーの読み込み失敗がないことを確認します。 - 明示的プロキシの確認:テスト端末で下のcurlコマンドを実行します。この手順で確認できるのは7890番ポートのプロキシであり、透過プロキシの動作ではありません。
- DNSの確認:
192.168.10.2にドメイン名を問い合わせ、DNSのNATカウンターが増えるか確認します。NATチェーンのカウンターが示すのは新規接続のマッチ数であり、DNSパケットの総数ではありません。 - 透過接続の確認:端末の明示的プロキシを無効にして公開Webサイトへアクセスし、TPROXYカウンターと
logread -e mihomoの接続ログを確認します。 - プロキシ経由の確認:有効なノードをインポートし、実際のルールグループを設定して最終ルールを置き換えた後、同じリクエストを再実行します。ログに表示される送信先が想定どおりであることを確認し、大容量ファイル、動画、UDPを使うアプリもテストしてください。
# テスト端末で実行
curl -I --proxy http://192.168.10.2:7890 https://example.com/
nslookup example.com 192.168.10.2
curl -I --noproxy '*' https://example.com/
# バイパスルーターで実行
ip -4 rule show
ip -4 route show table 100
nft list table inet mihomo_test
logread -e mihomo
ブラウザーは正常でもゲームに問題がある場合、UDPの転送漏れ、ノードがUDPに非対応、アプリが別のアドレスファミリーを使っている、といった原因が考えられます。小さなWebページは表示できても大きな通信が止まる場合は、MTU、Path MTU Discovery、回線のパケットロスを調べてください。これらをすべてDNSの問題と決めつけたり、ログなしにカーネルパラメーターを変更したりしないでください。
テスト中は「ネットワーク」→「ファイアウォール」でソフトウェア/ハードウェアフローオフロードを一時的に無効にすると、高速転送経路が検証に与える影響を抑えられます。設定が安定したら、項目ごとに元へ戻して再テストしてください。この記事では実測スループットを示していません。機器のCPU、ノードのプロトコル、暗号化方式、回線速度で結果が変わるため、同一条件で複数回測定した値を基準にしてください。
7. 通信障害時の復旧:ゲートウェイを戻してから転送ルールを解除
ネットワーク全体のDHCPゲートウェイをバイパスルーターに変更した後で電源が落ちても、クライアントが自動的にメインルーターへ切り替わることはありません。procdで対処できるのはプロセスの異常終了であり、停電、誤ったルール、上流回線の切断は復旧できません。適用範囲を広げる前に、復旧手順を準備してください。
1台の端末だけをテストした場合の復旧手順
- テスト端末のIPv4ゲートウェイとDNSを
192.168.10.1に戻すか、メインルーターのDHCPから自動取得する設定に戻します。 - バイパスルーターでテスト用nftablesテーブルを削除し、接続の捕捉を停止します。
- 今回追加したポリシールートとローカルルートだけを削除してから、カーネルを停止します。
- ネットワークに再接続するか、端末のDNSキャッシュを消去し、直接接続が復旧したことを確認します。確立済みのプロキシ接続は再接続が必要です。
nft delete table inet mihomo_test
ip -4 rule del priority 100 fwmark 0x1/0x1 lookup 100
ip -4 route del local 0.0.0.0/0 dev lo table 100
/etc/init.d/mihomo stop
/etc/init.d/mihomo disable
削除コマンドは、対象がこの記事のテストで作成したものだと確認できた場合にのみ実行してください。nft flush ruleset で機器全体のルールを消去したり、ポリシールーティングテーブル全体を空にしたりしないでください。firewall4、VPN、ほかのネットワークサービスに影響します。
ネットワーク全体へ展開する前のメンテナンス項目
- メインルーターの既存のDHCPゲートウェイとDNS設定を保存し、リースの更新時刻を記録します。設定を戻しても、リース期限前の端末は引き続きバイパスルーターを使う場合があります。
- 固定アドレスの保守用PCやメインルーターの管理アドレスなど、バイパスルーターに依存しない管理経路を確保します。
- サブスクリプションの更新は「一時ファイルへダウンロード → 設定をテスト → 差し替え → 再起動」の順に行い、失敗した場合に備えて直前の正常な設定を残します。
- ストレージの空き容量とログ量を確認し、debugを長時間有効にして限られたフラッシュ容量を使い切らないようにします。
- カーネルの停止とバイパスルーターの電源断を実際に試し、正常起動だけでなく、クライアント側の復旧手順も検証します。
安定稼働の判断基準は、サービスが「実行中」と表示されることではありません。ゲートウェイ、DNS、透過プロキシ、ルールによる出力先、障害時の復旧をそれぞれ確認できることが重要です。まず1台の端末で一連の動作を検証し、それから段階的に範囲を広げると、変更の影響を抑えられます。