V2Ray 設定檔 JSON 結構逐段解析:inbounds、outbounds 與 routing 各自負責什麼
以一份實際設定檔為例,逐段解析 inbounds 入站、outbounds 出站與 routing 路由三大區塊的欄位意義及關聯,協助你看懂並手動微調自己的設定。
一份 V2Ray JSON 設定檔不是依照執行順序排列的腳本,而是一張鏈路宣告表。應用程式流量會先進入某個入站,由路由規則讀取網域、目標位址、連接埠或入站標籤,再選擇一個出站傳送。DNS、日誌與策略區塊則為這條主鏈提供解析、觀測與行為控制。閱讀設定檔時若只盯著伺服器位址,很容易忽略真正決定流量走向的標籤關係。
適合已能匯入訂閱、但看不懂產生設定檔的讀者;全文從頂層骨架開始,依序檢查入站監聽、代理與直連出站、路由比對順序、DNS 配合方式,並提供可直接用於檢視設定檔的欄位清單。
先建立完整鏈路:JSON 區塊並非彼此獨立
V2Ray 核心讀取設定檔後,會建立監聽連接埠、出站處理器與路由器。以本機瀏覽器為例,瀏覽器會將請求交給本地 SOCKS 或 HTTP 代理連接埠;入站接收連線並辨識目標;routing 依序由上到下比對規則;符合規則的 outboundTag 會指向代理、直連或阻斷出站。若沒有符合任何規則,通常會使用 outbounds 陣列中的第一個出站,因此陣列順序本身也有意義。
以下骨架省略了伺服器身分欄位,但保留區塊之間的連接點。請特別注意 inbound 的 tag、routing.rules 中的 inboundTag 與 outboundTag,以及 outbounds 中對應的 tag。標籤只是設定檔內部名稱,可以自行定義;引用處必須完全一致,大小寫也不能混用。
{
"log": {
"loglevel": "warning"
},
"inbounds": [
{
"tag": "socks-in",
"listen": "127.0.0.1",
"port": 10808,
"protocol": "socks",
"settings": {
"udp": true
},
"sniffing": {
"enabled": true,
"destOverride": ["http", "tls", "quic"]
}
}
],
"outbounds": [
{
"tag": "proxy",
"protocol": "vmess",
"settings": {}
},
{
"tag": "direct",
"protocol": "freedom"
},
{
"tag": "block",
"protocol": "blackhole"
}
],
"routing": {
"domainStrategy": "IPIfNonMatch",
"rules": [
{
"type": "field",
"ip": ["geoip:private"],
"outboundTag": "direct"
},
{
"type": "field",
"network": "tcp,udp",
"outboundTag": "proxy"
}
]
}
}
結論:先追蹤標籤,再閱讀協定細節
遇到「規則已寫入但沒有分流」時,先核對 inboundTag、outboundTag 與實際 tag 是否完整對應,再檢查網域與 IP 條件;這比先修改傳輸參數更容易找出問題。
inbounds:誰在監聽,哪些流量能進入核心
inbounds 是入站陣列,每個物件代表一個接收入口。桌面代理最常見的是 SOCKS、HTTP,或由客戶端組合管理的本地入口。listen 決定監聽位址,port 決定連接埠,protocol 決定入口如何解讀連線,settings 儲存協定專屬選項。若 listen 為 127.0.0.1,只有本機程式能夠存取;改為 0.0.0.0 則會監聽所有網路介面,設定前應先確認區域網路的存取範圍與系統防火牆規則。
SOCKS 入站
- tag
- socks-in
- listen
- 127.0.0.1
- port
- 10808
- protocol
- socks
- udp
- true
適合瀏覽器、終端機工具或支援 SOCKS5 的應用程式明確連線。
HTTP 入站
- tag
- http-in
- listen
- 127.0.0.1
- port
- 10809
- protocol
- http
- timeout
- 300
適合讀取系統 HTTP 代理設定的桌面程式。
tag 不會改變協定,它只為 routing 與日誌提供穩定的引用名稱。一份設定檔可以同時定義多個入站,讓不同入口套用不同策略。例如 socks-in 預設走代理,http-in 只存取內部網路;此時路由規則可透過 inboundTag 區分兩類連線,不必猜測連線來源程式。
sniffing 用於從連線初期的資料中還原目標網域。瀏覽器先將網域解析為 IP 後再建立連線時,路由器可能只能看到 IP;啟用 sniffing 並設定 destOverride 後,核心有機會從 HTTP 請求或 TLS 交握中取得網域,讓 domain 規則參與比對。它不是 DNS 解析器,也不會自動修復所有網域分流問題。若應用程式採用無法辨識的封裝,路由仍可能只能看到位址。
{
"tag": "http-in",
"listen": "127.0.0.1",
"port": 10809,
"protocol": "http",
"settings": {
"timeout": 300
},
"sniffing": {
"enabled": true,
"destOverride": ["http", "tls"]
}
}
- 連接埠被占用:啟動失敗並出現監聽錯誤時,先確認 10808 或 10809 是否已被其他程序占用。
- 代理類型:應用程式填寫的 SOCKS5、HTTP 類型必須與對應的入站協定一致,不能只看連接埠數字。
- UDP 開關:SOCKS 入站需要處理 UDP 時,將 settings.udp 設為 true,同時確認出站與傳輸鏈路支援目標流量。
- 區域網路分享:不要只修改 listen;還要檢查客戶端中的區域網路連線選項、系統防火牆與存取控制範圍。
outbounds:如何定義代理、直連與阻斷
outbounds 是出站陣列。代理出站負責將流量封裝至遠端鏈路,freedom 出站讓核心直接存取目標,blackhole 出站則用於終止符合規則的連線。routing 不會儲存伺服器連線參數,它只回傳一個 outboundTag;真正的位址、連接埠、使用者身分、傳輸方式與安全層都位於對應的出站中。
VMess 代理出站
- tag
- proxy
- protocol
- vmess
- address
- 節點網域
- port
- 443
- network
- ws
- security
- tls
使用者參數位於 settings,傳輸與安全層位於 streamSettings。
本地控制出站
- direct
- freedom
- block
- blackhole
- 引用方式
- outboundTag
- 預設出口
- 陣列第一項
私有位址通常直連,需要明確終止的目標則可交給 block。
以 VMess 為例,settings.vnext 是伺服器清單,users 儲存 id、alterId 與 security 等使用者參數;streamSettings 則描述 TCP、WebSocket 等承載方式,以及 TLS 設定。伺服器端要求的傳輸方式、路徑、主機名稱與連接埠必須成組一致。只將 network 從 tcp 改成 ws,卻未同步 path 與伺服器端入口,不會得到相容的鏈路。
{
"tag": "proxy",
"protocol": "vmess",
"settings": {
"vnext": [
{
"address": "server.example",
"port": 443,
"users": [
{
"id": "訂閱提供的使用者識別碼",
"alterId": 0,
"security": "auto"
}
]
}
]
},
"streamSettings": {
"network": "ws",
"security": "tls",
"wsSettings": {
"path": "/gateway"
},
"tlsSettings": {
"serverName": "server.example"
}
}
}
VLESS 常見於 Xray 核心設定檔,外層仍可看到 tag、protocol、settings 與 streamSettings,但 flow、Reality 等欄位屬於相應核心與鏈路能力,不能機械式複製到任意 V2Ray 設定檔。v2rayN 使用的核心可由客戶端設定決定,v2rayNG 使用 Xray 核心,v2flyNG 使用 v2fly 核心。閱讀訂閱產生的內容時,請先確認目前使用的核心,再查閱該核心支援的欄位範圍。
- 先確認 outbounds 中代理項目的 tag 是否為 routing 實際引用的名稱。
- 再核對 address、port 與使用者身分欄位,避免將本地監聽連接埠誤認為遠端連接埠。
- 接著核對 network、security、path、serverName 等傳輸層欄位是否成組對應。
- 最後查看日誌中的交握、逾時或連線拒絕訊息,不要連續隨機切換參數。
結論:依層次處理連線問題
本地連接埠無法連線先檢查 inbound;遠端逾時先檢查 outbound 位址與網路;只有特定網域走錯出口,再檢查 routing。依層次定位可以避免一次修改多個變數。
routing:比對條件、規則順序與預設出口
routing.rules 是有順序的規則陣列。常用的 type 是 field,條件可包含 domain、ip、port、network、inboundTag 與 protocol 等。同一規則內寫入多種不同類型的條件時,通常必須同時符合;同一欄位中的多個值則視為候選集合。規則會依宣告順序檢查,第一個符合的規則決定 outboundTag,後續規則不會再覆蓋它。
{
"routing": {
"domainStrategy": "IPIfNonMatch",
"rules": [
{
"type": "field",
"ip": ["geoip:private"],
"outboundTag": "direct"
},
{
"type": "field",
"domain": ["domain:intranet.example"],
"outboundTag": "direct"
},
{
"type": "field",
"domain": ["geosite:category-ads-all"],
"outboundTag": "block"
},
{
"type": "field",
"network": "tcp,udp",
"outboundTag": "proxy"
}
]
}
}
這組規則會先放行私有位址,再放行指定的內部網域,接著終止符合條件的目標,最後以 tcp,udp 作為兜底代理。若將兜底代理放在第一條,它會先攔截絕大多數連線,後面的直連與阻斷規則便失去執行機會。檢查分流設定時,不只要問「是否有這條規則」,還要問「前面是否已有更寬泛的條件」。
| 欄位 | 比對對象 | 典型寫法 | 檢查重點 |
|---|---|---|---|
| domain | 目標網域 | domain:example.com | 是否能取得網域,是否被前置規則攔截 |
| ip | 目標位址 | geoip:private | domainStrategy 是否觸發解析 |
| port | 目標連接埠 | 53 或 80-443 | 這裡不是本地入站連接埠 |
| network | 傳輸類型 | tcp,udp | 寬泛條件應放在後面作為兜底 |
| inboundTag | 流量入口 | socks-in | 必須與 inbounds 的 tag 一致 |
domainStrategy 決定路由階段如何處理網域與 IP 條件。AsIs 盡量依原始目標進行比對,不會為 IP 規則主動解析網域;IPIfNonMatch 會先嘗試網域規則,未命中時解析位址並繼續比對 IP 規則;IPOnDemand 則會在可能需要 IP 比對時更積極地解析。這不是速度開關,而是規則語意的選擇。當設定包含 geoip:private 等 IP 規則,且入口經常提供網域時,IPIfNonMatch 是較容易理解的起點。
DNS 與路由如何配合:解析結果不等於最終出口
dns 區塊定義核心可使用的解析伺服器、靜態 hosts 與查詢策略,routing 則決定連線交給哪個出站。兩者彼此相關,但並非同一個步驟。若應用程式自行發出 DNS 查詢,查詢會先以一般網路流量進入核心;若應用程式已提供目標 IP,網域規則能否參與比對,仍取決於 sniffing,以及連線中是否存在可辨識的網域資訊。
{
"dns": {
"hosts": {
"domain:internal.example": "192.168.10.20"
},
"servers": [
{
"address": "223.5.5.5",
"port": 53,
"domains": ["geosite:cn"]
},
"1.1.1.1"
],
"queryStrategy": "UseIP"
},
"routing": {
"domainStrategy": "IPIfNonMatch",
"rules": [
{
"type": "field",
"port": 53,
"network": "udp",
"outboundTag": "proxy"
}
]
}
}
範例會將 UDP 53 連接埠流量交給 proxy,但這並不涵蓋所有解析形式:應用程式可能使用 TCP 53,也可能透過加密的 HTTPS 連線完成解析。較穩妥的排查方式,是先確認請求究竟由系統解析器、應用程式本身或核心 DNS 發出,再決定路由規則需要比對連接埠、網域或特定入站。僅增加一個 DNS 位址,無法自動保證所有請求都採用同一出口。
- 網域規則完全沒有命中時,檢查入站是否啟用 sniffing,以及日誌中的目標顯示為網域還是 IP。
- 私有網域應直連卻被代理時,將明確的內部網域與 geoip:private 規則放在寬泛代理規則之前。
- 修改 DNS 後結果沒有變化時,重新啟動相關應用程式並清除系統解析快取,再進行單一目標測試。
- 出現解析成功但連線逾時時,表示 DNS 已完成工作,下一步應檢查 routing 的選擇與 outbound 鏈路。
手動微調前的檢查順序:避免修改後被覆寫
客戶端通常會將訂閱節點、全域參數與路由設定合併為執行設定檔。v2rayN 7.13.x 的一般參數可從「設定」→「參數設定」進入,先記錄本地連接埠、核心類型、系統代理模式與 DNS 相關選項;路由調整應在客戶端提供的路由設定中完成。v2rayNG 1.10.x 可從「設定」檢查本地代理、DNS 與分流相關項目。版本介面可能會調整文字,但檢查順序不變:先確認設定來源,再確認產生結果。
- 保留可復原副本:匯出目前的客戶端設定,或複製準備修改的獨立 JSON,記錄原有模式與生效範圍。
- 驗證 JSON 語法:檢查逗號、引號、方括號與大括號。JSON 不接受行尾註解,也不能在陣列最後一項後保留多餘逗號。
- 檢查標籤對應:列出所有 inbound tag、outbound tag 與規則引用,確認不存在拼寫差異。
- 一次只修改一層:連接埠問題只修改入站,節點問題只修改出站,分流問題只修改規則順序與條件。
- 建立最小測試集:分別測試一個應直連目標、一個應代理目標,以及一個明確阻斷目標,並記錄三次結果。
- 回到客戶端的持久設定:確認暫時修改有效後,將等效設定寫回 v2rayN、v2rayNG 或 v2flyNG 的正式設定入口。
JSON 能啟動,但所有網站都走代理,最可能是哪裡寫錯?
先查看 routing.rules 的第一條是否已使用 network: tcp,udp 或過於寬泛的 domain 條件攔截所有連線。將私有位址、內部網域與明確的直連規則移到兜底代理規則之前,再重新啟動核心測試。
修改了 outbounds 的伺服器位址,切換節點後為什麼又恢復了?
目前檔案很可能是由訂閱節點動態產生。請編輯客戶端儲存的節點資料,或在節點清單中更新對應的伺服器欄位;不要把執行目錄中的暫時 JSON 當作長期設定來源。
規則寫了 domain,但日誌裡只有 IP,該怎麼處理?
檢查對應 inbound 的 sniffing.enabled 是否為 true,並確認 destOverride 包含實際流量類型。若仍只有 IP,再檢查應用程式是否已提前解析,且連線中沒有可還原的網域。
10808 可以連線,10809 連不上,是節點壞了嗎?
先核對 inbounds 是否同時宣告兩個連接埠,以及 10809 對應的 protocol 是否為 http。單一本地連接埠失敗通常屬於監聽或連接埠占用問題,不能直接歸因於遠端節點。
設定中同時有 proxy、direct、block,如何確認實際使用的是哪一個?
暫時將日誌層級設為 info,分別存取預設的代理、直連與阻斷目標,結合目標位址與錯誤結果檢查規則。完成後恢復 warning,並保留三類測試目標供日後回歸測試。
看懂 V2Ray 設定檔的關鍵,不是記住所有欄位,而是將每次連線還原為「從哪個入站進入、攜帶什麼目標、命中哪條規則、最後落到哪個出站」。inbounds 負責接收,outbounds 負責傳送,routing 負責選擇,DNS 與日誌則補充解析和觀測。沿著這條鏈路檢查,即使設定檔由訂閱與客戶端自動產生,也能快速找出連接埠衝突、標籤斷鏈、規則遮蔽與傳輸參數不一致的位置。