上級テクニック 読了目安 13分

カスタムルーティングルールの書き方:domain・ip・geositeの構文とマッチング優先順位

ルーティングルールで、プロキシ経由と直接接続の通信を振り分けます。domainのプレフィックス構文、ip/CIDRの指定方法、geositeデータセットの使い方、上から順に評価される仕組みを解説し、すぐ使えるルール例も紹介します。

まず、ルーティングルールが処理する対象を理解する

V2RayとXrayのルーティングモジュールは、インバウンドとアウトバウンドの間に位置します。アプリの通信がコアに入ると、ルーティングモジュールは宛先ドメイン、宛先IP、ポート、ネットワーク種別、インバウンドタグなどを読み取り、その接続をいずれかのアウトバウンドへ渡します。代表的なアウトバウンドタグには、プロキシ接続に使う proxy、ローカルへ直接接続する direct、接続を拒否する block があります。これらは固定キーワードではなく、設定内の outbounds 項目にある tag の値です。ルールの outboundTag は実際のタグと完全に一致させる必要があります。

VMessやVLESSなどのプロトコルは、クライアントとリモート間でデータを転送する方法を担い、ルーティングルールは使用するアウトバウンドを選択します。両者は異なる層の仕組みです。VMessからVLESSへ変更しても、振り分け結果が自動的に変わるわけではありません。新しいサブスクリプションをインポートしても、既存のカスタムルールがそのまま使えるとは限りません。v2rayN、v2rayNG、v2flyNGを使う場合は、現在の設定、ルーティングモード、コアの種類をそれぞれ確認し、ルールが実行中の設定に正しく反映されていることを確かめてください。

典型的なフィールドルールは、type、マッチ条件、送信先アウトバウンドで構成されます。現在よく使われるタイプは field です。1つのルールに複数種類の条件を含めることもできます。たとえばドメインとポートを同時に指定する場合、通常は異なる種類の条件をすべて満たす必要があります。同じ種類の条件に複数の値を指定した場合は候補集合となり、いずれか1つに一致すればそのルールが適用されます。

{
  "type": "field",
  "domain": [
    "domain:example.com",
    "full:api.example.net"
  ],
  "port": "443",
  "network": "tcp",
  "outboundTag": "proxy"
}

この例はTCPの443番ポートだけを対象とし、宛先ドメインが2つの候補のいずれかに一致する場合に適用されます。同じドメインへ80番ポートで接続してもマッチしません。実際の設定では、「より正確にする」ためだけに条件をむやみに追加しないでください。条件を1種類増やすたびに、本来処理すべき接続まで除外される可能性があります。

domainでよく使う4種類のマッチング方法

domain 配列には完全なドメイン名だけでなく、さまざまな形式を指定できます。プレフィックスによって、コアが各エントリーを解釈する方法が決まります。代表的なのは full:domain:regexp:、そしてプレフィックスなしの文字列です。プレフィックスを誤ると、マッチ範囲が広がりすぎたり、親ドメインだけに一致してサブドメインを取りこぼしたりします。

書式 マッチ範囲 適した用途
full:www.example.com 完全一致する宛先ドメインだけを対象 特定のホスト名を個別に処理
domain:example.com ルートドメインとサブドメインを対象 サイト全体と一般的なサブドメインを処理
regexp:^api\d+\.example\.com$ 正規表現でマッチング ドメインに連番や一定の形式がある場合
example ドメイン内のキーワードでマッチング 特定の文字列を含むドメインを広く対象

full::1つの完全一致ドメインだけを受け付ける

full:api.example.com は、APIホストや更新サーバーなど、対象範囲が明確な宛先に適しています。www.example.comcdn.api.example.com まで一緒に対象にはしません。特定のサブドメインだけを変更し、同じ親ドメインに属する他のサービスへ影響させたくない場合は、まず full: を使うとよいでしょう。

domain::ルートドメインと下位サブドメインをまとめて対象にする

domain:example.comexample.com に加えて、www.example.comstatic.example.com などの下位ドメインも対象にします。ただし、末尾の名前が似ているだけで境界の異なるドメインまで同じサイトとして扱うことはありません。サイト単位で振り分ける場合、キーワード指定より安定しやすい方法です。

