V2Ray config.json 設定檔解析:看懂 inbounds、outbounds 與 routing

逐步解析 V2Ray 設定檔 JSON,從入站監聽、出站標籤到路由比對順序,帶你看懂各欄位與用戶端產生的設定。

本文重點

適合已匯入訂閱、想進一步閱讀 config.json 的 Mac 使用者。先透過一份僅含本機入站、直連與封鎖的完整設定檔了解基本架構,再逐項檢查連接埠、出站標籤、規則順序與 DNS。範例連接埠是明確指定的教學值,不代表所有用戶端的預設設定。

config.json 與 v2rayN 設定的差異

config.json 是核心讀取的設定檔;v2rayN 則是管理節點、訂閱與執行狀態的桌面用戶端。兩者屬於不同層級:用戶端可以將介面設定轉換成核心執行設定,也能管理自訂設定檔。看到名為 config.json 的檔案,不能只憑檔名就認定目前執行中的程序正在讀取它。

本文採用 V2Ray 傳統 JSON 設定格式。Xray 與 V2Ray 的欄位大致相近,但支援的協定與具體參數不盡相同。閱讀設定前,請先從用戶端執行記錄確認實際啟動的核心、設定檔路徑與啟動錯誤;不要將適用於某個核心的協定參數直接貼到另一個核心。

應用程式請求 本機入站 路由比對 目標出站 遠端服務

這條連線流程也說明了系統代理的作用:遵循系統代理設定的應用程式會將請求送到本機入站。單獨啟動核心,不會讓所有應用程式自動走這條流程;不讀取系統代理設定的應用程式,需要使用自身支援的代理選項或其他明確的流量接管方式。

完整範例:兩個入站、兩個出站

以下設定檔可用來了解本機設定架構,提供 SOCKS 與 HTTP 兩個入口,預設直連,並封鎖範例網域 example.com 及其子網域。這份設定沒有設定遠端代理伺服器,因此不能當作訂閱節點設定使用。開始測試前,請先確認這兩個連接埠沒有被執行中的用戶端占用。

{
  "log": {
    "loglevel": "warning"
  },
  "inbounds": [
    {
      "tag": "local-socks",
      "listen": "127.0.0.1",
      "port": 10808,
      "protocol": "socks",
      "settings": {
        "auth": "noauth",
        "udp": false
      }
    },
    {
      "tag": "local-http",
      "listen": "127.0.0.1",
      "port": 10809,
      "protocol": "http",
      "settings": {}
    }
  ],
  "outbounds": [
    {
      "tag": "direct",
      "protocol": "freedom",
      "settings": {}
    },
    {
      "tag": "blocked",
      "protocol": "blackhole",
      "settings": {}
    }
  ],
  "routing": {
    "domainStrategy": "IPIfNonMatch",
    "rules": [
      {
        "type": "field",
        "domain": [
          "domain:example.com"
        ],
        "outboundTag": "blocked"
      },
      {
        "type": "field",
        "ip": [
          "10.0.0.0/8",
          "172.16.0.0/12",
          "192.168.0.0/16"
        ],
        "outboundTag": "direct"
      }
    ]
  }
}

從最外層來看,入站、出站與規則都是陣列。方括號內可以放入多個物件,物件之間以逗號分隔,最後一項後面不加逗號。為相容一般 JSON 工具,儲存時請使用雙引號,不要加入註解,也不要把連接埠寫成帶引號的字串。

10808
範例 SOCKS 入站連接埠
10809
範例 HTTP 入站連接埠
2 條
依序檢查的路由規則

inbounds:監聽位址、連接埠與入站標籤

listen 決定接收連線的網路介面。範例使用 127.0.0.1,只有本機可以連線。改成 0.0.0.0 會監聽所有 IPv4 介面,但不代表其他裝置一定能連上,還需考量防火牆、網路隔離與驗證機制。僅供本機使用時,保留回送位址監聽較容易控管存取範圍。

