Xray 配置文件结构拆解:inbounds、outbounds 与 routing 逐段读懂

按 log、inbounds、outbounds、routing、dns 的顺序逐段解读 Xray 配置 JSON,讲清每个字段的作用,以及流量在各段之间的走向。

本文速览

本文适合已经会导入节点、准备阅读 Xray 原生配置的用户。先用一份仅含本地入口、直连和阻断出口的完整 JSON 建立参照,再解释日志、端口、标签、路由顺序与 DNS 的关系。读完可以定位流量在哪一段中断,也能分清客户端设置、分享链接与内核运行配置各自负责什么。

配置对象与流量路径

Xray 是处理连接的内核,v2rayN 是管理节点、生成配置并启动内核的桌面客户端。节点分享链接通常只描述一个远端连接;原生 JSON 则可以同时描述本地监听、多个出口、路由与 DNS。把分享链接保存为 config.json,不会自动变成可运行的内核配置。

应用请求 入站接收 路由匹配 出站连接 目标服务

上述链路是阅读配置的主线。log 负责记录状态,dns 在需要解析域名时参与处理,都不是每条请求必须依次经过的独立转发站。顶层对象在 JSON 中的书写先后,不决定流量顺序。

完整 JSON:本地入口与直连基线

下面是一份用于理解结构的独立配置。SOCKS 入口监听 127.0.0.1:10808,HTTP 入口监听 127.0.0.1:10809。它不包含远端代理节点:普通请求直连,发往保留测试域名 blocked.test 的请求被阻断。它不能用来验证远端代理是否可用。

{
  "log": {
    "loglevel": "warning"
  },
  "inbounds": [
    {
      "tag": "socks-in",
      "listen": "127.0.0.1",
      "port": 10808,
      "protocol": "socks",
      "settings": {
        "auth": "noauth",
        "udp": true
      }
    },
    {
      "tag": "http-in",
      "listen": "127.0.0.1",
      "port": 10809,
      "protocol": "http",
      "settings": {}
    }
  ],
  "outbounds": [
    {
      "tag": "direct",
      "protocol": "freedom",
      "settings": {
        "domainStrategy": "UseIP"
      }
    },
    {
      "tag": "block",
      "protocol": "blackhole",
      "settings": {}
    }
  ],
  "routing": {
    "domainStrategy": "AsIs",
    "rules": [
      {
        "type": "field",
        "domain": [
          "full:blocked.test"
        ],
        "outboundTag": "block"
      },
      {
        "type": "field",
        "ip": [
          "127.0.0.0/8",
          "10.0.0.0/8",
          "172.16.0.0/12",
          "192.168.0.0/16"
        ],
        "outboundTag": "direct"
      }
    ]
  },
  "dns": {
    "servers": [
      "localhost"
    ]
  }
}

示例是严格 JSON:键名和字符串使用双引号,不带注释,不在最后一个数组元素后加逗号。文章后面的字段说明用于解释这份配置,不需要逐段再拼成第二份配置。

log:先确定错误发生的位置

loglevel 控制错误日志的详细程度。常用值包括 debug、info、warning、error 和 none。排障时可以临时把示例中的 warning 改成 info,完成后再恢复,避免保留过多连接细节。

字段用途排查时关注什么
loglevel调整错误日志级别配置加载、监听失败、连接失败的具体提示
access指定访问日志文件请求目标及实际采用的出站信息
error指定错误日志文件启动和运行中的错误上下文

本例没有指定日志文件路径;命令行运行时先观察控制台。若自行增加 access 或 error,应选用当前进程可写的路径,并区分相对路径与启动工作目录。日志中可能出现访问目标,分享排障内容前应先移除敏感信息。

inbounds:监听地址、端口与入口标签

一个入站对象就是一个接收流量的入口。listen 是绑定地址,port 是监听端口,protocol 决定应用要用哪种协议连接它。tag 是配置内部的标识,不是密码,也不是要填进浏览器的主机名。

SOCKS 入口

标签
socks-in
地址
127.0.0.1
端口
10808
协议
socks
UDP
true

应用需要使用 SOCKS 协议接入;UDP 还要求应用和后续链路共同支持。

HTTP 入口

标签
http-in
地址
127.0.0.1
端口
10809
协议
http
协议设置
{}

HTTPS 网站通常通过 HTTP CONNECT 建立隧道,不是把入口协议改成 HTTPS。

127.0.0.1 只接受本机连接。将它改为 0.0.0.0 会扩大 IPv4 监听范围,是否能被其他设备访问还取决于防火墙和网络环境。本例 SOCKS 使用 noauth,因此不要为了尝试局域网共享而直接扩大监听范围。

outbounds:出口协议与默认出口

outbounds 是可供路由选择的出口数组。本例的 freedom 直接连接目标,blackhole 阻断连接。这里的 direct、block 都是自行定义的标签;真正决定行为的是 protocol,不是标签的英文含义。

配置层示例字段负责内容
出口标识tag供路由的 outboundTag 引用
代理协议protocol如 freedom、blackhole、VMess、VLESS、Trojan 或 Shadowsocks 对应的协议实现
协议参数settings按出口协议提供目标、用户或其他协议设置
传输参数streamSettings为支持的代理出口配置传输方式与传输安全

添加远端代理出口时,协议、服务端地址、端口、身份参数与传输设置必须互相匹配。不能只把 freedom 改为 vless 就认为已经配置好节点。TLS 或 REALITY 相关字段属于相应的传输安全配置,不应随意塞进入站 SOCKS 的 settings。

