サブスクリプションのインポートを済ませ、v2rayNのルーティングを調整したい方向けの記事です。V2Ray/Xrayのrouting設定をもとに、ドメイン、IP、カテゴリデータ、ルールの順序を解説します。「キーワードによるマッチング」と、標準仕様には存在しないkeyword:プレフィックスの違いも確認します。読み終えると、最小限のルールを作成し、先行ルールに隠れた例外を見つけ、実際の接続ログで使用されたアウトバウンドを確認できるようになります。
1. ルーティングルールが制御するのは接続であり、サブスクリプションのノードではない
サブスクリプションのインポートでは、サーバーアドレス、認証情報、通信方式などを設定します。ルーティングは、各接続をどのアウトバウンドに渡すかを決めます。VMessとVLESSはプロキシプロトコル、routing.rulesは通信先を振り分けるルールであり、互いに代用できません。サブスクリプションの更新に成功しても、カスタムルーティングが現在の設定で有効とは限りません。
ルーティングで参照される接続先は、ドメイン名の場合もIPアドレスだけの場合もあります。アプリがプロキシプロトコル経由でドメイン名を渡す場合は、ドメインルールをそのまま適用できます。一方、アプリが自ら名前解決してIPアドレスだけを渡すと、ドメインルールを照合する情報がないことがあります。対応する通信ではスニッフィングでドメイン情報を復元できる場合がありますが、あらゆる暗号化通信からサイト名を特定できるわけではありません。
type: "field":この記事で使用するフィールド照合ルールの種類です。domain、ip、port:接続先に対する照合条件です。outboundTag:既存のアウトバウンドタグを指定します。サーバーアドレスを直接入力する項目ではありません。- ルールによってノードのTLS、通信経路、認証パラメーターが変更されることはありません。接続に失敗する場合は、これらの設定も個別に確認してください。
2. domainの書き方:完全一致、サブドメイン、キーワード、正規表現
domainは文字列の配列です。同じ配列内の項目はOR条件となり、どれか1つが一致すればこのフィールドの条件を満たします。まずは対象範囲が明確な書き方を選びましょう。特定のホストだけならfull:、ルートドメインとそのサブドメインを含めるならdomain:を使います。文字列の部分一致が必要な場合に限り、プレフィックスなしの文字列を指定します。
| 書き方 | マッチする範囲 | 注意点 |
|---|---|---|
full:example.com | example.comのみ | www.example.comは含まない |
domain:example.com | example.comとそのサブドメイン | notexample.comには一致しない |
example | ドメイン内の部分文字列example | 無関係な複数のサイトにも一致する可能性がある |
regexp:^api[0-9]+\.example\.com$ | 例:api1.example.com | JSONではバックスラッシュのエスケープが必要 |
geosite:cn | データファイル内のcnカテゴリに含まれるドメイン | 実際にインストールされているデータファイルによる |
keyword:は標準のプレフィックスではない
ルールエディターによっては、キーワードのオプションがkeywordと表示されます。しかし、V2Ray/Xray標準のdomain配列でキーワードに一致させるには、通常の文字列を使います。keyword:exampleを汎用的な書き方としてコピーしないでください。「ドメインにexampleを含む」という条件を自動的に表すものではありません。GUI上の種類選択とコアが読み込むJSONは別のレイヤーです。最終的に生成されたルールを確認しましょう。
{
"type": "field",
"domain": [
"full:login.example.com",
"domain:docs.example.com",
"regexp:^api[0-9]+\\.example\\.com$"
],
"outboundTag": "proxy"
}
これはルールオブジェクトであり、クライアント設定全体ではありません。3つの項目はそれぞれ、ログイン用ホスト、ドキュメントドメインとそのサブドメイン、数字付きのAPIホストに対応します。正規表現の\\.はJSON文字列としての表記です。デコード後に正規表現エンジンへ渡されるのは\.です。クライアントの正規表現入力欄に直接入力する場合は、その欄の形式に従い、バックスラッシュを機械的に二重にしないでください。
ポイント:例外のドメインにはfull:を使う
ログイン用や決済用のホストだけを個別に変更する場合は、まず完全一致のドメインを指定し、広範囲のカテゴリルールより前に置きます。短いキーワードでサイト全体を対象にすると、名前が似ている無関係なドメインまで別経路に振り分けるおそれがあります。
3. ip・geoip・geosite:IP範囲とドメイン集合を分けて指定
ipにはIPアドレス、CIDRネットワーク、geoip:データへの参照を指定できます。domainにはドメインルールとgeosite:参照を指定します。この2種類のデータが表すものは異なります。ドメインカテゴリは名前がどの集合に属するかを示し、IPカテゴリは接続先アドレスがどのアドレス集合に属するかを示します。サイトのコンテンツ、企業の所属、物理的なデータセンターの場所を保証するものではありません。
ドメインカテゴリのルール
- フィールド
domain- 参照先
geosite:cn- リソース
geosite.dat- 前提条件
- ルーティングで接続先のドメイン名を取得できる
カテゴリ名が現在のデータファイルに存在する必要があります。名前だけで利用可否を判断しないでください。
IPカテゴリのルール
- フィールド
ip- 参照先
geoip:private- リソース
geoip.dat- 前提条件
- 接続先がIPアドレスであるか、名前解決結果を取得できる
カテゴリの内容はデータファイルによって異なります。特定のアドレスを試す場合は、まず明示的なCIDRを使ってください。
以下では、ドメインの直接接続とプライベートアドレスの直接接続を別々のルールで指定し、「いずれかの集合に一致すれば直接接続する」設定にしています。domainとipを1つのルールにまとめると、OR条件ではなく、両方のフィールドを同時に満たす必要があります。
{
"routing": {
"domainStrategy": "AsIs",
"rules": [
{
"type": "field",
"domain": ["geosite:cn"],
"outboundTag": "direct"
},
{
"type": "field",
"ip": ["geoip:private", "192.0.2.10/32"],
"outboundTag": "direct"
}
]
}
}
192.0.2.10/32は文書用に予約された例示用のIPv4アドレスであり、実在するサービスを示すものではありません。テスト時には対象のアドレスに置き換えてください。- IPv4の
/32は単一アドレスに一致します。IPv6の単一アドレスには/128を使い、ネットワーク範囲には実際のプレフィックス長を指定してください。 geoip:cnとgeosite:cnは同じではありません。同じドメインでも、名前解決結果によって異なるIP集合に属する場合があります。- カテゴリの読み込みエラーが出た場合は、まずコアの実行環境から必要なデータファイルを参照できるか確認し、次にカテゴリ名を確認してください。ルールの順番だけを繰り返し変更しないようにしましょう。
4. 優先順位:上から順に評価し、最初の一致で決定
ルーティングが「より具体的な」ルールを自動的に先頭へ並べることはありません。各処理ではrules配列の順に照合し、最初に一致したルールのアウトバウンドを選択します。完全一致のドメインがgeositeカテゴリより具体的でも、先に一致するカテゴリルールの後ろに置けば適用されません。
{
"routing": {
"domainStrategy": "IPIfNonMatch",
"rules": [
{
"type": "field",
"domain": ["full:login.example.com"],
"outboundTag": "proxy"
},
{
"type": "field",
"ip": ["geoip:private"],
"outboundTag": "direct"
},
{
"type": "field",
"domain": ["geosite:cn"],
"outboundTag": "direct"
},
{
"type": "field",
"network": "tcp,udp",
"outboundTag": "proxy"
}
]
}
}
ここではrouting部分のみを示しています。完全な設定には、proxyとdirectというタグを持つアウトバウンドがすでに存在する前提です。これらは例示用のタグで、すべてのクライアントで固定されている名前ではありません。directと書くだけで直接接続用アウトバウンドが自動作成されるわけではない点にも注意してください。
- まず、個別のログインホストをプロキシ経由にするなど、明確な例外を指定します。
- 次に、明確なLAN内の接続先など、基本的なネットワークルールを指定します。
- 続いて、対象範囲の広いドメインカテゴリやIPカテゴリを指定します。
- 最後に、デフォルトの動作を決めます。どのルールにも一致しない場合、V2Ray/Xrayは通常、アウトバウンド一覧の先頭を使用します。
通常、フィールド同士はAND条件、各フィールドの配列内はOR条件です。たとえば、1つのルールにdomain: ["domain:example.com"]とport: "443"を指定すると、そのドメインとサブドメインへの443番ポートの接続だけが対象になります。ここで指定するのは接続先のポートであり、クライアントのローカル待ち受けポートではありません。
5. domainStrategy:名前解決するか、いつ行うか
routing.domainStrategyは、ルーティング時にドメインの名前解決結果をどのように利用するかを決めます。ブラウザーのDNS設定ではなく、アウトバウンド側にある同名オプションの代わりでもありません。値を変更すると照合結果や名前解決のタイミングが変わる場合がありますが、ルール配列の基本的な優先順位は変わりません。
| 値 | ルーティング時の動作 | 確認ポイント |
|---|---|---|
AsIs | ルーティングの照合では、ドメイン名を積極的に名前解決しない | 元の接続先がIPアドレスなら、ipルールに一致する |
IPIfNonMatch | ドメインリクエストが1回目の照合で一致しない場合、名前解決してルールを再度照合する | 先にドメインルールまたはデフォルトルールに一致すると、この処理は実行されない |
IPOnDemand | ドメインリクエストの照合中、IP判定が必要なルールに応じて名前解決する | 後続のドメインルールより前に、先行するIPルールへ一致する場合がある |
たとえば、あるドメインをプロキシへ送るルールより前にgeoip:cnを置いた場合を考えます。IPOnDemandでは、前方のIP条件によって名前解決が行われ、アドレスがその集合に属すると直接接続が選択されることがあります。AsIsでは、ドメイン名だけのリクエストはこのIPルールのために積極的に名前解決されないため、後続のドメインルールに一致する場合があります。結果が異なるのはルール順が無効になったからではなく、照合に使えるデータが異なるためです。
次にIPIfNonMatchを確認します。1回目の照合でドメインルールに一致せず、他のルールにも処理されなかった場合に限り、コアが名前解決して再度照合します。受信時点で接続先がすでにIPアドレスなら、ドメイン名で最初の照合を行う必要はありません。調査では、すべての接続をドメインリクエストと見なさず、まず入力された接続先の種類を記録してください。
- ドメインによる振り分けだけが必要なら、まず
AsIsで動作を把握しやすい最小限の設定を作成します。 - 「ドメインルールを優先し、一致しなければIPで判定」する場合は、
IPIfNonMatchの設定と、途中にデフォルトルールがないかを確認してください。 - 照合中に名前解決後のIPアドレスを使う必要がある場合は、
IPOnDemandを検討し、前方にある範囲の広いIPカテゴリも見直してください。 - ルーティング時の名前解決にはコアのDNS機構が使われます。解決結果の誤りや失敗、アプリによる解決結果との不一致が、カテゴリの判定に影響する場合があります。
6. v2rayNのカスタムルールが適用されたか確認する
GUI上のルーティング設定、実行中のコア設定、ディスク上で編集したファイルは、同じ内容とは限りません。操作前に現在のルーティング設定を保存してください。v2rayNのメイン画面からルーティング設定を開いて現在の設定を確認し、生成された設定内のrouting.domainStrategyとrouting.rulesを確認します。画面レイアウトによってメニュー名は異なる場合があるため、項目名と実際の実行設定を基準にしてください。一時生成ファイルを直接編集しても、変更が保持されるとは限りません。
- テスト用のルールを1つ作成します。アクセス可能な完全なホスト名を選び、
full:を指定してルールの先頭に置きます。既存のアウトバウンドタグを設定してください。最初は正規表現やカテゴリデータを混在させないようにします。 - 設定を保存して再適用します。クライアントから設定を再読み込みするか、コアを再起動して、変更を現在の実行設定に反映します。起動ログに未知のフィールド、アウトバウンドの未検出、カテゴリの読み込み失敗などがないことを確認してください。
- 新しい接続を確立します。対象のWebページを閉じてから再度アクセスします。必要に応じてテスト用アプリも再起動してください。HTTP/2の長時間接続やコネクション再利用では、古いアウトバウンドが使われ続けることがあり、ページを再読み込みしても新しい接続が作られるとは限りません。
- 実際のログを確認します。アクセスログを有効にして接続先とアウトバウンドタグを確認します。必要に応じて一時的にログレベルを上げてください。ログの形式はコアによって異なります。Webページが開けるかどうかだけで、どのルールに一致したかを判断しないでください。
- 複雑な条件を1つずつ戻します。完全一致のドメインで動作を確認してから、ドメインカテゴリ、IP条件、DNSポリシーを追加します。毎回変更するのは1項目だけにし、変更前後のログを比較できるようにしてください。
ブラウザーの通信には、メインサイト、静的リソース、ログインAPI、メディア用ドメインなどが含まれる場合があります。Webページが表示されても、すべての接続が同じアウトバウンドを通ったとは限りません。ログは接続先のホストごとに確認し、1つのページに含まれるリクエストをすべて同一の接続として扱わないでください。
domain:example.comと書いたのに、別のドメインまで同じ経路になるのはなぜ?
保存されたルールでdomain:が抜けていないか確認してください。プレフィックスのない文字列example.comは部分一致のため、より広い範囲に一致します。ホスト1つだけを対象にする場合はfull:example.comに変更し、設定を再適用して新しい接続を確立してください。
geositeルールを保存したのに、コアの起動時にエラーが出るのはなぜ?
起動ログにカテゴリが存在しない、またはデータファイルを読み込めないというメッセージがないか確認し、現在のコアが参照するデータの保存場所と実際のカテゴリ名を照合してください。まずfull:ルールに置き換えて基本的なルーティングを確認します。リソースの読み込み失敗をノードの利用不可と混同しないでください。
IPIfNonMatchを有効にしたのに、IPルールが適用されないのはなぜ?
前方のドメインルールにすでに一致していないか、末尾にnetwork: "tcp,udp"のようなデフォルトルールがないか確認してください。1回目の照合ですでにルールに一致すると、この設定による名前解決と再照合は行われません。次に、接続がコアに入った時点で接続先がドメイン名かIPアドレスかを確認してください。
ポート53を直接接続に設定すれば、すべてのDNS通信を制御できる?
いいえ。接続先ポート53のルールで対象になるのは、条件に一致する従来型DNSの通信だけです。暗号化DNSは別のポートを使う場合があり、コア自身のDNSクエリにも個別の処理経路があります。ポートルールを1つ追加するだけでなく、アプリのDNS設定とコアのDNS設定も確認してください。
まとめ:接続先・順序・アウトバウンドを記録して検証
変更するたびに、「テストするホスト名、ルールの位置、ログに記録されたアウトバウンドタグ」を控えてください。完全一致ルールで動作を確認してからカテゴリ集合に広げると、構文エラー、マッチ範囲の誤り、DNSのタイミングに関する問題を切り分けやすくなります。