SOCKS 入站

標籤
local-socks
監聽位址
127.0.0.1:10808
協定
socks
驗證
noauth,僅供本機使用
UDP
false,本例停用

應用程式必須選擇 SOCKS 代理;不可將此連接埠填入 HTTP 代理欄位。

HTTP 入站

標籤
local-http
監聽位址
127.0.0.1:10809
協定
http
參數
settings: {}

可接收 HTTP 代理請求與 CONNECT 通道請求;此入口本身不代表使用 TLS 加密監聽。

在 macOS 中,可前往「系統設定」→「網路」→目前的網路連線→「詳細資訊」→「代理」核對位址與連接埠。使用本例的 HTTP 入站時,可視需要將網頁代理與安全網頁代理設為 127.0.0.1:10809;使用 SOCKS 入站時,對應的連接埠是 10808。排查期間一次只啟用所需的代理方式,避免不同設定互相影響。

tag 是核心設定內部使用的識別名稱,不是伺服器位址,也不是所有應用程式都能識別的名稱。路由中的 inboundTag 可用來區分請求來源。例如,某條規則只處理 local-http,另一條則處理 local-socks,就能依入口分別設定策略。

outbounds:協定決定行為,tag 用來連結路由

範例中的 freedom 是直連出站,由目前裝置直接存取目標;blackhole 則用來封鎖請求。真正的遠端代理出站還需要設定協定對應的伺服器位址、連接埠與身分參數,以及可能需要的傳輸層設定。只把 tag 改成 proxy,不會讓直連變成代理。

欄位或協定說明檢查重點
tag出站的內部名稱必須與規則中的 outboundTag 完全一致
protocol選擇出站實作方式確認執行中的核心支援該協定
settings該協定專用的參數不同協定不可套用相同設定結構
streamSettings傳輸方式與傳輸安全設定逐項確認是否符合伺服器端要求
freedom直接連線至目標使用本機實際的網路出口
blackhole封鎖符合條件的請求確認沒有誤封正常流量

一般設定中,未符合路由規則的請求會使用 outbounds 陣列中的第一個出站。本例將 direct 放在第一項,因此未符合規則的請求會直連。閱讀用戶端產生的設定檔時,這個順序尤其重要:檔案中有代理出站,不代表未符合規則的流量一定會使用它。

結論:先確認預設出站,再檢查個別規則

排查「為什麼還是直連」時,先查看 outbounds 的第一項,再核對符合規則的 outboundTag。不要根據節點名稱或介面顏色推測實際出口。

routing:首條符合規則、條件組合與網域策略

routing.rules 會由上而下依序檢查,符合某條規則後就使用該規則指定的出站,不會再往下尋找更精確的規則。因此,明確的例外通常要放在範圍較廣的規則之前。陣列順序也是設定行為的一部分,調整順序可能在沒有語法錯誤的情況下改變連線出口。

  1. 請求目標為 www.example.com:符合第一條的 domain:example.com,涵蓋主網域及其子網域,交由 blocked 處理。
  2. 請求目標為 192.168.1.20:不符合第一條,但符合第二條的私有網路位址範圍,交由 direct 處理。
  3. 目標不符合上述條件:沒有規則符合,使用第一個出站 direct。

同一條規則中的不同條件欄位通常都必須符合;同一欄位的多個候選值則符合其中任一項即可。例如,以下規則只會封鎖由 HTTP 入站進入、目標連接埠為 25 的 TCP 請求。來自 SOCKS 入站、使用相同連接埠的請求不符合所有條件。

{
  "type": "field",
  "inboundTag": ["local-http"],
  "network": "tcp",
  "port": "25",
  "outboundTag": "blocked"
}

這個物件應加入既有的 routing.rules 陣列,並依需求安排順序;它不是完整設定檔。也請留意欄位型別有所不同:入站監聽的 port 是數字,路由規則的 port 則以字串表示連接埠或範圍,例如 "80,443"。

