1. 設定ファイルの確認:バックアップを取り、実際に読み込まれるファイルを特定

クライアントの設定一覧から現在使用中の設定を選び、編集またはファイルを開くメニューを探します。まず複製を保存してからYAMLを編集してください。メニュー名はクライアントによって異なります。編集対象が有効な設定なのか、サブスクリプションの原文なのか、ローカルオーバーライドなのか、クライアントが生成した実行時ファイルなのかを確認することが重要です。変更後は設定を再読み込みし、ログで正常に読み込まれたことを確認します。

config.yamlはよく使われるファイル名ですが、必須ではありません。コアは指定されたパスのYAMLを読み込めます。また、GUIクライアントではサブスクリプションごとに別のファイルを保存する場合があります。サブスクリプションを更新すると、通常は元のファイルが再ダウンロードされます。ポート、DNS、独自ルールを長期的に維持するには、クライアントのオーバーライドやマージ機能を利用してください。マージ方法はクライアントの実装に従います。

YAMLの基本チェック3項目

  • インデントにはスペースを使う:階層ごとに半角スペース2つを目安にし、Tabは使いません。トップレベルのdns、proxies、rulesを揃え、子項目は字下げします。
  • リスト項目にはハイフンを付ける:rulesの各ルールはリスト項目です。proxy-groupsの各プロキシグループも同様です。
  • 特殊な文字列は引用符で囲む:パスワードや、コロン・シャープ記号を含む文字列は引用符で囲むのがおすすめです。同じ名前のトップレベルキーを重複して定義したり、半角コロンの代わりに全角コロンを使ったりしないでください。

読み進める順序は、入口から出口へとたどると分かりやすくなります。ポートはアプリからコアへの接続を受け付け、DNSは名前解決とドメイン情報を扱い、ノードとプロキシグループが出口を提供し、ルールが接続ごとの出口を決めます。以下ではこの順に説明しますが、YAML内のトップレベル項目の並び順が処理順を決めるわけではありません。

2. 基本設定:mixed-port、mode、ログレベル

mixed-port: 7890
allow-lan: false
mode: rule
log-level: info
ipv6: false

この設定では、HTTPとSOCKSのプロキシ入口を7890にまとめ、ルールモードを使い、通常の実行情報をログに記録します。ポート番号は説明用の例で、すべてのクライアントに共通する既定値ではありません。クライアントの設定画面でポートが上書きされている場合は、実際の待ち受け状態を確認してください。

項目役割と確認ポイント
mixed-portHTTPとSOCKSのプロキシリクエストを同じ入口で受け付けます。アプリには実際に待ち受けているアドレスとポートを設定してください。
port / socks-portHTTPとSOCKSの入口を個別に用意します。混合ポートを使う場合、同じ目的で個別のポートを追加する必要はありません。
allow-lanLAN内のデバイスからプロキシ入口へのアクセスを許可するか設定します。自分のMacだけで使う場合は、まずfalseのままにしてください。
moderuleはルールに従って接続を振り分け、globalはグローバルポリシーを使い、directは直接接続します。
log-level調査中は一時的にdebugへ変更できます。完了後はinfoに戻し、詳細ログが長期間大量に蓄積しないようにしてください。
ipv6コアでIPv6を使うかどうかに影響します。DNSモジュールにも独立したIPv6設定があるため、この項目だけで判断しないでください。

ポートの待ち受けとシステムプロキシの有効化は別

mixed-port: 7890を設定すると、コアは接続を受け付ける入口を用意します。macOSのアプリからシステムプロキシ経由で接続するには、クライアント側でシステムプロキシを有効にするか、「システム設定」→「ネットワーク」→現在のネットワークサービス→「詳細」→「プロキシ」で設定を確認してください。画面の表示はmacOSのバージョンによって多少異なります。Mac上だけでテストする場合、通常はプロキシアドレスに127.0.0.1、ポートに7890を指定します。

システムプロキシの設定がすべてのアプリに適用されるとは限りません。一部のコマンドラインツール、ゲーム、独自のネットワークスタックを持つアプリでは、個別設定やTUNによる接続の取り込みが必要です。まずHTTPプロキシを明示的に指定できるツールで入口を確認し、その後、接続の取り込み範囲を広げる必要があるか判断してください。

3. dns:待ち受けアドレス、上流DNS、Fake-IP

dns:
  enable: true
  listen: 127.0.0.1:1053
  ipv6: false
  enhanced-mode: fake-ip
  fake-ip-range: 198.18.0.1/16
  default-nameserver:
    - 223.5.5.5
  nameserver:
    - https://dns.alidns.com/dns-query
  fake-ip-filter:
    - "*.lan"
    - "localhost"

