本文適合準備編輯 Xray 路由規則的使用者閱讀。從網域與 IP 的輸入差異切入,說明規則語法、欄位組合與解析策略,並提供可供核對的 routing 設定片段。讀完後即可判斷連線為何走直連、代理或阻斷,以及修改規則後該查看哪些記錄。範例使用保留測試網域,不涉及真實服務憑證。
路由輸入與出站標籤
Xray 路由負責選擇出站,不會替應用程式建立請求。應用程式的連線先進入 inbounds,路由再讀取目標位址、連接埠與網路類型等資訊,並將連線交給對應的 outbounds。v2rayN 是用戶端介面;本文程式碼描述的是 Xray 核心的 JSON 設定,不能直接當成訂閱連結匯入。
每條規則的 outboundTag 都必須對應到現有出站的 tag。以下使用的 direct、proxy、block 都是自訂標籤,不會因為填上名稱就自動啟用功能。通常分別對應直連出站、已設定的代理出站與阻斷出站。
- 有網域:透過 SOCKS 或 HTTP 代理提交網域時,路由通常可以直接比對網域規則。
- 只有 IP:應用程式先完成解析,再向代理提交 IP 時,便沒有網域可供網域規則直接比對。
- 啟用嗅探:核心可能從支援的握手資訊中擷取網域;是否取代目標位址,或僅供路由比對使用,取決於嗅探設定。
- 沒有規則符合:一般 Xray 設定會使用第一個出站。請勿將這項隱含行為誤認為固定的「預設代理」。
domain、full 與 regexp 的差異
網域比對內容放在規則的 domain 陣列中。這裡的 domain 既是欄位名稱,也可以是陣列元素的比對前綴。欄位名稱表示「檢查網域」,前綴則表示「比對方式」。以下的 example.test 是保留測試網域,適合用來說明語法,不代表可直接連線的服務。
| 陣列元素 | 比對方式 | 比對範圍 |
|---|---|---|
full:api.example.test | 完整網域比對 | 只比對該主機,不包含其子網域。 |
domain:example.test | 網域及子網域比對 | 包含根網域與 api.example.test,不包含 notexample.test。 |
example | 一般字串比對 | 以子字串比對,涵蓋範圍通常比網域後綴比對更廣。 |
regexp:^api[0-9]+\\.example\\.test$ | 正規表示式比對 | 這是 JSON 字串格式,反斜線必須跳脫。 |
geosite:cn | 網域集合比對 | 讀取本機網域資料檔中的指定集合。 |
只想讓單一主機走代理,優先使用 full:。需要涵蓋整個網域樹時,使用 domain:。不要把 *.example.test 當成通用萬用字元寫進一般網域項目;若要達到萬用字元效果,應使用網域後綴比對或明確的正規表示式。
{
"type": "field",
"domain": [
"full:api.example.test",
"regexp:^edge[0-9]+\\.example\\.test$"
],
"outboundTag": "proxy"
}
上例中的兩個陣列元素採「或」的關係,符合任一項即可。正規表示式中的句點必須表示為字面句點;因此在 JSON 中要寫成 \\.。開頭的 ^ 與結尾的 $ 用來限制比對範圍,避免意外符合前後帶有其他字元的主機名稱。
ip、geoip 與 geosite 資料集
ip 欄位用來檢查目標 IP,可填入單一位址、CIDR 網段或 geoip: 集合。網域集合放在 domain 中,IP 集合則放在 ip 中。geosite 與 geoip 不是線上查詢服務,也不能互換欄位。
{
"type": "field",
"ip": [
"192.168.0.0/16",
"10.0.0.0/8",
"fc00::/7",
"geoip:private"
],
"outboundTag": "direct"
}
這段範例明確列出幾個私有網段,並以 geoip:private 集合補足涵蓋範圍。部分範圍會重疊,目的是方便對照語法;實際設定可依所用資料檔內容精簡。192.168.0.0/16 代表一個網段,不是只比對 192.168.0.0 這個位址。
geosite.dat提供網域集合;geoip.dat提供 IP 集合。核心必須能從資源路徑讀取這些檔案。geosite:cn與geoip:cn分別代表網域集合與位址集合,兩者的比對結果不一定相同。- 集合名稱、屬性篩選條件與涵蓋範圍,取決於實際使用的資料檔。不能只看分類名稱,就認定某個網站一定包含在集合中。
- 修改規則後若核心無法啟動,先檢查記錄中是否有讀取檔案失敗或找不到集合的錯誤,不要馬上更換節點。
比對優先順序與欄位組合
routing.rules 會依陣列順序逐條檢查,第一條符合條件的規則就會決定出站。規則越具體,不代表核心會自動將它排在越前面。前面的寬泛規則可能提早結束比對,讓後面的例外規則沒有機會生效。
{
"routing": {
"domainStrategy": "AsIs",
"rules": [
{
"type": "field",
"domain": ["full:api.example.test"],
"outboundTag": "proxy"
},
{
"type": "field",
"domain": ["domain:example.test"],
"outboundTag": "direct"
},
{
"type": "field",
"network": "tcp,udp",
"outboundTag": "proxy"
}
]
}
}
在這段設定中,api.example.test 走代理,www.example.test 走直連,其餘 TCP、UDP 連線則由最後一條規則交給代理。若將第二條移到第一條之前,介面網域會先符合網域樹規則,改走直連。
| 欄位組合 | 邏輯關係 | 實際意義 |
|---|---|---|
同一個 domain 陣列中的多個項目 | 或 | 符合其中任一項,就符合該欄位條件。 |
同一個 ip 陣列中的多個網段 | 或 | 位址落在任一網段內,就符合該欄位條件。 |
同一條規則中的 domain 與 port | 且 | 網域與連接埠必須同時符合。 |
同一條規則中的 domain 與 ip | 且 | 不是網域或 IP 擇一符合;IP 條件也取決於目標位址資訊與解析策略。 |
結論:例外規則應排在集合規則之前
先寫單一主機的特殊處理,再寫網域樹與分類集合,最後才寫兜底規則。若要達成「網域符合或 IP 符合就直連」,應拆成兩條規則,而不是把兩種欄位放進同一條規則。
domainStrategy 如何影響 IP 比對
routing.domainStrategy 決定路由階段是否為網域補上 IP 資訊。它不是用來調整規則順序的開關,也不是指定 DNS 伺服器位址的欄位。即使設定中有 dns 區段,路由也不會因此自動對每個網域執行 IP 比對。
| 策略 | 路由階段的行為 | 注意事項 |
|---|---|---|
AsIs | 不會為了路由比對而主動解析網域。 | 若目標本身就是 IP,仍可比對 IP 規則。 |
IPIfNonMatch | 網域未符合規則時,才嘗試解析並比對含有 IP 條件的規則。 | 若第一輪已符合寬泛的兜底規則,就不會因為未符合而觸發解析。 |
IPOnDemand | 遇到需要 IP 資訊的規則時,會嘗試解析網域後繼續判斷。 | 排在前面的 IP 規則可能增加對解析的依賴,也可能影響後續網域規則是否有機會執行。 |
常見的誤解是:選擇 IPIfNonMatch,先寫 geoip:cn,最後再寫一條涵蓋所有 TCP、UDP 連線的代理規則,就以為所有網域都會先依地區 IP 分流。對網域目標而言,第一輪可能直接符合最後的代理規則;既然已經符合,就沒有「未符合後再解析」的機會。
- 若主要想依網域集合分流:先設定清楚的網域規則,並確認只有 IP 的請求該如何處理。
- 若要等網域沒有規則可符合時才依 IP 判斷:使用
IPIfNonMatch,並檢查是否有通用規則提早符合。 - 若希望較前面的 IP 條件也參與網域請求的判斷:評估使用
IPOnDemand,並確認 DNS 回傳結果與規則順序符合預期。
路由解析取得的 IP,不應直接視為建立連線時最終使用的位址。出站是否繼續使用網域、在哪個階段解析,也會受到所用協定與出站設定影響。排查時應分別確認「路由為何選中這個標籤」與「連線最後前往哪裡」。
依連接埠建立最小驗證案例
不要一次匯入數十條分類規則,再觀察網頁能不能開啟。先使用明確的入站連接埠、一條限制連接埠的網域規則,以及容易辨識的出站標籤,驗證比對流程。以下三個數值是測試設定中的明確參數,不是所有用戶端版本的預設值。
{
"type": "field",
"domain": ["full:api.example.test"],
"port": "443",
"network": "tcp",
"outboundTag": "proxy"
}
這條規則只會比對目標網域、目標連接埠 443 與 TCP 三者同時符合的連線。它不會比對同一主機的 80 連接埠,也不會比對 UDP 443。port 檢查的是目標連接埠,不是本機 SOCKS 監聽的 10808。若瀏覽器使用以 UDP 為基礎的傳輸方式,不能用這條 TCP 規則推斷結果。
- 先備份目前可用的設定,並確認核心已讀取新的路由設定,而不是仍在執行舊的程序。
- 確認本機入站確實監聽
127.0.0.1:10808;若使用其他連接埠,請以實際設定為準。 - 在測試環境中,為保留網域準備解析或嗅探輸入。若沒有準備測試服務,只檢查核心能否載入規則,不要把連線失敗當成路由失敗。
- 若要比較 DNS 行為,可暫時提高記錄層級並重複一次請求,核對接收目標、DNS 查詢與出站標籤;測試完成後請恢復原本的記錄層級。
- 每次只調整一項:先調整規則順序,再調整
domainStrategy,最後才加入資料集。保留每個階段的結果,避免多項變更互相干擾。
v2rayN 路由疑難排解
在 v2rayN 中調整路由後,也要確認目前選用的路由設定與核心類型。本文說明的是 Xray 的欄位語意;介面中的路由編輯項目可能由用戶端轉換後寫入產生的設定,不要將整段 JSON 隨意貼進只接受網域項目的輸入框。
加了 full 規則,為什麼還是走原本的出站?
先將該規則移到寬泛的網域集合規則與兜底規則之前,再重新載入設定。查看記錄中的目標是否仍是網域;若目標只有 IP,請確認應用程式是否自行解析,以及入站嗅探是否確實提供可用的網域。
geosite 規則儲存後,核心為什麼無法啟動?
查看核心啟動記錄,分別確認資料檔能否讀取、集合名稱是否存在,以及規則是否放在正確欄位。先用一條 full: 規則驗證路由,再還原集合規則,即可區分是語法問題還是資料檔問題。
設定了 IPIfNonMatch,為什麼沒有看到預期的 DNS 查詢?
確認第一輪是否已符合網域規則或 network: tcp,udp 兜底規則。若已符合,就不符合「未符合」的觸發條件。若需要讓較前面的 IP 條件參與判斷,再評估 IPOnDemand,不要只靠移動 IP 規則來猜測結果。
同一條規則中同時寫 domain 和 ip,為什麼符合的連線變少了?
這兩個欄位必須同時符合。若原本要表達的是網域集合或位址集合任一符合就直連,請拆成兩條規則,並使用相同的 outboundTag。接著分別以網域目標與 IP 目標進行測試。
修改產生的設定後,重新啟動用戶端又恢復原狀,該怎麼辦?
自動產生的設定可能會在切換節點或重新啟動核心時重建。請透過用戶端提供的路由設定入口儲存規則,或使用用戶端支援的自訂設定方式。重新啟動後再次核對核心實際載入的內容;曾在編輯器中成功儲存,不代表設定已生效。
請固定依照以下順序核對:輸入目標是什麼、規則是否符合、哪條規則最先符合、標籤是否存在、出站能否連線。網頁能開啟,只能證明一次存取成功,不能單獨證明分流正確。保留最小測試規則與對應記錄,比同時切換多種路由模式更容易找出問題。