文字列と正規表現:範囲が広いため慎重に使う

プレフィックスのない値は、キーワードとしてマッチングされます。example というエントリーは、名前にその文字列を含む複数のドメインに一致する可能性があります。対象ドメインの変動が多く、命名規則が明確な場合には便利ですが、無関係なサイトまで巻き込むリスクも高くなります。正規表現はより細かく制御できる一方、保守やトラブルシューティングの負担が増えます。full:domain: で表現できるなら、最初から複雑な正規表現を書く必要はありません。

{
  "type": "field",
  "domain": [
    "full:status.example.com",
    "domain:media.example.net",
    "regexp:^edge-[0-9]+\\.example\\.org$"
  ],
  "outboundTag": "proxy"
}

JSON文字列内のバックスラッシュはエスケープが必要です。そのため、正規表現の \. はJSONファイルでは \\. と記述します。「正規表現単体では正常なのに、設定へ入れると起動できない」問題の主な原因の1つです。保存後にコアがすぐ終了する場合は、実行ログにあるJSON解析エラーとルール解析エラーをまず確認してください。

ip、CIDR、geoipの指定方法

ip 配列では宛先IPをマッチングできます。単一アドレス、CIDRネットワーク、geoip データセットを指定可能です。単一アドレスは固定サーバー、CIDRは連続したネットワーク範囲に適しています。IPv4の 192.0.2.0/24 は、そのネットワークプレフィックスがカバーするアドレス群を表します。IPv6も同じくプレフィックス長で指定し、例として 2001:db8::/32 のように記述します。

{
  "type": "field",
  "ip": [
    "192.0.2.25",
    "198.51.100.0/24",
    "2001:db8::/32"
  ],
  "outboundTag": "direct"
}

CIDRで重要なのは、開始・終了アドレスを文字で省略することではなく、ネットワークプレフィックスです。プレフィックス長が大きいほど範囲は狭くなります。IPv4では /32 が1つのアドレスだけを指し、/24 は通常、同じプレフィックス内の256アドレスをカバーします。サービス事業者が現在返している1つのアドレスを、安易に広すぎるネットワークへ拡張しないでください。同じネットワーク上の無関係なサービスまで振り分け対象になります。

geoip:private は、プライベートネットワークやローカル用途のアドレスにマッチさせるためによく使われ、直接接続ルールの一部に適しています。これにより、LANゲートウェイ、内部パネル、ローカルデバイスへのアクセスがリモートプロキシへ送られるのを防げます。TUNなど、より広範囲の通信を取り込む方式を有効にしている場合は、プライベートアドレスの直接接続ルールを汎用プロキシルールより前に置くことが特に重要です。

{
  "type": "field",
  "ip": [
    "geoip:private"
  ],
  "outboundTag": "direct"
}

geoip:cn のようなエントリーは、現在のコアが読み込んでいるIPデータファイルに依存します。データセットが表すのはネットワークアドレスの集合であり、ドメインの集合ではありません。また、特定サイトのすべてのサーバーが常に同じ地域に属することを保証するものでもありません。大規模サイトはCDNを利用することが多く、同じドメインでもネットワークや時間帯によって異なるアドレスへ解決されます。そのため、IPの地理情報だけでサイト単位の振り分けを行う方法は、必ずしも安定しません。

geositeはドメイン集合であり、プロトコル名ではない

geosite:domain 配列に記述し、あらかじめ整理されたドメイン集合を参照します。たとえば geosite:cn は、該当カテゴリのドメイン群を表すためによく使われ、geosite:category-ads-all は広告関連ドメインの集合を表すためによく使われます。利用できる名称は現在のデータファイルに依存します。名称が存在しない、ファイルが読み込まれていない、データバージョンが一致しないといった場合、ルールが正常に適用されないことがあります。

{
  "type": "field",
  "domain": [
    "geosite:cn"
  ],
  "outboundTag": "direct"
}

