Xray JSON 設定看似只是由 inbounds、outbounds、routing 與 dns 組成的文字檔,實際上卻同時描述了流量從哪裡進入、如何辨識目標、由哪個出站送出,以及網域名稱在什麼位置完成解析。當所有內容都塞進單一檔案時,短期內容易匯入與啟動;但節點增加、分流規則變複雜,或需要在 Windows、Linux 旁路由與容器環境之間搬移時,單檔設定很快會變成難以審查的風險來源。
本文以 Xray-core 的 JSON 結構為主軸,說明如何設計模組邊界、排列路由規則、處理 DNS 防洩漏,並建立可驗證、可回滾的部署流程。範例會使用本機 SOCKS 入站、VLESS 代理出站、直連與阻斷出站,讀者可以再依 v2rayN 匯出的節點參數替換位址、UUID、SNI 與 Reality 相關欄位。設定中的網域、UUID、金鑰與連接埠均為示意值,不能直接當作可用節點使用。
先用單檔設定完成最小可運作鏈路,再按入站、出站、DNS、路由與記錄職責拆分;每次修改都以 Xray 設定測試、核心日誌與實際請求三層驗證,避免把 JSON 語法錯誤、路由命中錯誤和遠端節點故障混在一起排查。
先建立 Xray JSON 的模組心智模型
Xray 的設定頂層通常由 log、api、dns、routing、inbounds、outbounds 與 policy 等區塊組成。不是每份設定都必須包含所有區塊,但每個區塊都應有清楚的責任。inbounds 只負責接收本機或區域網路流量,outbounds 描述流量離開核心時採用的協定,routing 決定選擇哪個出站,dns 則決定名稱解析與路由判斷所使用的解析路徑。
最常見的設計錯誤,是把「能啟動」誤認為「架構正確」。例如一個 SOCKS 入站可以成功監聽 127.0.0.1:10808,但若路由規則把所有連線送到不存在的出站標籤,核心仍可能在收到實際請求後報錯。相反地,JSON 語法正確也不代表遠端 VLESS、VMess 或 Trojan 節點的傳輸參數一致。設定驗證應分成語法、核心初始化、入站監聽、路由命中與遠端交握五個層次。
以下是一個只保留結構的最小骨架。這段內容不能直接使用,因為代理出站缺少實際伺服器參數;它的用途是協助確認頂層物件與陣列的層級關係:
{
"log": {
"loglevel": "warning"
},
"inbounds": [
{
"tag": "socks-in",
"listen": "127.0.0.1",
"port": 10808,
"protocol": "socks",
"settings": {
"udp": true
}
}
],
"outbounds": [
{
"tag": "proxy",
"protocol": "vless",
"settings": {}
},
{
"tag": "direct",
"protocol": "freedom"
},
{
"tag": "block",
"protocol": "blackhole"
}
],
"routing": {
"domainStrategy": "AsIs",
"rules": []
}
}
先固定入站與出站的邊界
入站是本機服務的入口,出站是 Xray 對外建立連線的方式。兩者透過路由規則連接,但不應互相混寫。桌面端通常可以從 127.0.0.1 提供 SOCKS 或 HTTP 入站,讓指定應用程式使用;旁路由或 TUN 環境則可能需要透明代理入站,並額外處理原始目的位址、UDP 與策略路由。若沒有明確需求,不要一開始就同時開啟多種入站,否則很難判斷請求究竟進入了哪個監聽連接埠。
出站至少建議保留三個語意清楚的標籤:proxy 代表代理鏈路、direct 代表本地直連、block 代表主動拒絕。標籤是路由規則引用的識別名稱,不是協定名稱。把標籤命名為 vless-443、direct-cn 或 reject-ads 也可以,但長期維護時應避免同一標籤在不同檔案中重複定義。
建立最小入站
先在「本機 SOCKS 連接埠」建立
127.0.0.1:10808,啟用 UDP 時再確認應用程式確實需要 UDP,不要把服務綁定到所有網卡。加入代理出站
從 v2rayN 或其他管理端取得節點參數,逐項填入協定、位址、連接埠、UUID、傳輸、安全層、SNI 與 flow,不能只複製伺服器名稱。
保留直連出站
使用
freedom建立direct,讓區域網路、更新服務與明確例外有穩定的出口。加入阻斷出站
使用
blackhole建立block,將不需要的廣告、追蹤或明確禁止的目標送入,避免錯誤地落到代理出口。驗證標籤引用
逐一搜尋
outboundTag,確認每個值都能在outbounds找到完全相同的標籤,大小寫與連字符都不能不同。
代理出站的安全參數需要與服務端完全一致。以 VLESS + Reality 為例,常見欄位包括伺服器位址、TCP 連接埠、UUID、flow、security、serverName、publicKey、shortId 與 fingerprint;其中某些欄位是否出現,取決於核心版本與節點產生方式。VMess + WebSocket + TLS 則通常需要核對 WebSocket path、Host、TLS serverName 與 alterId 或相容欄位。不要把 Reality 的參數套到 VMess,也不要因為連接埠同樣是 443 就省略傳輸層設定。
| 區塊 | 主要責任 | 常見錯誤 | 驗證方式 |
|---|---|---|---|
inbounds | 接收本機或區域網路流量 | 連接埠占用、綁定位址錯誤 | 查看監聽狀態與核心啟動日誌 |
outbounds | 定義代理、直連與阻斷出口 | UUID、SNI、傳輸參數不一致 | 使用單一節點進行交握測試 |
routing | 依條件選擇出站 | 規則順序錯、標籤不存在 | 開啟 routing debug 或檢查存取日誌 |
dns | 控制網域解析路徑 | 解析洩漏、解析迴圈、錯誤上游 | 比較不同出站下的解析結果 |
以模組化方式安排路由規則
Xray 路由通常依規則陣列順序判斷,先命中的規則就會決定出站。這表示「例外在前、寬泛條件在後」不是排版偏好,而是功能要求。區域網路、核心自身流量、阻斷清單與特定網域應放在兜底規則之前;最後才使用匹配大量 TCP、UDP 或所有剩餘流量的代理規則。
路由條件可以依網域、IP、連接埠、網路類型、來源入站與協定等欄位組合。需要特別注意的是,同一條規則中的不同條件通常是交集關係,而同一欄位陣列內的多個值通常是任一符合。例如同時寫入 domain 與 ip,未必代表網域或 IP 任一命中;若要表達兩種獨立情況,應拆成兩條規則,讓意圖更清楚。
{
"routing": {
"domainStrategy": "IPIfNonMatch",
"rules": [
{
"type": "field",
"ip": ["geoip:private"],
"outboundTag": "direct"
},
{
"type": "field",
"domain": ["geosite:category-ads-all"],
"outboundTag": "block"
},
{
"type": "field",
"domain": ["geosite:cn"],
"outboundTag": "direct"
},
{
"type": "field",
"ip": ["geoip:cn"],
"outboundTag": "direct"
},
{
"type": "field",
"network": "tcp,udp",
"outboundTag": "proxy"
}
]
}
}
上例只是常見分流骨架,不代表所有地區或所有應用程式都應採用相同策略。geoip:private 通常應優先處理,避免路由器管理頁面、NAS 或印表機經過代理。廣告阻斷規則是否啟用,則要考慮網站相容性;若誤阻斷登入、驗證或圖片網域,應從日誌找出實際命中的網域,再加入例外,而不是直接刪除全部阻斷規則。
domainStrategy 會影響網域何時解析為 IP。AsIs 主要保留原始目標形式,適合以網域規則為主的情況;IPIfNonMatch 表示網域規則未命中時再解析並進行 IP 判斷;IPOnDemand 則會更積極地在需要 IP 條件時解析。選擇策略時要同時檢查 DNS 設定、路由規則和流量型態,不能只看到 geoip:cn 就任意切換成最積極的模式。
結論:先讓路由可解釋,再追求規則數量
一套只有十條、每條都能從日誌說明原因的規則,通常比堆疊數十個來源不明的網域清單更容易維護。新增規則前先寫出「什麼流量、為什麼、要去哪個出站」,再決定是否真的需要加入設定。
DNS 防洩漏要同時看解析位置與路由結果
DNS 防洩漏不是單純把系統 DNS 位址換成某個公共服務。真正需要確認的是:應用程式的查詢是否被核心接收、核心使用哪個上游、代理網域是否透過代理鏈路解析,以及直連網域是否因規則設計而回到不預期的本地解析器。若瀏覽器使用 DoH、應用程式內建 DNS,或系統服務繞過 TUN 與本機入站,單靠 Xray 的 dns 區塊仍可能看不到全部查詢。
在桌面部署中,可以先將 Xray DNS 的用途限制清楚,再以路由規則配合。代理出站所需的遠端網域,常見做法是讓代理鏈路處理解析;直連目標則可以交給指定的本地上游。實際欄位和可用策略會隨 Xray-core 版本改變,因此升級核心後必須重新執行設定測試,並觀察是否出現 DNS server、解析失敗或循環轉送訊息。
{
"dns": {
"servers": [
{
"address": "https+local://1.1.1.1/dns-query",
"domains": ["geosite:geolocation-!cn"]
},
{
"address": "223.5.5.5",
"domains": ["geosite:cn"],
"expectIPs": ["geoip:cn"]
},
"localhost"
],
"queryStrategy": "UseIP"
}
}
這段示例只用來展示分組思路,不能直接推導出你的環境一定不會洩漏。上游 DNS 是否可達、DoH 的連線是否被其他規則代理、系統是否仍把查詢送往路由器,以及 queryStrategy 是否與後續 geoip 判斷一致,都需要實際驗證。若將 DNS 上游指向本機監聽位址,尤其要避免 Xray DNS 再把查詢送回自身,形成遞迴迴圈。
明明設定了代理 DNS,為什麼還看到路由器查詢?
先確認應用程式是否啟用內建 DoH,再檢查系統 DNS、TUN 接管範圍與本機防火牆。只修改 Xray 的 dns 區塊,無法攔截完全繞過核心的加密 DNS。
使用 geoip 規則時一定要設定 IPIfNonMatch 嗎?
不一定。是否需要解析取決於目標形式和規則設計;先確認網域規則未命中時是否真的需要 IP 判斷,再選擇 IPIfNonMatch 或其他策略。
DNS 解析成功但網頁仍然無法開啟?
把 DNS 成功與代理交握分開測試。檢查代理出站的位址、連接埠、TLS、SNI、Reality 公鑰或 WebSocket path,不要只因為能解析網域就判定節點正常。
設定拆分、版本管理與安全部署
單檔設定適合首次建立與故障隔離,因為核心載入的內容一目了然。當入站、節點、DNS 與路由規則逐漸增加,可以按職責拆分,例如建立 conf.d/10-inbounds.json、20-outbounds.json、30-dns.json 與 40-routing.json。不過,是否能讀取目錄、檔案合併規則、陣列是否會追加,以及啟動參數的實際寫法,都必須以目前 Xray-core 版本的文件和執行結果為準。不要因為檔名看起來合理,就假設核心一定會自動載入。
拆分的目的不是把一份混亂設定切成更多混亂檔案,而是讓變更範圍可審查。節點出站檔案不應包含路由例外,DNS 檔案不應偷偷修改入站監聽,路由檔案則應只引用已存在的出站標籤。若部署工具會先把多個 JSON 合併成一份最終檔案,應將「來源檔案」與「實際載入檔案」都保存,否則排查時只看來源檔案,可能無法重現核心真正讀到的內容。
設定檔的版本管理也要注意敏感資料。UUID、Reality privateKey、訂閱網址與 API 存取密鑰不應直接提交到公開位置。可以將公用結構保留在範本中,再由部署階段注入秘密;若只是個人電腦,也至少要限制設定檔的讀取權限,並在分享日誌前移除完整節點網址和認證參數。
# 先測試設定,不直接覆蓋正在使用的服務
xray run -test -config /etc/xray/config.json
# 確認測試通過後,再以前景方式觀察啟動日誌
xray run -config /etc/xray/config.json
# Linux 上確認本機 SOCKS 連接埠是否被監聽
ss -lntup | grep 10808
Windows、Linux、macOS 或容器的執行檔名稱與服務管理方式可能不同,但流程不應改變:先複製目前可用設定,再修改單一模組;先執行核心測試,再重載或重啟;最後用實際請求驗證直連、代理與阻斷三條路徑。若服務由 systemd、排程器或容器管理,還要確認服務使用的工作目錄、設定檔路徑和手動測試時一致,否則容易出現「命令列測試成功,服務啟動卻載入另一份檔案」的假象。
| 驗證層級 | 觀察內容 | 失敗時優先檢查 |
|---|---|---|
| JSON 語法 | 括號、逗號、雙引號與資料型別 | 最後一個欄位多逗號、字串未加引號 |
| 核心初始化 | 模組是否成功載入、資料檔是否存在 | 路徑、版本差異、權限與檔案名稱 |
| 本機監聽 | 127.0.0.1:10808 是否建立 | 連接埠占用、服務帳戶權限、綁定位址 |
| 路由命中 | 目標進入 proxy、direct 或 block | 規則順序、domainStrategy、標籤拼寫 |
| 遠端交握 | TCP、TLS、VLESS 或 VMess 是否完成 | 位址、連接埠、UUID、SNI、flow、傳輸路徑 |
用分層方法排查載入與連線故障
遇到「核心啟動但沒有網路」時,先不要同時更換節點、修改 DNS 和重排路由。第一步查看啟動日誌,確認入站是否監聽成功;第二步用 SOCKS 或 HTTP 用戶端對一個已知目標發起請求;第三步確認該請求命中的出站;第四步才處理遠端握手。這種順序可以把本機服務故障與節點本身失效分開。
若錯誤訊息指出 JSON 無法解析,應從報錯行附近檢查括號配對、逗號、陣列與物件層級。若訊息指出未知欄位或不支援的設定,先核對 Xray-core 版本,不要直接把其他核心或舊版範例的欄位整段複製過來。若核心啟動正常但請求失敗,再查看路由是否把流量送往預期標籤;最後才核對代理出站中的遠端參數。
設定變更最好採用小步驟。先只加入一個代理出站與一條預設代理規則,確認可用後再加入私有位址直連、地區分流、阻斷清單和 DNS 分組。每次變更保留時間、檔案版本與測試結果;如果問題在第三步出現,就能立即回到第二步的已知可用版本,而不是在一大批無法區分的修改中猜測原因。
最後,將可用設定視為一份需要持續維護的部署資產,而不是一次性文字貼上。每次升級 Xray-core、替換節點、調整 DNS 或新增路由分類後,都重新執行設定測試,確認本機連接埠、代理請求、直連目標與阻斷規則仍符合預期。這樣模組化 JSON 才能真正降低維運成本,而不是只是把問題分散到更多檔案之中。