使用 geosite: 或 geoip: 類型的條件時,還要確認核心能讀取對應的資料檔,且項目名稱存在。本文使用明確的網域與 CIDR 網段,方便將規則行為與外部資料相依性分開觀察。不要將 routing.domainStrategy 與直連出站中同名或相似的 DNS 策略選項混為一談。

DNS 與 sniffing:規則能辨識哪些目標

網域規則能否符合,取決於入站收到的目標資訊。HTTP 代理請求與 CONNECT 通常會帶有網域;SOCKS 請求則可以傳送網域,也可以傳送應用程式已解析出的 IP。如果應用程式先在本機解析,核心收到的可能只有 IP 位址,因此不能假設核心一定知道原始網域。

curl --proxy socks5h://127.0.0.1:10808 --connect-timeout 5 https://example.com/
curl --proxy http://127.0.0.1:10809 --connect-timeout 5 https://example.com/

第一個指令中的 socks5h 會讓 curl 將網域交由 SOCKS 代理處理;若改用 socks5,curl 就會在本機解析目標。本例預期上述網域請求會遭封鎖,因此指令失敗是教學規則的預期結果,實際錯誤訊息則取決於連線失敗的階段。這裡的 5 是連線逾時秒數,不是效能測量結果。

設定修改順序與常見問題排查

先備份,再確認目前生效的檔案,最後才進行修改。v2rayN 可能在切換節點、更新訂閱或重新啟動核心時重新產生執行設定。暫時修改產生的檔案適合用來驗證問題,不適合長期保存規則;需要保留的變更,應回到用戶端對應的設定頁面或受管理的自訂設定檔中。

  1. 確認核心與路徑。查看啟動記錄中的核心名稱、載入的檔案與錯誤行。路徑若含空格,終端機指令中的檔案路徑必須加上引號。
  2. 檢查 JSON 結構。在 macOS 終端機執行以下指令。這只會解析 JSON,不會驗證核心是否支援每個欄位。
  3. 檢查監聽連接埠。確認 10808、10809 未被其他程序占用,並與應用程式設定一致。
  4. 核對標籤引用。逐一檢查 outboundTag 是否指向現有出站,以及 inboundTag 是否與入站標籤一致。
  5. 重新載入並驗證。透過用戶端重新啟動或載入核心,確認啟動成功,再分別測試已知會符合與不會符合規則的目標。
plutil -lint -s -r -- config.json
lsof -nP -iTCP:10808 -sTCP:LISTEN
lsof -nP -iTCP:10809 -sTCP:LISTEN

plutil 在此用於檢查 JSON 語法;即使語法正確,協定名稱拼錯、缺少必要參數或核心不相容,仍會導致啟動失敗。如果檢查監聽狀態時沒有輸出,也不能單憑這點認定設定檔語法錯誤,還要確認程序是否已啟動,以及是否讀取了另一份檔案。

狀況優先檢查項目下一步處理方式
核心啟動後立即退出JSON、欄位相容性、必要參數查看啟動記錄中的第一則有效錯誤訊息
顯示位址已被占用入站連接埠與重複執行的程序找出占用連接埠的程序,再決定停用或更換連接埠
規則沒有符合規則順序、目標格式、入站標籤使用固定代理指令重現問題並比對記錄
重新啟動後修改內容消失是否修改了產生的設定檔將設定移回用戶端的管理介面
瀏覽器可用,其他應用程式失敗應用程式是否遵循系統代理設定檢查應用程式自身的代理類型與連接埠

結論:每次只修改一個層級

先確認入站能接收請求,再確認出站可用,最後調整路由。暫時提高記錄詳細程度有助於排查,完成後請恢復原設定;分享記錄與設定檔前,請移除訂閱網址、身分憑證及私人目標資訊。

下載v2rayN依平台選擇用戶端