本文適合已經能匯入節點,卻看不懂核心設定與日誌欄位的使用者。讀完後即可分辨本機監聽、遠端連線與規則分流分別位於哪個區塊,並沿著 tag 找到「請求從哪裡進入、經過哪條規則,最後由哪個出口送出」。
先看全局:設定檔不只是一個節點
V2Ray 5.x 使用 JSON 描述核心的執行方式。一份完整的用戶端設定通常不只儲存伺服器位址與使用者 ID,還要定義本機接收流量的入口、向外傳送流量的出口、DNS 行為、日誌層級與路由規則。圖形化用戶端裡看到的「一個節點」,主要對應代理出站中的一組伺服器參數,並不等於完整的執行設定。
讀取設定時,可以先略過協定細節,把資料流理解成三個階段:應用程式將請求交給本機監聽埠,inbounds 接收並識別請求,routing 根據網域、IP、埠號或協定選擇目標,最後由某個 outbounds 項目送出。入站與出站透過 tag 命名,路由規則再引用這些名稱。
頂層欄位沒有固定的書寫順序,JSON 解析器不會因為 routing 寫在 outbounds 前面就改變執行結果。但陣列內的順序可能具有意義:路由規則通常由上到下比對,未命中規則的流量通常會交給第一個出站。因此,閱讀時既要看 tag,也要注意陣列位置。
inbounds
- 方向
- 應用程式到核心
- 常見協定
- SOCKS、HTTP
- 關鍵欄位
- listen、port、tag
- 典型埠號
- 10808
決定本機哪些位址與埠號可以將流量交給核心。
outbounds
- 方向
- 核心到目標
- 代理協定
- VMess、VLESS
- 輔助出口
- freedom、blackhole
- 識別方式
- tag
節點伺服器資訊、傳輸層與 TLS 參數主要集中於此。
routing
- 規則類型
- field
- 比對對象
- 網域、IP、埠號
- 執行結果
- outboundTag
- 檢查順序
- 由上到下
負責選擇出口,不負責建立遠端協定連線。
dns 與 log
- dns
- 解析策略
- log
- 日誌層級
- 常用層級
- warning
- 排錯層級
- info
不是每份設定都會明確寫出,但會直接影響解析與排錯。
inbounds:流量從本機哪裡進入
inbounds 是陣列,每個物件代表一個本機入口。桌面用戶端常見的做法是同時建立 SOCKS 與 HTTP 入站,例如將 SOCKS 放在 127.0.0.1:10808,HTTP 放在 127.0.0.1:10809。瀏覽器、命令列工具或系統代理將請求送到對應埠號後,核心才會開始處理這條連線。
listen 決定監聽位址。設定為 127.0.0.1 時,只接受本機連線;設定為 0.0.0.0 則會監聽所有網路介面,區域網路裝置可能因此存取該埠號。除非明確需要區域網路代理,否則本機迴路位址更符合桌面使用情境。port 必須未被其他程式佔用;重複佔用時,日誌中常會出現 bind 或 address already in use。
protocol 代表入口協定,不是遠端節點協定。一個 SOCKS 入站完全可以將請求轉交給 VLESS 或 VMess 出站,兩者沒有「協定必須相同」的關係。settings 儲存該入站協定專屬的參數;SOCKS 入站常見的 udp: true 表示允許接收 UDP 請求。
sniffing 用來從連線內容中還原目標網域。應用程式有時會先將網域解析成 IP,再向本機代理發起連線;如果核心只能看到 IP,依網域撰寫的路由規則就無法命中。啟用嗅探並設定 destOverride 後,核心可以在適用的 HTTP、TLS 流量中識別網域,再交由 routing 判斷。
{
"tag": "socks-in",
"listen": "127.0.0.1",
"port": 10808,
"protocol": "socks",
"settings": {
"auth": "noauth",
"udp": true
},
"sniffing": {
"enabled": true,
"destOverride": ["http", "tls"]
}
}
tag只要在目前設定內保持唯一即可,名稱可以使用socks-in、lan-in等易讀的短語。- 系統代理只會將支援系統代理設定的流量送入 HTTP 或 SOCKS 入口,不代表會攔截所有程式的流量。
- 修改埠號後,呼叫端也必須同步修改;只改核心設定而未修改系統代理,會表現為立即拒絕連線。
- UDP 是否能正常運作,還取決於應用程式、入站協定、出站協定與伺服器設定。
outbounds:節點、直連與封鎖出口
outbounds 同樣是陣列。代理節點通常只是其中一項,實際用戶端還會建立直連出口與封鎖出口。代理出口使用 VMess 或 VLESS 等協定連線至遠端服務;freedom 讓核心直接存取目標;blackhole 則會終止由規則選中的連線。
代理出站可以再分成兩層。settings 描述協定身分與伺服器埠號,例如 VMess 的位址、埠號、使用者 ID 與安全參數;streamSettings 描述底層傳輸與安全層,例如 TCP、WebSocket、TLS 或 Reality。即使協定欄位正確,只要傳輸路徑、SNI 或安全層不一致,連線仍可能失敗。
VMess + WebSocket + TLS
- protocol
- vmess
- network
- ws
- security
- tls
- 遠端埠號
- 443
- 路徑
- /v2ray
使用者身分放在 settings,傳輸路徑與 TLS 放在 streamSettings。
VLESS + TCP + Reality
- protocol
- vless
- network
- tcp
- security
- reality
- flow
- xtls-rprx-vision
- 指紋
- chrome
Reality 參數必須與伺服器相符,不能只將 security 欄位改名。
直連出口
- tag
- direct
- protocol
- freedom
- 遠端節點
- 不需要
- 用途
- 本機與直連規則
命中 direct 後,由本機網路直接連線至目標。
封鎖出口
- tag
- block
- protocol
- blackhole
- 遠端連線
- 不建立
- 用途
- 封鎖指定流量
路由規則引用 block 後,請求不會繼續傳送至目標。
出站的 tag 是排查設定時最重要的索引。看到路由規則寫著 "outboundTag": "direct",就回到 outbounds 尋找 tag 為 direct 的物件。若規則引用不存在的 tag,核心通常會在啟動階段回報設定錯誤,而不會自動猜測目標出口。
訂閱提供的通常是節點連線參數,不會完整決定本機埠號、日誌層級與所有分流規則。v2rayN、v2rayNG 或 v2flyNG 匯入訂閱後,會將節點欄位與用戶端自身的設定合併,再產生交給核心的執行設定。因此,同一份訂閱在不同用戶端產生的完整 JSON 可能不同。
結論:先按層定位出站錯誤
認證失敗時,先核對 settings 中的位址、埠號與使用者資訊;TLS、Reality 或 WebSocket 交握失敗時,再檢查 streamSettings。將兩層參數混在一起修改,最容易造成欄位看似齊全,連線卻仍然逾時。
routing:依序將請求交給指定出口
routing.rules 是規則陣列。常用的規則類型為 field,可以依照 domain、ip、port、network、protocol、inboundTag 等條件進行比對。規則本身不會轉送資料,只透過 outboundTag 指定由哪個出站處理。
規則順序會改變結果。假設第一條將某個網域交給代理,第二條則將更寬泛的網域集合交給直連,該網域在第一條命中後就會停止繼續比對。更具體的封鎖或強制代理規則應放在前面,涵蓋範圍較大的直連規則與最後的兜底規則則放在後面。
| 比對欄位 | 比對對象 | 典型用途 | 執行結果 |
|---|---|---|---|
domain |
完整網域、後綴或網域集合 | 依網站類別分流 | 交給指定的 outboundTag |
ip |
單一 IP、CIDR 或 IP 集合 | 區域網路與目標網段分流 | 直連、代理或封鎖 |
port |
單一埠號或埠號範圍 | 控制特定服務流量 | 選擇對應出口 |
network |
tcp、udp 或兩者 | 最後的兜底規則 | 涵蓋剩餘連線 |
inboundTag |
一個或多個入站 tag | 不同本機入口使用不同出口 | 實現入口級分流 |
domainStrategy 決定路由器何時為網域解析 IP。AsIs 優先依原始網域進行比對,不會為了 IP 規則主動解析;IPIfNonMatch 會先檢查網域規則,未命中時再解析 IP 並嘗試 IP 規則;IPOnDemand 遇到可能需要 IP 的規則時,會更早觸發解析。選擇哪一種取決於規則設計,不是越積極越好。
如果沒有任何規則命中,V2Ray 通常會使用第一個出站。為避免依賴隱含順序,可以在末尾加入涵蓋 TCP 與 UDP 的兜底規則,並明確寫出目標 outboundTag。如此一來,調整 outbounds 順序時就不會意外改變預設流量方向。
{
"domainStrategy": "IPIfNonMatch",
"rules": [
{
"type": "field",
"protocol": ["bittorrent"],
"outboundTag": "block"
},
{
"type": "field",
"ip": ["geoip:private"],
"outboundTag": "direct"
},
{
"type": "field",
"domain": ["geosite:cn"],
"outboundTag": "direct"
},
{
"type": "field",
"network": "tcp,udp",
"outboundTag": "proxy"
}
]
}
結論:路由排錯從第一條規則開始
先確認目標網域或 IP 實際命中了哪條規則,再檢查該規則引用的 outboundTag。節點連線正常但存取方向錯誤,通常是規則順序、網域嗅探或 DNS 結果造成,而不是代理協定本身損壞。
一份易讀的最小用戶端設定
以下範例將日誌、一個 SOCKS 入站、三個出站與四條路由規則放在同一份檔案中。範例位址與使用者 ID 僅用於展示結構,不能作為實際節點使用。設定檔採用標準 JSON,鍵名與字串必須使用雙引號,結尾不能保留多餘逗號,也不能直接插入註解。
從資料流來看,應用程式先連線至 127.0.0.1:10808。核心檢查路由:BitTorrent 流量進入 block,私人位址與指定網域集合進入 direct,其餘 TCP 與 UDP 請求進入 proxy。proxy 再使用 VMess、WebSocket 與 TLS 連線至範例伺服器的 443 埠號。
{
"log": {
"loglevel": "warning"
},
"inbounds": [
{
"tag": "socks-in",
"listen": "127.0.0.1",
"port": 10808,
"protocol": "socks",
"settings": {
"auth": "noauth",
"udp": true
},
"sniffing": {
"enabled": true,
"destOverride": ["http", "tls"]
}
}
],
"outbounds": [
{
"tag": "proxy",
"protocol": "vmess",
"settings": {
"vnext": [
{
"address": "server.example.com",
"port": 443,
"users": [
{
"id": "00000000-0000-4000-8000-000000000000",
"alterId": 0,
"security": "auto"
}
]
}
]
},
"streamSettings": {
"network": "ws",
"security": "tls",
"tlsSettings": {
"serverName": "server.example.com"
},
"wsSettings": {
"path": "/v2ray"
}
}
},
{
"tag": "direct",
"protocol": "freedom",
"settings": {}
},
{
"tag": "block",
"protocol": "blackhole",
"settings": {}
}
],
"routing": {
"domainStrategy": "IPIfNonMatch",
"rules": [
{
"type": "field",
"protocol": ["bittorrent"],
"outboundTag": "block"
},
{
"type": "field",
"ip": ["geoip:private"],
"outboundTag": "direct"
},
{
"type": "field",
"domain": ["geosite:cn"],
"outboundTag": "direct"
},
{
"type": "field",
"network": "tcp,udp",
"outboundTag": "proxy"
}
]
}
}
- 先檢查 JSON 語法,尤其確認雙引號、逗號與方括號是否成對。
- 接著核對所有 tag 是否唯一,以及 routing 引用的 outboundTag 是否確實存在。
- 確認入站埠號未被佔用,並讓系統代理或應用程式指向相同埠號。
- 核對代理出站的協定、伺服器埠號、傳輸方式與安全層是否完整對應。
- 最後檢查規則順序,確認兜底規則位於更具體的規則之後。
圖形化用戶端與核心 JSON 如何對應
v2rayN、v2rayNG 與 v2flyNG 都會將常用欄位拆分為表單。節點編輯頁中的位址、埠號、使用者 ID、傳輸方式與安全設定,主要對應至代理 outbound;本機 SOCKS 埠號、允許區域網路連線等選項對應至 inbounds;路由模式、規則集與自訂規則則對應至 routing。
以 v2rayN 為例,本機埠號與基本行為通常可從「設定」→「參數設定」進入調整,節點參數則在伺服器編輯介面修改。用戶端啟動核心時,會將節點、全域參數與路由設定組合成執行設定。直接修改暫時產生的核心 JSON,下一次切換節點、更新訂閱或重新啟動核心時,可能會被重新產生。
Android 上的 v2rayNG 與 v2flyNG 也採用相似的分層方式,但兩者使用的核心不同:v2rayNG 使用 Xray 核心,v2flyNG 使用 v2fly 核心。部分進階欄位與預設值會有所差異,不能將某個用戶端匯出的完整設定原樣視為另一個用戶端的介面設定檔。
為什麼介面裡只有一個節點,執行設定卻有三個出站?
節點只對應 proxy 出站。用戶端會額外建立 direct 與 block,供直連與封鎖規則引用,因此 outbounds 數量通常會多於節點數量。
修改產生的 JSON 後,為什麼重新啟動又恢復原狀?
產生的檔案屬於執行產物。應回到「設定」→「參數設定」、節點編輯或路由設定中修改來源資料,再重新啟動核心驗證。
匯入訂閱後,本機埠號為什麼沒有跟著變更?
訂閱主要提供節點連線參數,本機監聽埠號屬於用戶端設定。請檢查 SOCKS 埠號是否仍為 10808,並同步更新系統代理。
路由規則寫了網域,為什麼還是走錯出口?
先啟用適用的網域嗅探,再檢查 domainStrategy、DNS 結果與規則順序。可暫時將日誌層級調至 info,觀察實際目標與出站 tag。
依日誌順序排查啟動失敗與分流錯誤
設定問題可以分為啟動階段與執行階段。啟動階段失敗通常與 JSON 語法、欄位類型、埠號重複或無效 tag 有關,核心甚至不會建立入站監聽。執行階段才出現的問題,則多半與節點參數、DNS、規則命中與目標網路有關。
排錯時不要一次修改多個區塊。先將 loglevel 從 warning 暫時調整為 info,重現一次問題並記錄時間。確認是入站未監聽、規則選錯出口,還是 proxy 出站連線失敗,再回到對應區塊修改。問題解決後可恢復為 warning,減少平時的日誌量。
- 出現 JSON 解析錯誤:檢查錯誤行附近的逗號、雙引號,以及陣列與物件的閉合符號。
- 核心已啟動但埠號未監聽:檢查
listen、port與埠號佔用情況,確認沒有兩個入站使用相同的位址與埠號。 - 應用程式立即提示拒絕連線:核對應用程式代理位址是否為
127.0.0.1,埠號是否與實際入站一致。 - 節點可以連線但分流錯誤:依 routing.rules 由上到下檢查,確認目標最先命中了哪條規則。
- 網域規則始終未命中:檢查 sniffing 是否啟用、DNS 是否回傳預期結果,以及規則使用的是網域還是 IP 條件。
- 只有部分 UDP 應用程式失敗:確認 SOCKS 入站允許 UDP,並檢查出站協定、伺服器與網路是否共同支援該流量。
{
"log": {
"loglevel": "info"
}
}
日誌中的 inbound tag、目標位址與 outbound tag 可以串起完整路徑。例如請求由 socks-in 進入,目標顯示為某個網域,最後選擇 direct,表示節點本身並未參與這次連線;若預期應使用代理,就應檢查 routing,而不是反覆修改 VMess 或 VLESS 身分參數。
反過來,如果日誌已顯示規則選擇 proxy,之後才發生 TLS 交握或連線逾時,代表路由基本上已完成職責。此時應將注意力轉向代理 outbound 的位址、埠號、SNI、傳輸路徑、系統時間與遠端可達性。
結論:用 tag 追蹤完整鏈路
將排錯流程固定為「入站 tag → 目標網域或 IP → 命中規則 → 出站 tag → 傳輸連線」。每一步只對應一個設定區塊,能避免將埠號佔用、分流錯誤與節點交握失敗混為同一個問題。