geositeの利点は、大量のドメインを手作業で管理しなくてよいことです。基本的な振り分け層の構築には適していますが、リアルタイムのオンライン検索と考えてはいけません。データファイルを更新して初めて集合の内容が変わります。新しいドメインがまだ収録されていない場合は、geositeルールの前に明示的な full: または domain: ルールを追加し、まず現在の経路を補正してからデータ更新を検討してください。

広告カテゴリをブロックするには、まずアウトバウンドに対応する拒否用アウトバウンドを設定し、ルールから正しいタグを参照する必要があります。完全な設定に block タグがないのに outboundTag: "block" と書くだけでは、有効な処理経路にはなりません。

{
  "type": "field",
  "domain": [
    "geosite:category-ads-all"
  ],
  "outboundTag": "block"
}

カテゴリ単位で振り分ける場合は、例外も確認してください。あるドメインが集合ルールによって直接接続と判定されても、現在のネットワークではプロキシ経由が必要な場合があります。そのときは、そのドメイン専用のプロキシルールを集合ルールより前に置きます。逆に、広範なプロキシ集合に含まれていても固定で直接接続したいドメインがあるなら、より具体的な直接接続ルールを先に記述します。

マッチング優先順位:ルールは上から評価し、マッチした時点で停止

ルーティングルールは、rules 配列の順番に従って1つずつ評価されます。最初に条件を満たしたルールがアウトバウンドを決め、それ以降のルールは処理されません。つまり、「より具体的なルール」が自動的に高い優先順位を得るわけではなく、実際の優先順位は配置順そのものです。2番目のルールが full: による完全一致でも、1番目の広範なルールが先にマッチすれば実行されません。

次の順序では、前にある domain:example.com が対象をすでにカバーするため、full:special.example.com の直接接続ルールが機能しません。

[
  {
    "type": "field",
    "domain": [
      "domain:example.com"
    ],
    "outboundTag": "proxy"
  },
  {
    "type": "field",
    "domain": [
      "full:special.example.com"
    ],
    "outboundTag": "direct"
  }
]

正しくは、例外を先に置き、対象範囲の広いルールを後ろに配置します。

[
  {
    "type": "field",
    "domain": [
      "full:special.example.com"
    ],
    "outboundTag": "direct"
  },
  {
    "type": "field",
    "domain": [
      "domain:example.com"
    ],
    "outboundTag": "proxy"
  }
]

順序を整理するときは、「ローカル保護、明示的な例外、カテゴリ集合、地域ルール、最後のフォールバック」という考え方が役立ちます。

  1. まず、プライベートネットワーク、LAN、直接接続を維持したいローカル通信を処理します。
  2. 次に、単一ドメインや単一IPなど、明確な例外を配置します。
  3. 続いて、geosite、geoip、大きめのCIDR集合を配置します。
  4. 最後に、TCPとUDPを対象とする汎用ルールで、残りの通信を処理します。

汎用のフォールバックルールは必ず末尾に置きます。network: "tcp,udp" のプロキシルールを先頭に置くと、ほとんどの接続がすぐにマッチし、後続の直接接続やブロックルールが実質的に機能しなくなります。

domainStrategyがドメインルールとIPルールに与える影響

routing.domainStrategy は、ルーティング段階でドメイン解決をどう扱うかを決めます。代表的な値は AsIsIPIfNonMatchIPOnDemand です。コアのバージョンやクライアントが設定を生成する方法によって違いが生じる場合があるため、変更前に画面上の項目名だけでなく、最終的に実行される設定を確認してください。

ポリシー 処理の要点 使用時の確認事項
AsIs 元の宛先情報に基づいてドメインルールを実行し、ルーティング判定のためにIPを自動解決しない IPによる振り分けに依存するドメイン接続は、想定したルールにマッチしない可能性がある
IPIfNonMatch ドメインルールにマッチしなかった場合にIPを解決し、IPルールを試す DNSサーバー、名前解決結果、最終フォールバックの順序
IPOnDemand ルーティング判定でIP条件が必要な場合に名前解決が行われる可能性がある ルール数、DNS経路、追加の問い合わせ動作

