カスタムルールを設定する際は、まずルールの順序、次にマッチ条件、最後にDNSの設定を確認します。ノードに正常に接続できており、特定サイト向けの例外ルールを追加したい方を対象に、V2RayとXrayでよく使われるfieldルールの書き方と、v2rayNでの設定・確認方法を解説します。例では予約済みのドメイン名と文書用アドレスを使用しており、実際のサイト分類を示すものではありません。
1. ルーティングルールは条件を判定してから出力先を選ぶ
ルーティングはノードへの接続設定ではありません。VMessやVLESSなどのプロトコルはサーバーへの接続を担い、ルーティングはコアに届いたリクエストをどの出力先に渡すかを決めます。v2rayNは設定用の画面であり、ルールを実行するのは現在稼働中のコアです。以下ではV2Ray/XrayのJSON構文を使います。他の形式の設定エディターには、そのまま貼り付けられません。
一般的なルールは、type: "field"、マッチ条件、outboundTagで構成されます。タグは、既存の出力先のtagと一致させる必要があります。タグにproxyと書いてもプロキシノードが自動で作成されるわけではなく、directと書いても直接接続用の出力先が作成されるわけではありません。クライアントが生成するタグは環境によって異なるため、変更前に実際の設定を確認してください。
これらはリクエストの宛先ポートであり、クライアントのローカル待ち受けポートではありません。たとえば、次のルールは宛先ポートが443で、ドメインがexample.comに属するリクエストだけをプロキシ出力先に送ります。このドメインへのすべての接続が対象になるわけではありません。
{
"type": "field",
"domain": ["domain:example.com"],
"port": "443",
"outboundTag": "proxy"
}
- 同じフィールド内では通常「OR」:
domain配列のいずれかの項目に一致すれば、ドメイン条件を満たします。 - 異なるフィールド間では「AND」:
domainとportを両方指定した場合、両方の条件を満たす必要があります。 - ルールは記述順に評価:条件に完全一致する最初のルールが見つかると出力先が決まり、より詳細なルールを探し続けることはありません。
2. domain・full・regexp:ドメインマッチの違い
ルートドメインとすべてのサブドメインを対象にする場合はdomain:、特定のホスト名だけを対象にする場合はfull:を使います。どちらもルール名に「ドメイン」が含まれているからといって、同じものとして扱わないでください。domainフィールドに指定するのはホスト名です。URLではないため、プロトコルやパス、クエリパラメーターは含めません。
| 記述方法 | マッチする範囲 | 間違えやすい境界 |
|---|---|---|
domain:example.com | example.comとそのサブドメイン(api.example.comなど) | notexample.comやexample.com.testにはマッチしない |
full:example.com | example.comのみ | www.example.comにはマッチしない |
example | ドメイン内にこの文字列を含む | unrelated-example.testにもマッチする可能性があり、特定サイトの例外設定には不向き |
regexp:^api[0-9]+\.example\.com$ | api1.example.com、api25.example.comなど | 先頭と末尾のアンカーが必要。JSONに記述する場合はバックスラッシュのエスケープも必要 |
正規表現は、パターン指定が必要な場合に限って使いましょう。次の例ではJSON文字列内のバックスラッシュを2つ重ねているため、コアに渡される正規表現には、ピリオドを文字どおりにマッチさせる\.が含まれます。画面の入力欄がJSON文字列ではなく、ルールをそのまま受け付ける場合は、このJSON用のエスケープは不要です。
{
"type": "field",
"domain": [
"full:login.example.com",
"regexp:^api[0-9]+\\.example\\.com$"
],
"outboundTag": "proxy"
}
まとめ:単一ホストの例外にはまずfullを使う
ログイン用のホスト1つだけを例外にするなら、まず完全なホスト名を指定したルールを追加して動作を確認します。すべてのサブドメインも同じ出力先にする必要があると確認できてからdomainルールに広げ、静的リソースや他のサービスの出力先まで変わらないようにしましょう。
3. ip・geoip・geosite:IPアドレスとドメインの集合を分けて記述
ipはJSONのフィールド名で、geoip:はそのフィールドの配列に指定できるデータセット参照です。一方、geosite:はdomain配列に指定します。どちらのデータセットも、コアが対応するデータファイルを読み込める必要があります。データセットの名前や内容はデータファイルによって決まり、コアが名前からリアルタイムに生成するものではありません。
{
"type": "field",
"domain": ["geosite:cn"],
"outboundTag": "direct"
}
{
"type": "field",
"ip": [
"192.0.2.15/32",
"2001:db8::15/128",
"geoip:private",
"geoip:cn"
],
"outboundTag": "direct"
}
上記の192.0.2.15と2001:db8::15は文書用の例示アドレスです。実際に使う場合は対象サービスのアドレスに置き換えてください。IPv4の/32とIPv6の/128は、どちらも単一のアドレスを表します。ネットワークプレフィックスが短いほど、通常は対象範囲が広くなります。1つのアドレスへの接続問題を解決するために、ネットワーク全体を含む大きな範囲を指定するのは避けてください。
- geosite:cn:データセットに登録されたドメイン分類でマッチします。該当ドメインのすべての名前解決結果が同じ地域にあるとは限りません。
- geoip:cn:宛先IPアドレスが属するアドレス集合でマッチします。そのアドレス上のサイトが特定のドメイン分類に属するとは限りません。
- geoip:private:データセットで定義されたプライベートアドレスおよび予約済みアドレスの範囲にマッチします。ローカルネットワークの通信を直接接続にする用途などに使います。
- データセットが見つからない場合:起動ログにgeositeまたはgeoipを読み込めないというメッセージが表示されたら、まずデータファイルと項目名を確認してください。ノードの障害として対処する必要はありません。
4. マッチの優先順位:例外ルールは広いルールより前に置く
コアが「完全なドメイン名はドメイン集合より詳細」と自動判定することはありません。ルールはrules配列の上から順に評価されます。最初のdomain:example.comが直接接続に一致すると、その後のfull:api.example.comによるプロキシルールでは上書きできません。例外ルールを先に置き、対象範囲の広い集合ルールをその後に、最後にフォールバックを置きます。
以下は既存の設定に組み込めるroutingの断片であり、クライアント設定全体ではありません。既存のoutboundsにproxyとdirectのタグがあり、参照するデータセットも利用できることが前提です。実際のタグが異なる場合は、先にタグを合わせてください。出力先を確認せずにルールだけコピーしないようにしましょう。
{
"routing": {
"domainStrategy": "IPOnDemand",
"rules": [
{
"type": "field",
"domain": ["full:api.example.com"],
"outboundTag": "proxy"
},
{
"type": "field",
"domain": ["domain:example.com", "geosite:cn"],
"outboundTag": "direct"
},
{
"type": "field",
"ip": ["geoip:private", "geoip:cn"],
"outboundTag": "direct"
},
{
"type": "field",
"network": "tcp,udp",
"outboundTag": "proxy"
}
]
}
}
| テスト対象 | 最初にマッチするルール | 想定される出力先 |
|---|---|---|
| api.example.com:443 | 1番目:完全なドメイン名の例外 | proxy |
| www.example.com:443 | 2番目:ルートドメインとサブドメインのルール | direct |
| 192.168.1.20:80 | 3番目:プライベートアドレスの集合 | direct |
| 上記の集合にマッチしないパブリック宛先 | 4番目:TCP/UDPのフォールバック | proxy |
この表は設定の評価例であり、実際の通信速度を測定した結果ではありません。例示用ドメインで実際のサービスが動作する保証はないため、Webページの動作確認には利用可能と分かっている宛先を使ってください。最後のフォールバックルールを削除すると、マッチしないリクエストは通常、設定内で最初に定義された出力先を使います。完全な設定を確認せずに「未マッチなら必ずプロキシ」または「未マッチなら必ず直接接続」とは言えません。
5. domainStrategy:IPルールが適用されない理由
リクエストがコアに届いた時点で、宛先はドメイン名の場合もあれば、すでにIPアドレスの場合もあります。IPアドレスだけを含むリクエストは、ドメインルールを追加しても元のドメイン名に戻るわけではありません。逆に、ドメイン名だけのリクエストでip条件にマッチさせるには、通常、ルーティング時の名前解決が必要です。そのため、domainStrategyは個別に確認する必要があります。
| ポリシー | ルーティング時の動作 | 設定時の注意点 |
|---|---|---|
AsIs | ルーティングのマッチ判定のために、宛先ドメインを積極的にIPアドレスへ名前解決しない | 宛先がもともとIPアドレスならIPルールにマッチ可能。出力先でドメイン名が一切名前解決されないという意味ではない |
IPIfNonMatch | 最初の評価でドメイン名にマッチするルールがない場合、名前解決して再度評価する | 最初の評価で無条件のフォールバックにマッチすると、この追加の名前解決は行われない |
IPOnDemand | IPアドレスが必要なルールの評価時に、宛先ドメインの名前解決を試みる | DNSクエリが増える可能性があるため、名前解決の遅延とDNSの出力先も考慮する |
前のセクションでIPOnDemandを使ったのは、最後のフォールバックより前に、3番目のアドレス集合ルールを評価できるようにするためです。IPIfNonMatchに変更すると、ドメイン名のリクエストが先に4番目の広いルールにマッチし、想定したアドレスによる振り分けが行われない場合があります。これはgeoipの書き方ではなく、名前解決が行われるタイミングの違いによるものです。
まとめ:まず必要な情報の種類を決める
サイトごとにルーティングするなら、リクエストにドメイン名が含まれていることをまず確認します。名前解決後のアドレスで振り分けるなら、次に名前解決ポリシーを選びます。DNSサーバー、DNSクエリの出力先、スニッフィングで宛先を補えるかは、それぞれ別に確認してください。domainStrategyを切り替えるだけで、すべてを解決できるわけではありません。
- アプリがHTTPまたはSOCKSプロキシに明示的に接続し、ホスト名を送信する場合、通常はコアがそのままドメインルールで判定できます。
- アプリが先に名前解決してからIPアドレスを送信すると、ドメイン情報が失われることがあります。スニッフィングで識別できるのは対応する通信に限られ、すべてのリクエストを復元できるとは限りません。
- ルーティングの
domainStrategyと、出力先への接続時に使われる同種の名前解決オプションは役割が異なります。変更する際は、設定内のどの階層にあるかを確認してください。
6. v2rayNで設定・動作を確認する
通常はルーティング設定画面からルールを管理することをおすすめします。v2rayNは実行用の設定を生成するため、一時的に生成されたJSONを直接編集すると、サービスの再起動やノードの切り替え時に変更が上書きされる場合があります。以下では「設定」→「ルーティング設定」を開けるデスクトップ画面を例にします。バージョンによってボタンの位置は異なる場合がありますが、ルールの順序と出力先の対応は項目ごとに確認してください。
-
現在の設定を保存する
「設定」→「ルーティング設定」を開き、現在選択されているルールセットとドメイン名前解決ポリシーを記録します。変更前に既存の設定をバックアップし、デフォルトのルールセットをそのまま消去しないでください。
-
ルールを1つ追加する
対象のルールセットに
full:api.example.comなど、完全なドメイン名の条件を追加し、プロキシ出力先を選択します。画面のドメイン入力欄にはルール項目だけを入力し、routingオブジェクト全体を貼り付けないでください。 -
ルールの順序を調整する
この例外ルールを、対応する
domain:、geosite:などの範囲が広いルールより前に移動します。保存後、メイン画面で変更したルールセットが選択されていることを確認してください。 -
接続をやり直す
サービスを再起動するか設定を再読み込みし、対象ページの既存接続を閉じてから再アクセスします。ルールを変更しても、確立済みの接続は通常、自動的に別の出力先へ切り替わりません。
-
実行ログを確認する
コアのログで宛先ホスト、宛先ポート、出力先のタグを確認します。まず動作が確認できているサイトでテストし、その後でルールの範囲を広げてください。ログの詳細が足りない場合は一時的にinfoまたはdebugに引き上げ、確認後に元へ戻します。
動作確認では最低3種類のリクエストを試します。例外ホスト、同じルートドメイン配下の通常ホスト、ローカルネットワークのリソースです。最初の2種類でドメインルールの範囲を確認し、3種類目でプライベートアドレスへの直接接続が、前方にある広いプロキシルールに遮られていないか確認します。ログにリクエストが記録されない場合は、ルーティング式をさらに変更する前に、アプリの通信が現在のプロキシ経由になっているか確認してください。
7. よくあるルール競合への対処
fullを設定したのに、なぜ直接接続される?
まず、その前に対象ドメインを含むdomain:、geosite:、または全通信に適用されるルールがないか確認してください。完全なドメイン名の例外を範囲の広いルールより前に移動して保存し、新しい接続でテストします。選択した出力先タグも確認してください。
domainとipを同時に指定したら、なぜマッチしない?
fieldルールでは両方の条件を満たす必要があります。「ドメインまたはアドレスのどちらかにマッチ」させたい場合は、出力先が同じルールを2つに分けます。2つの条件を両方とも指定する必要がある場合に限り、1つのルールにまとめてください。
geosite:cnがあるのに、プロキシ経由になるサイトがあるのはなぜ?
まず、実際のリクエスト先ホスト名を確認してください。ページ内で読み込まれるリソースは、ページ本体と異なるドメインを使う場合があります。次に、前方のルール、データファイルが読み込まれているか、対象ドメインがデータセットに含まれているかを確認します。検証用に明示的なfull:ルールを追加する方法もあります。アクセスログで実際の出力先を確認してください。
port 443を設定すれば、すべてのWebページにマッチする?
いいえ。宛先ポートを限定するだけです。一般的なHTTPでは80が使われることがあり、ほかのサービスでは独自のポートを使う場合もあります。HTTPSはTCPまたはUDPで通信することもあります。さらにnetwork: "tcp"を指定すると、UDPのリクエストにはマッチしません。
サブスクリプションを更新しても、カスタムルールは有効?
ノードのサブスクリプションとルーティングルールは、別々の設定項目です。更新後に現在のルールセットが選択されているか、プロキシ出力先が有効なノードを参照しているか確認してください。サブスクリプションURLをルーティング設定として扱ったり、ルーティングJSONをサブスクリプションURLの入力欄に貼り付けたりしないでください。
確認する順番は固定しましょう。リクエストがコアに届いているか、ドメイン名またはアドレスを利用できるか、最初にマッチしたルールはどれか、出力先自体が接続できるかを順に確認します。一度に変更する条件を1種類に絞れば、結果の変化がルールの範囲、DNSポリシー、ノードのネットワークのどれに起因するか切り分けられます。