enableでコアのDNSを有効にし、listenでローカルの待ち受けアドレスを指定します。ここでの1053は、通常より高い権限が必要な53を避けるための高番ポートの例です。待ち受けアドレスを設定しただけでは、システム全体のDNSクエリが自動的にそこへ送られるわけではありません。システムのDNS設定、TUNによるDNSの横取り、アプリ独自の暗号化DNSなどが実際の経路に影響します。

default-nameserverとnameserverの役割

  • default-nameserverは主に、上流DNSサーバーのホスト名を最初に解決するために使います。たとえば、例のdns.alidns.comを先に名前解決してから、DoHリクエストを確立します。
  • nameserverは通常のドメイン検索に使う上流DNSサーバーの一覧です。例ではDoHを使用しています。接続できるかどうかは、現在のネットワークや関連するルーティング設定によって異なります。
  • nameserver-policyを使うと、特定のドメインに対して上流DNSを指定できます。社内ドメインや社内DNSなど、対象範囲が明確な環境に適しています。

ノードのserverがホスト名の場合は、mihomoのproxy-server-nameserverも確認してください。ノードのホスト名解決に使われ、ノードの解決経路を通常のWebサイトの名前解決と分けるのに役立ちます。通常のクエリ、上流DNSの初期解決、ノードの名前解決を、同じ処理として捉えないようにしましょう。

Fake-IPはリモートサーバーのアドレスではない

fake-ipモードでは、アプリに対応付け用のアドレスを返します。コアはそのアドレスとドメインの対応関係を保持し、接続を受け取った際に照合して転送します。例の198.18.0.1/16は対応付け用アドレスの範囲です。実際のWebサイトの所在地を判断する用途や、プロキシノードのアドレスとして使うものではありません。

fake-ip-filterに含まれるドメインには、既定のフィルター動作によりFake-IPではなく実際の名前解決結果が返されます。LAN内の名前解決や実アドレスを必要とするアプリに応じて例外を追加できますが、DNSの上流サーバーがそのドメインを解決できる必要があります。社内ドメインをフィルターに追加しても、社内DNSで解決できるようになるわけではありません。

4. proxiesとproxy-providers:ノードの定義と取得元

proxiesはノードの一覧です。各ノードは、プロトコルと接続パラメーターを含むマッピングとして記述します。一般的な項目はname、type、server、portのほか、プロトコルに必要な認証情報や通信設定です。ノード名はプロキシグループから参照されるため、重複しない名前を付けてください。サーバー側のポートとローカルのmixed-portは別のものなので、同じ番号にする必要はありません。

項目確認ポイント
nameローカルで識別するための名前です。プロキシグループはこの名前でノードを参照します。
typeプロトコルの種類です。例:ss、trojan、vmess。対応状況はコアによって異なります。
server / portリモートサーバーのアドレスとサーバー側のポートです。接続サービスの提供元から指定されます。
認証情報と通信設定パスワード、UUID、TLS、SNI、トランスポート層の設定はサーバー側と一致させる必要があります。プロトコル名だけを変更しても接続できません。
proxy-providers別の取得元からノード一覧を読み込み、プロキシグループのuseで参照します。

完全なサブスクリプションには、ノード、プロキシグループ、ルールがまとめて含まれていることがあります。一方、ノードプロバイダーが提供するのは、主にノード一覧です。任意のBase64形式のノードサブスクリプションURLをHTTPタイプのproxy-providersに指定しても、コアが自動的に形式を変換するわけではありません。プロバイダーが対応するデータ形式を使う必要があります。

ノードがまだない場合、proxies: []は空の一覧を表し、設定の構造確認に使えます。ただし、リモートの出口が生成されるわけではありません。すでにサブスクリプションのノードがある場合は、実際のプロトコル設定を維持し、例に合わせるために一覧を空にしないでください。

5. proxy-groups:ノードとルールをつなぐプロキシグループ

proxies: []

proxy-groups:
  - name: 手動出口
    type: select
    proxies:
      - DIRECT

これは設定の構造確認に使える、直接接続のみのプロキシグループです。手動出口はグループ名、selectはメンバーを手動で選択する設定で、現在のメンバーは組み込みポリシーのDIRECTだけです。そのため、現状では直接接続しかできません。リモートノードを使うには、現在の設定に実在するノード名をグループに追加するか、useでノードプロバイダーを参照してください。

