本文速覽

適合已能正常使用 v2rayN、v2rayNG 或 v2flyNG,並希望進一步控制直連、代理與阻擋流量的使用者。重點涵蓋 domain、full、regexp、geosite、CIDR、geoip 的準確意義、多條件規則的組合方式,以及從特殊規則到兜底規則的排列方法。

路由規則實際處理什麼

V2Ray 路由並不是在多個節點之間測試速度,而是根據連線的目標資訊選擇一個出站。應用程式發起連線後,核心會讀取目標網域或目標 IP、目標連接埠、網路類型、入站標籤等欄位,再從 routing.rules 的第一條開始檢查。第一條符合所有條件的規則會決定 outboundTag,後續規則不再參與這次連線。

因此,路由設定必須先定義可用的出站標籤。例如將代理出站標記為 proxy、直連標記為 direct、阻擋出站標記為 block。規則中的標籤只負責引用,拼寫必須與 outbounds 中的 tag 完全一致,大小寫也不能混用。

應用程式發起請求讀取目標資訊逐條比對規則選擇出站標籤建立連線

一條 type: field 規則可以同時包含多個欄位。同一欄位陣列中的值採用「任一命中」邏輯,例如 domain 陣列列出三個網域時,命中其中一個即可;不同欄位之間則須「同時符合」,例如一條規則同時寫入 domainport 時,目標必須符合網域條件,也必須位於指定的連接埠範圍內。

規則欄位 讀取的資訊 範例 組合關係
domain 目標網域 full:api.example.com 陣列內任一命中
ip 目標 IP 或解析結果 10.0.0.0/8 陣列內任一命中
port 目標連接埠 5380-443 與其他欄位同時符合
network 傳輸層網路 tcp,udp 與其他欄位同時符合
inboundTag 連線來自哪個入站 socks-in 與其他欄位同時符合

domain、full、regexp 與 geosite

domain 欄位用來承載網域條件,但陣列中的每個字串還可以使用不同前綴。沒有前綴的普通字串會以關鍵字比對,範圍最廣;domain: 會比對網域及其子網域;full: 只比對完整網域;regexp: 使用正規表示式;geosite: 則引用本機規則資料中的網域分類。

精確網域

寫法
full:api.example.com
命中
api.example.com
未命中
www.example.com

適合單獨控制介面網域、更新網域或固定的服務入口。

網域與子網域

寫法
domain:example.com
命中
example.com
同時命中
cdn.example.com

常用於將主網域及其所有子網域交給同一個出站處理。

正規表示式比對

寫法
regexp:^img[0-9]+\.example\.com$
命中
img12.example.com
代價
比對負擔較高

只有在前綴、後綴與規則集無法表達目標時才使用。

網域分類

寫法
geosite:cn
資料來源
本機 geosite 資料檔
更新方式
隨規則資料更新

適合涵蓋大量網域,但分類內容取決於本機資料版本。

普通關鍵字寫法容易擴大命中範圍。例如陣列項目寫成 example 時,只要網域包含這段字元就可能命中,example.netcdn-example.org 都可能被納入。已知完整網域時,優先使用 full:;需要涵蓋主網域與子網域時使用 domain:,比寬泛的關鍵字更容易檢查。

regexp: 中的表示式還要經過 JSON 字串跳脫。正規表示式本身的 \. 在 JSON 中應寫成 \\.。如果少寫一層反斜線,設定可能無法解析,或表示式意義與預期不同。以下規則只會讓指定的介面網域及一組圖片子網域使用代理:

{
  "type": "field",
  "domain": [
    "full:api.example.com",
    "regexp:^img[0-9]+\\.example\\.com$"
  ],
  "outboundTag": "proxy"
}

geosite 不是線上查詢服務,而是從本機資料檔讀取分類。常見寫法包括 geosite:cngeosite:privategeosite:category-ads-all。某個分類是否存在、實際包含哪些網域,取決於用戶端目前使用的資料檔。複製規則時若日誌提示分類不存在,應先更新 Geo 資料,再確認分類名稱,而不是反覆修改出站節點。

ip、CIDR、geoip 與 domainStrategy

ip 欄位可以寫入單一位址、CIDR 網段或 geoip: 分類。單一 IPv4 位址可寫成 192.0.2.10,網段可寫成 192.168.0.0/16;IPv6 同樣使用 CIDR,例如 fd00::/8。私有網路通常使用 geoip:private 統一處理,避免逐條列出 10.0.0.0/8172.16.0.0/12192.168.0.0/16

IP 規則能否比對網域請求,與 routing.domainStrategy 直接相關。瀏覽器存取網域時,核心最初取得的目標可能仍是網域。若策略為 AsIs,路由階段不會為了 IP 規則主動解析該網域,因此不應將 geoip:cn 視為網域分類的替代方案。

domainStrategy 處理方式 適用重點
AsIs 依原始目標比對,不為路由主動解析網域 以 domain、geosite 規則為主
IPIfNonMatch 網域規則未命中後,再解析 IP 並嘗試 IP 規則 網域規則優先,geoip 作為補充
IPOnDemand 比對過程遇到需要 IP 資訊的規則時解析目標 高度依賴 IP 條件的規則結構

多數「網域分類直連、IP 分類補充」的設定都可以從 IPIfNonMatch 開始。如此會先檢查 geosite:cn,未命中時再透過解析結果檢查 geoip:cn。如果 DNS 回傳多個位址,實際連線與路由解析結果還會受到 DNS 設定、快取與位址選擇影響,因此不要只憑一次解析結果判斷整條規則失效。

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