振り分けの中心が domain:geosite: なら、ドメイン情報を判定に利用するほうが分かりやすいでしょう。ドメイン接続も geoip: やCIDRで分類したい場合は、domainStrategy とDNSを同時に確認してください。どのIPへ解決されるかが、その後のIPルールの結果を直接左右します。

ルーティング用DNSと、アプリ自身の名前解決動作も区別する必要があります。接続によってはIPを直接送信するため、コアには元のドメイン名が見えません。この場合、ドメインルールはマッチせず、IPやポートなどの条件だけに頼ることになります。ドメイン名を送信するアプリなら、domainやgeositeの判定に先に参加できます。トラブルシューティングでは、ブラウザーのアドレスバーだけからコアが必ずドメインを受け取っていると判断せず、ログに記録された宛先形式を確認してください。

よく使うルール構成3例

構成1:LANは直接接続、その他はプロキシ経由

この構成は、ローカルデバイスへのアクセスを維持しつつ、それ以外のTCP・UDP通信をプロキシアウトバウンドへ送る場合に適しています。1番目のルールでプライベートアドレスを処理し、2番目を最終フォールバックにします。

{
  "domainStrategy": "IPIfNonMatch",
  "rules": [
    {
      "type": "field",
      "ip": [
        "geoip:private"
      ],
      "outboundTag": "direct"
    },
    {
      "type": "field",
      "network": "tcp,udp",
      "outboundTag": "proxy"
    }
  ]
}

有効にする前に、プロキシアウトバウンドが必要なネットワーク種別に対応していることを確認し、ローカルDNS、LANドメイン、プライベートIPの対応関係も確認してください。内部サービスへカスタムドメインでアクセスする場合は、最終フォールバックより前に内部ドメインの直接接続ルールを追加できます。

構成2:よく使う集合は直接接続、残りはプロキシ経由

この構成では、まずプライベートネットワークを保護し、次にgeositeとgeoipの集合を直接接続へ振り分け、最後に未マッチの接続をプロキシへ渡します。地域別の集合を基盤にした振り分けに適していますが、実際の結果はデータファイルとDNSの解決結果に左右されます。

{
  "domainStrategy": "IPIfNonMatch",
  "rules": [
    {
      "type": "field",
      "ip": [
        "geoip:private"
      ],
      "outboundTag": "direct"
    },
    {
      "type": "field",
      "domain": [
        "geosite:cn"
      ],
      "outboundTag": "direct"
    },
    {
      "type": "field",
      "ip": [
        "geoip:cn"
      ],
      "outboundTag": "direct"
    },
    {
      "type": "field",
      "network": "tcp,udp",
      "outboundTag": "proxy"
    }
  ]
}

geosite集合に含まれていてもプロキシ経由にしたいドメインがある場合は、geosite:cn より前に完全一致のプロキシエントリーを追加します。例外を集合ルールの後ろに置くと、先行する直接接続ルールに処理されます。

構成3:カテゴリをブロックし、例外を許可し、残りは集合で振り分け

より完全な構成では、まず必ずアクセスしたい例外を置き、次にブロック対象のカテゴリを処理し、その後に直接接続の集合とプロキシのフォールバックを実行します。例外をブロックルールより前に置くことで、例外に高い優先順位を与えられます。

{
  "domainStrategy": "IPIfNonMatch",
  "rules": [
    {
      "type": "field",
      "domain": [
        "full:required.example.com"
      ],
      "outboundTag": "direct"
    },
    {
      "type": "field",
      "domain": [
        "geosite:category-ads-all"
      ],
      "outboundTag": "block"
    },
    {
      "type": "field",
      "ip": [
        "geoip:private"
      ],
      "outboundTag": "direct"
    },
    {
      "type": "field",
      "domain": [
        "geosite:cn"
      ],
      "outboundTag": "direct"
    },
    {
      "type": "field",
      "network": "tcp,udp",
      "outboundTag": "proxy"
    }
  ]
}

例にあるドメインは構成説明用のものなので、使用時には実際の宛先へ置き換えてください。ルーティング設定全体も完全な設定の routing オブジェクト内に組み込む必要があり、断片だけを実行可能な設定として扱うことはできません。クライアントにGUIのルールエディターがある場合も、同じ順序で1つずつ作成し、保存後に生成された結果を確認してください。