结论:调整出口顺序前先补齐兜底规则

没有命中任何路由规则时,通常使用第一个出站。本例把 direct 放在首位,所以未匹配请求直连;若希望默认代理,应明确设计兜底出口,不能只检查某条规则是否写了代理标签。

routing:规则顺序、标签引用与解析策略

routing.rules 按数组顺序匹配,先命中的规则决定出口。本例第一条把完整域名 blocked.test 送到 block;第二条把列出的 IPv4 网段送到 direct。这些网段只是示例,不是完整的特殊地址集合,也不包含 IPv6。

  1. 请求进入后,内核取得入口标签、目标域名或 IP、端口等可用信息。
  2. 从第一条规则向后检查;同一条规则中的不同条件类别通常需要同时满足。
  3. 同类列表内的候选项通常按“任一匹配”处理,例如命中 ip 数组中的任一网段。
  4. 找到匹配规则后,使用其 outboundTag;没有命中时走默认出口。

full: 表示完整域名匹配,domain: 用于域名及其子域名匹配。需要限制某个入口时,可在规则里增加 inboundTag 数组。引用标签必须与对应对象的 tag 一致;入口标签和出口标签各有用途,不能把 socks-in 当作出站来引用。

routing.domainStrategy域名解析时机阅读规则时的注意点
AsIs不为路由匹配主动解析域名域名目标不能指望仅凭 IP 规则得到分流
IPIfNonMatch域名未匹配到规则后,再解析并尝试匹配过早命中的宽泛规则会阻止后续解析匹配
IPOnDemand匹配过程遇到需要 IP 的规则时触发解析IP 规则的位置会影响解析发生的时机

示例选择 AsIs,因此以域名形式提交的请求不会仅为匹配第二条 IP 规则而解析。不过本例默认出口仍是直连,所以看见请求直连,并不能反推它命中了私有网段规则。排查规则时应看实际匹配和出口,而不只看最终能否打开页面。

dns:分清路由解析与连接解析

配置 dns 不等于接管了所有应用的 DNS。应用可能先自行解析,再把 IP 交给代理;也可能把域名交给 SOCKS 或 HTTP 入口。路由能获得哪些信息,首先取决于入口实际收到什么。

本例的 dns.servers 使用特殊值 localhost,表示通过本地系统解析器解析,不是指定一台运行在本机的 DNS 服务器。它也没有创建 UDP 53 监听端口。若要向应用提供 DNS 服务,需要另行设计接收 DNS 请求的入口和处理路径。

本例在 freedom 出口设置 UseIP,让直连出口对域名使用内置 DNS 解析流程。这与路由的 AsIs 不冲突:前者发生在出口准备连接时,后者约束的是规则匹配阶段。即使出口后来得到了 IP,也不会自动重新执行已经结束的路由选择。

结论:先确认应用提交的是域名还是 IP

域名规则未命中时,先检查应用是否已经本地解析。不要同时修改路由策略、DNS 服务器和出口协议;每次只改变一层,才能判断是哪一步改变了结果。

验证与排错:从配置检查到实际连接

先用内核自带的检查命令验证配置,再启动监听,最后让应用接入。以下命令在能找到 xray 可执行文件的终端中运行;若文件不在命令搜索路径中,应使用其实际路径。先查看版本和帮助,可以确认当前二进制所支持的参数。

xray version
xray run -help
xray run -test -config ./config.json
xray run -config ./config.json

配置检查通过只说明内核接受这份配置,不代表远端服务可达,也不代表应用已经使用代理。需要做可重复的本地测试时,可以先在另一个终端启动测试服务,再分别通过两个入口访问它:

python -m http.server 8000 --bind 127.0.0.1
curl --noproxy "" --proxy socks5h://127.0.0.1:10808 http://127.0.0.1:8000/
curl --noproxy "" --proxy http://127.0.0.1:10809 http://127.0.0.1:8000/

测试需要本机已安装 Python 和 curl。响应来自本地测试目录,验证的是“应用接入入口、路由选择、直连出口”这条链路。--noproxy "" 用于避免已有绕过代理设置跳过本次入口测试。测试完成后停止临时服务,不要把终端中的目录清单当作代理节点测速结果。

配置检查通过,为什么一启动就退出?

检查控制台是否提示监听失败。确认 10808、10809 未被占用,必要时改为 11808、11809,并同步修改应用代理端口。

加了域名规则,为什么还是走默认出口?

先确认请求携带域名,再检查规则是否被更早的通用规则截获。核对 full: 的完整匹配范围,以及 outboundTag 是否引用了正确出口。

在 v2rayN 里改了运行文件,重启后怎么没了?

客户端可能重新生成运行配置。先保留独立副本,再通过当前版本提供的自定义配置入口加载,或在客户端对应的路由、DNS 设置中修改,不把临时运行文件当作长期配置来源。

能把这份 JSON 直接导入所有客户端吗?

先确认导入入口接受的是原生配置还是节点分享内容。v2rayNG 使用 Xray 内核,v2flyNG 使用 v2fly 内核;完整配置的兼容性仍取决于内核版本、字段支持与客户端的加载方式。

完成基线验证后,再加入远端代理出口,并为它设置明确的路由。每次只改一个部分,保留能运行的上一份配置。这样出现问题时,可以把范围收敛到入口、规则、解析或远端连接,而不是在多个无关设置之间反复切换。

下载v2rayN