結論:網域分類與 IP 分類不能互換

需要依網站分類時先寫入 geosite,需要依解析後的網路位置補充判斷時再寫入 geoip;同時將 domainStrategy 設為與這套順序一致的策略。

比對優先順序與規則排列方法

V2Ray 不會為 full:geosite:geoip: 自動分配全域優先順序。所謂「精確規則優先」,實際上必須由設定者將精確規則放在前面。只要前面的規則已命中並選定出站,後面更精確的條件也不會覆寫結果。

最穩定的排列方式是「例外在前、分類居中、兜底在後」。先放必須阻擋或必須直連的精確目標,再放私有網路與區域分類,接著放需要代理的分類,最後使用僅包含 network: tcp,udp 的規則承接其餘連線。兜底規則不能放在中間,否則後續規則永遠沒有機會處理相同的網路類型。

  1. 第一層:特定網域、特定 IP、特定連接埠等明確例外。
  2. 第二層:廣告分類或需要阻擋的目標。
  3. 第三層:區域網路、私有位址與明確要求直連的網站。
  4. 第四層:區域網域與區域 IP 分類。
  5. 第五層:需要代理的指定網域或分類。
  6. 最後一層:涵蓋 tcp,udp 的兜底出站。

以下是一份方便後續擴充的整理範例。它會先阻擋廣告分類,再讓私有位址與指定網站直連,接著處理區域分類,最後將其他 TCP、UDP 連線交給代理。範例中的 proxydirectblock 必須替換為目前完整設定中實際存在的出站標籤。

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

同一條規則中同時寫入 domainip,通常不是「二選一」,而是要求兩個欄位同時符合。若目標是「某個網域或某個 IP 都走直連」,應拆成兩條規則,並使用相同的 outboundTag。這是自訂路由中最常見的邏輯誤區之一。

結論:先拆分規則,再調整順序

當一條規則包含多個不同欄位卻始終無法命中時,先將 domain、ip、port 拆成獨立規則測試;確認各項單獨有效後,再決定是否需要以「同時符合」的方式合併。

在用戶端中套用與驗證

桌面版 v2rayN 7.x 可先開啟「設定」→「路由設定」,複製現有路由方案後再進行修改,避免直接覆寫正在使用的方案。編輯完成後儲存並選取該方案,然後重新啟動核心。若需要核對最終產生的內容,可透過「設定」→「檢視設定檔」查看實際傳給核心的 JSON,重點搜尋 routingrulesoutboundTag

Android 版 v2rayNG 與 v2flyNG 的介面入口會隨版本調整,但驗證原則相同:先確認目前設定已啟用自訂路由,再檢查預設規則、網域策略與應用程式層級的代理設定是否彼此覆蓋。訂閱更新通常只會更新伺服器設定,不應假設它會保留每一種用戶端自訂路由方案;修改前先儲存規則文字,之後更方便搬移。

測試連接埠條件時,需要區分本機代理監聽連接埠與目標連接埠。v2rayN 常見的本機 SOCKS 監聽連接埠為 10808,它屬於入站連接埠;路由規則中的 port: 443 指的是遠端目標連接埠。將 10808 寫入目標連接埠規則,通常不會達到「所有瀏覽器流量」的效果。

若修改後所有網頁都無法連線,先退回只含一條兜底規則的最小設定,再逐條恢復。核心日誌出現 failed to parse 時,檢查 JSON 逗號、引號與正規表示式跳脫;出現找不到 geosite 或 geoip 分類時,更新對應資料檔;連線已建立但出站不符時,優先檢查規則順序與標籤拼寫。

寫了 full 規則,為什麼還是走兜底代理?

先確認日誌中的目標仍是網域,而不是應用程式預先解析出的 IP,再檢查完整網域、連接埠條件與出站標籤。若應用程式直接連線至 IP,單獨的 full: 規則不會命中。

geosite:cn 和 geoip:cn 應該只留一個嗎?

兩者處理的資訊不同。可以先用 geosite:cn 比對網域,再在 IPIfNonMatch 下使用 geoip:cn,補充依解析位址判斷的連線。

把 direct 放在第一條,為什麼代理規則會失效?

檢查第一條是否寫入涵蓋所有連線的 network: tcp,udp。這類規則屬於兜底規則,應移到清單末尾,否則後續相同網路類型的規則無法命中。

同一條規則寫入 domain 和 port 是什麼關係?

兩個欄位必須同時符合。例如 domain:example.com 搭配 port:443,只會處理該主網域及子網域前往目標連接埠 443 的連線,不包含目標連接埠 80。

可維護規則的最終檢查

一份容易維護的路由設定不需要堆疊大量重複項目。優先使用明確的 full:domain: 表達例外,再用 geositegeoip 承載分類,最後保留一條清楚易讀的兜底規則。每次修改只增加一類條件,並透過日誌確認實際命中的規則與出站。

當規則數量增加時,可以依「阻擋、私有網路、強制直連、分類直連、強制代理、兜底代理」的順序分組。即使用戶端介面允許拖曳,也應保留一份格式化 JSON 作為參考,記錄 domainStrategy、出站標籤與所依賴的 Geo 分類。如此在 v2rayN、v2rayNG 或 v2flyNG 之間轉移設定思路時,就不會將介面選項誤認為核心語法。