よく使うグループタイプの違い

  • select:メンバーを手動で選択します。特定の用途に使う出口を固定したい場合や、問題の切り分けに適しています。
  • url-test:指定したテストURLを使って利用可能なメンバーの遅延を比較し、許容差などの設定に基づいて出口を選択します。
  • fallback:設定順に利用可能なメンバーを選びます。常に最小遅延を追求するのではなく、障害時の切り替えを重視します。
  • load-balance:選択した方式に従って接続を振り分けます。1つのダウンロード接続の帯域が、複数ノード分の合計になるわけではありません。

テストを行うプロキシグループのurlとintervalは、ノードのヘルスチェックに関係します。テストに成功しても、テスト先に接続できたことを示すだけで、すべてのサービスにアクセスできる保証にはなりません。自動選択の結果がおかしい場合は、まずテストURLが現在のネットワークに適しているかを確認し、次にノードを調べてください。

プロキシグループ同士を相互に参照することもできますが、循環参照は作れません。ルールで手動出口を指定した場合、設定内に完全に同じ名前のグループが必要です。空白が増えたり、異なる句読点を使ったりすると、参照先が見つからないことがあります。

6. rule-providers:ルールデータと振り分け先を分ける

rule-providers:
  office-domains:
    type: file
    behavior: domain
    format: yaml
    path: ./rules/office-domains.yaml

この設定では、office-domainsという名前のローカルルールプロバイダーを定義しています。type: fileはファイルから読み込む指定で、ここでは自動ダウンロードを行いません。相対パスは通常、テキストエディターの現在のディレクトリではなく、コアの作業ディレクトリを基準にします。GUIクライアントでは読み込み可能なパスが制限される場合もあるため、クライアントが許可する設定データ用ディレクトリにファイルを配置してください。

対応するファイルは次のように記述できます。

payload:
  - "+.example.org"
  - "intranet.example.net"

ここでは構造の説明に予約済みのサンプルドメインを使っており、実在の業務サービスを示すものではありません。behavior: domainは、ファイル内の項目がドメイン照合用であることを示します。+.example.orgはルートドメインとサブドメインに一致します。classicalを使う場合は、DOMAIN-SUFFIX,example.orgのようにルールタイプを含む形式で記述します。上記のようなドメイン名だけの形式はそのまま使えません。

  • domain:ドメイン形式のデータです。ドメイン一覧の管理に適しています。
  • ipcidr:IPネットワークのデータです。アドレス範囲の一覧管理に適しています。
  • classical:ルールタイプを使って記述する一覧です。より多くの照合条件を指定できます。

HTTPタイプではurlも必要です。また、intervalで更新間隔を秒単位で指定できます。たとえば86400は1日です。formatは実際のファイル形式と一致させてください。textに変更すると、ファイルはYAMLのpayload形式ではなくなります。

7. rules:上から順に照合し、MATCHは最後に配置

rules:
  - DOMAIN-SUFFIX,example.org,手動出口
  - RULE-SET,office-domains,DIRECT
  - IP-CIDR,192.168.0.0/16,DIRECT,no-resolve
  - GEOIP,CN,DIRECT
  - MATCH,手動出口

このルールは、前述のプロキシグループとルールプロバイダーを組み合わせて使います。また、ローカルのルールファイルが必要です。1行目はexample.orgとそのサブドメインに一致します。2行目はoffice-domainsを参照します。3行目は指定したプライベートネットワークに一致します。4行目は中国のIPアドレスを照合します。最後の行は、ほかのルールに一致しない接続を処理します。GEOIPの判定には利用可能な地理情報データベースが必要で、ルールを1行追加するだけでは動作しません。

最初に一致したルールが適用される

rulesは上から順に照合し、一致した時点で対応する振り分け先を使います。上の例ではexample.orgがオフィス用ルールセットにも含まれていますが、先に1行目に一致して手動出口へ進みます。これが、独自の例外ルールを広範囲のルールより前に置く理由です。MATCHの後に置いた例外ルールは適用されません。

no-resolveは、IP系ルールとの照合のためにドメイン名を新たに名前解決するのを避ける指定です。接続先がドメイン名だけで、有効な接続先IPがない場合は、ルールに一致しないことがあります。接続先が最初からIPアドレスなら、そのままネットワーク範囲を判定できます。DNSを使った接続をすべて禁止するグローバル設定ではありません。

ポリシー名と組み込みアクション

  • DIRECT:直接接続します。実際に接続できるかは、端末のネットワーク、ルーティング、接続先サービスの状態にも左右されます。
  • REJECT:一致した接続を拒否します。明確にブロックしたい対象に適しています。
  • プロキシグループ名:そのグループで現在選択されているノード、または次の階層のグループに処理を引き渡します。
  • MATCH:追加の条件を指定しないフォールバックルールです。ルール一覧の最後に配置してください。