v2rayN、v2rayNG、v2flyNGで設定する

v2rayNのデスクトップ版では通常、ルーティング設定、ルールセット、カスタム設定から振り分けを管理します。バージョンによって画面上の名称は変わる場合がありますが、確認方法は同じです。現在選択されているルーティングモード、ルールが使用中の設定に紐付いているか、関連するコアを再起動した後のログを順に確認してください。編集画面で保存しただけで、対応するルール構成へ切り替えていなければ、実行結果は変わりません。

v2rayNGでXrayコアを使う場合は、クライアントが提供するルーティング項目から一般的なルールを適用できます。v2flyNGでv2flyコアを使う場合も、ルールの意味はドメイン、IP、ポート、アウトバウンドタグを中心に構成されますが、利用できるフィールドは現在のコアが実際にサポートしている内容に従ってください。サブスクリプションのインポートで通常更新されるのはサーバーノード情報であり、ローカルのカスタム振り分けがすべて自動統合されるとは限りません。

ルールを変更する前に、現在動作している設定をコピーしておくことをおすすめします。その後は毎回1つの変数だけを変更してください。たとえば、まず full: のドメインルールを追加して検証し、次にgeosite集合を追加し、最後に domainStrategy を調整します。一度に数十個のルールを追加して接続障害が起きると、JSON構造、タグ名、データファイル、マッチング順序のどれが原因か判断しにくくなります。

ルールが反映されないときの確認順序

  1. 設定が本当に有効になっているか確認する。クライアントが現在実行しているのが、先ほど変更したルーティング構成であり、別のノード設定やデフォルトルールではないことを確認します。
  2. JSONとフィールドの位置を確認する。rulesrouting オブジェクト内に置き、文字列のエスケープ、カンマ、角括弧が正しく対応していることを確認します。
  3. アウトバウンドタグを確認する。outboundTag は完全な設定内のタグと一字一句一致させ、大小文字も混在させないでください。
  4. 先行ルールを確認する。対象が、より前にあるdomain、IP、ポート、汎用ネットワークルールにすでにマッチしていないか確認します。
  5. 対象がドメインかIPか確認する。アプリがIPへ直接接続している場合、その接続から元のドメイン名を復元できないため、domainやgeositeのルールはマッチしません。
  6. DNSとdomainStrategyを確認する。IPによる追加判定が必要な場合、ルーティング段階で名前解決の結果を取得できることを確認します。
  7. データファイルを確認する。geositeとgeoipのエントリーは、現在読み込まれているデータの内容とカテゴリ名に依存します。
  8. 実行ログを確認する。設定解析エラー、アウトバウンドタグが見つからないエラー、データ読み込み失敗、実際に選択されたアウトバウンドを重点的に確認します。

テストでは再現性のある宛先を選び、アプリ自身による接続再利用の影響を避けてください。すでに確立された長時間接続は、ルールを変更しただけではすぐに経路を再選択しません。設定を保存してコアを再起動し、新しい接続を開始すると結果を判断しやすくなります。ドメインのDNSキャッシュに古いアドレスが残る場合もあり、geoipやCIDRを使うときは特に注意が必要です。

ルール作成時は明確な判断の流れを保つ

安定したルーティング設定は、ルールの数ではなく、各層の境界が明確かどうかで決まります。完全一致のドメインは例外、domain: はサイト全体、geositeは大量のドメイン、CIDRとgeoipはネットワークアドレス、最終フォールバックは残りの接続を担当します。範囲の狭いルールを前に、広いルールを後ろに置くことで、優先順位に関する多くのミスを減らせます。

設定が完成したら、「対象は何か」「最初にどのルールへマッチするか」「どのアウトバウンドへ渡すか」の3点を1つずつ確認してください。この判断の流れをログと設定で対応付けられれば、VMessやVLESSのノードを追加したりサブスクリプションを更新したりした後も、問題がノード接続にあるのかローカルの振り分けにあるのかをすぐ判断できます。

v2rayNをダウンロード