振り分けを調べるときは、まずmode: ruleを維持し、接続ログで接続先ドメイン、一致したルール、最終的な出口を確認してください。グローバルモードに切り替えた状態では、接続結果を使ってルール一覧の順序を検証できません。

8. TUNとコントロールAPI:必要な接続範囲に合わせて有効化

tun:
  enable: false
  stack: mixed
  auto-route: true
  auto-detect-interface: true
  dns-hijack:
    - any:53

例では、プロキシ入口とルールを順に確認できるよう、まずTUNを無効にしています。システムプロキシに従わないアプリの接続を取り込む場合は、クライアントのサービスインストール、システムの許可、コアの対応状況を確認してから有効にしてください。auto-routeはルートを自動設定し、auto-detect-interfaceは出口に使うネットワークインターフェイスの選択を補助します。TUNを有効にした後は、スイッチの状態だけでなくネットワークルートも確認してください。

dns-hijackのany:53は、対象となる通常のDNS通信を取り込む設定です。DoHやDoTのリクエストをすべて直接取り込めるわけではありません。社内VPN、ほかの仮想ネットワークインターフェイス、ファイアウォールがTUNのルーティングと干渉することがあります。問題が起きた場合は、DNS、ルート、すべてのルールを同時に変更するのではなく、まず接続を取り込む機能を1つ無効にして比較してください。

external-controllerはコントロールAPIの待ち受け先で、Webプロキシのポートとは異なります。たとえば、ローカル管理用のアドレスは127.0.0.1:9090にできます。有効にする場合は、secretで強力なパスワードを設定し、アクセス範囲を制限してください。クライアントによってはこれらの項目を独自に管理するため、依存しているアドレスや認証設定を直接上書きしないようにしましょう。

9. 変更後の確認:構文、待ち受け、出口の順に検証

  1. まず構文を確認します。mihomoのコマンドを単体でインストールしている場合は、設定ファイルの複製を置いたディレクトリで次の検証コマンドを実行できます。GUIクライアントの場合は、設定チェック機能や再読み込み機能を使ってエラーを確認してください。
  2. 次に待ち受けを確認します。7890が別のクライアントに使用されていないことと、現在のプロセスが編集後のファイルを読み込んでいることを確認してください。
  3. プロキシを指定してテストします。プロキシアドレスを明示してリクエストを送り、システムプロキシのスイッチやアプリ独自の設定による影響を除外します。
  4. 最後にルールを確認します。接続ログで適用されたルールと出口を確認し、必要に応じて既存の接続を切断してから再試行してください。長時間接続は、以前に確立された経路を引き続き使うことがあります。
mihomo -t -f ./config.yaml

# macOS:TCP 7890の待ち受けプロセスを確認
lsof -nP -iTCP:7890 -sTCP:LISTEN

# ローカルのHTTPプロキシを指定してリクエストをテスト
curl -I --proxy http://127.0.0.1:7890 https://example.com

設定チェックに成功した場合、現在のコアでファイルを解析できたことは確認できますが、ノードがオンラインであること、ルールセットのダウンロードが成功したこと、接続先サイトにアクセスできることまでは保証しません。curlがHTTPレスポンスを返せば、そのリクエストに応答があったことは分かります。実際に直接接続したのかプロキシ経由なのかは、接続ログも確認してください。この記事の空ノードの例にあるのは直接接続用のメンバーだけなので、リモートプロキシの動作確認には使えません。

エラーメッセージから項目を特定する

  • YAMLの解析に失敗:エラーが示す行の前後で、インデント、引用符、コロン、リストのハイフンを確認してください。
  • プロキシまたはプロキシグループが見つからない:ルールの振り分け先、グループのメンバー、ノード名を確認し、ノードプロバイダーが読み込まれていることも確かめてください。
  • ルールセットを読み込めない:パス、ファイルのアクセス権、behavior、formatが実際の内容と一致しているか確認してください。
  • ポートのバインドに失敗:ポートの使用状況と待ち受けアドレスを確認し、複数のクライアントが同じ入口を同時に使わないようにしてください。
  • サブスクリプション更新後に変更が消える:長期的に維持したい設定を、クライアントが対応するローカルオーバーライド層に移し、マージ後の実行時設定を確認してください。

正常に読み込める基準設定を1つ保存し、変更は一度に1種類ずつ行ってください。まずポート、次にDNS、ノードとプロキシグループ、その後にルールとTUNの順に進めると、問題の範囲を直前に変更した部分に絞り込めます。設定全体の入口については、サイトの詳細設定ガイドもご覧ください。