Xray JSON – Advanced
概述
在 Remnawave 中,XRAY_JSON 类型的订阅模板提供了 Remnawave 指令 — 这些是您添加到 JSON 模板中的特殊指令。面板在生成订阅时会处理它们,并从最终配置中删除 — 客户端永远不会看到它们。
目前可用的指令是 injectHosts,允许将主机的 outbound 配置动态注入到模板中。当您需要构建带有负载均衡器、自定义路由或多个 outbound 的复杂 Xray 配置时,这非常有用,而连接数据(地址、端口、密钥)将从面板自动注入。
以下呈现的配置是用于演示注入机制的示例。请根据您的需求进行调整。
需要 Remnawave 版本 2.6.3 或更高版本。
工作条件
- 虚拟主机(分配了注入模板的主机)必须已启用且未隐藏。
- 注入主机(通过
selector选择的主机)必须已启用。默认情况下,只选择隐藏的主机(可通过selectFrom更改此行为)。 - 所有主机 — 包括虚拟主机和注入主机 — 必须对最终用户可访问:它们绑定的 inbound 必须在用户的小队中启用。
- 备注 (remark) 和服务器描述 (Server Description,如果设置了) 将从虚拟主机传入最终配置。
remnawave 结构
remnawave 对象添加到 JSON 模板的根级别。它支持以下字段:
| 字段 | 描述 |
|---|---|
injectHosts | 注入组数组。每个组包含用于选择主机的选择器和标签形成参数。 |
addVirtualHostAsOutbound | 如果为 true — 虚拟主机将作为带有 proxy 标签的 outbound 添加到 outbounds 数组的开头。默认为 false。参见 addVirtualHostAsOutbound。 |
injectHosts 字段是注入组的数组。每个组包含用于选择主机的选择器和自己的 tagPrefix:
"remnawave": {
"injectHosts": [
{
"selector": { "type": "uuids", "values": ["uuid-хоста-1", "uuid-хоста-2"] },
"tagPrefix": "proxy"
},
{
"selector": { "type": "remarkRegex", "pattern": "^RU-" },
"tagPrefix": "backup"
}
]
},
injectHosts 数组的每个元素:
| 字段 | 描述 |
|---|---|
selector | 定义将选择哪些主机的对象。必填字段。 |
selectFrom | 从哪个主机池中选择:"HIDDEN"(默认)、"NOT_HIDDEN" 或 "ALL"。 |
tagPrefix | 创建的 outbound 的标签前缀。参见标签形成规则。 |
useHostRemarkAsTag | 如果为 true — outbound 的标签将是主机的备注 (remark)。 |
useHostTagAsTag | 如果为 true — outbound 的标签将是主机标签(如果标签未设置,则使用备注)。 |
必须指定三个字段中的恰好一个:tagPrefix、useHostRemarkAsTag 或 useHostTagAsTag。
可以有任意数量的组 — 每个组形成带有自己前缀的独立 outbound 集合。例如,这允许为每组服务器设置单独的负载均衡器。
选择器类型
uuids
通过 UUID 列表选择主机。UUID 的顺序决定 outbound 的顺序。
"selector": {
"type": "uuids",
"values": [
"8478b271-95d3-4312-85ae-ecf63fb53d1d",
"d31d6161-1315-4c1e-9a4b-141ab1c022f6"
]
}
remarkRegex
选择备注 (remark) 与正则表达式匹配的主机。语法为 JavaScript RegExp。
"selector": {
"type": "remarkRegex",
"pattern": "^Балансер"
}
上面的示例将选择所有备注以 "Балансер" 开头的隐藏主机(例如 "Балансер #1"、"Балансер RU")。
tagRegex
选择主机标签(主机设置中的 tag 字段)与正则表达式匹配的主机。
"selector": {
"type": "tagRegex",
"pattern": "^balancer-"
}
上面的示例将选择所有标签以 balancer- 开头的隐藏主机。
sameTagAsRecipient
选择所有主机标签与虚拟主机标签匹配的隐藏主机。不需要额外参数。
"selector": {
"type": "sameTagAsRecipient"
}
当您想自动对主机进行分组时很方便:只需为虚拟主机和注入主机分配相同的标签即可。
默认情况下,所有选择器只处理隐藏的主机。要更改此行为,请使用 selectFrom 字段:"NOT_HIDDEN" 值只选择可见的主机(已启用但未隐藏),"ALL" — 所有主机(已启用,已隐藏)。
标签形成规则
outbound 的标签由注入组中指定的三个字段中的哪一个决定:
tagPrefix — 第一个主机获得等于 tagPrefix 的标签。此后每个主机获得 {tagPrefix}-{N},从 2 开始。
三个主机使用 tagPrefix: "proxy" 的示例:
| 顺序 | outbound 标签 |
|---|---|
| 第1个 | proxy |
| 第2个 | proxy-2 |
| 第3个 | proxy-3 |
useHostRemarkAsTag — 每个 outbound 获得等于主机备注 (remark) 的标签。
{
"selector": { "type": "tagRegex", "pattern": "^ru-" },
"useHostRemarkAsTag": true
}
如果主机的备注是"莫斯科"、"圣彼得堡"、"喀山" — outbound 将获得 莫斯科、圣彼得堡、喀山 标签。
useHostTagAsTag — 每个 outbound 获得等于主机标签的标签。如果主机标签未设置,则使用其备注。
{
"selector": { "type": "tagRegex", "pattern": "^ru-" },
"useHostTagAsTag": true
}
Xray 中的前缀匹配
Xray 中的 selector(在 routing.balancers 中)和 subjectSelector(在 burstObservatory 中)字段作为前缀匹配器工作 — 它们与 outbound 标签的开头匹配,而不是与其精确值匹配。
例如,如果配置中有标签为 proxy、proxy-2、proxy-3、direct 的 outbound:
| selector / subjectSelector 值 | 将选择哪些 outbound |
|---|---|
["proxy"] | proxy、proxy-2、proxy-3 |
["proxy-"] | proxy-2、proxy-3 |
"selector": ["proxy"]— 将捕获所有注入的 outbound,包括第一个。"selector": ["proxy-"]— 将捕获除第一个之外的所有(仅proxy-2、proxy-3、...)。
第一个选择的主机始终获得没有 -{N} 后缀的标签(简单地为 proxy)。这允许将其用作负载均衡器中的 fallbackTag:如果 selector 中的所有 outbound 都不可用,流量将转到第一个主机。为此,设置 "selector": ["proxy-"](仅 proxy-2、proxy-3、...)和 "fallbackTag": "proxy"。
addVirtualHostAsOutbound
默认情况下,使用 remnawave 指令时,最终配置中只出现注入的主机。虚拟主机本身(recipient)仅用作 remarks 和 serverDescription 的来源。
如果您需要虚拟主机也成为带有 proxy 标签的 outbound,请在 remnawave 对象级别添加字段 addVirtualHostAsOutbound: true:
"remnawave": {
"addVirtualHostAsOutbound": true,
"injectHosts": [
{
"selector": { "type": "uuids", "values": ["uuid-хоста-1", "uuid-хоста-2"] },
"tagPrefix": "proxy"
},
{
"selector": { "type": "remarkRegex", "pattern": "^RU-" },
"tagPrefix": "backup"
}
]
}
在这种情况下,最终 outbounds 数组将如下所示:
- 带有
proxy标签的虚拟主机 Outbound。 - 注入的 outbound(来自
injectHosts)。 - 模板中的静态 outbound(
direct、block等)。
当路由规则使用 "outboundTag": "proxy" 通过主要主机路由流量,而注入的主机处理单独的流量组(例如,通过负载均衡器)时,这很有用。
addVirtualHostAsOutbound 可以与 injectHosts 一起使用,也可以不使用。如果 injectHosts 未指定或为空,则只有虚拟主机的 outbound 会被添加到配置中。
分步示例:带三个主机的负载均衡器
在此示例中,我们将创建一个配置,其中三个 outbound 使用 leastLoad 策略组合成负载均衡器,并由 Observatory 监控。
步骤 1. 创建主机
在面板中创建将参与注入的主机。在我们的示例中:
- Virtual Host — 将分配注入模板的虚拟主机。未隐藏,最终用户通过它获取配置。
- Balancer #1、Balancer #2、Balancer #3 — outbound 将注入模板的主机。
步骤 2. 隐藏注入主机
打开每个负载均衡器主机的卡片(Balancer #1、#2、#3),进入 Advanced 部分并启用 Hide Host 开关。
隐藏的主机不会出现在普通订阅中 — 它们只能通过注入机制访问。
步骤 3. 创建订阅模板
创建 XRAY_JSON 类型的订阅模板。在其中描述完整配置:dns、routing、inbounds、outbounds、burstObservatory 及其他所需部分。
在 outbounds 数组中只放静态 outbound(direct、block)— 注入主机的 outbound 将自动添加。
在 JSON 根级别添加带有隐藏主机选择器的 remnawave 对象。
模板示例
{
"remnawave": {
"injectHosts": [
{
"selector": {
"type": "uuids",
"values": [
"8478b271-95d3-4312-85ae-ecf63fb53d1d",
"d31d6161-1315-4c1e-9a4b-141ab1c022f6",
"5749f69e-cd1b-4012-9407-450434085196"
]
},
"tagPrefix": "proxy"
}
]
},
"burstObservatory": {
"pingConfig": {
"timeout": "3s",
"interval": "1m",
"sampling": 1,
"destination": "http://www.gstatic.com/generate_204",
"connectivity": ""
},
"subjectSelector": ["proxy"]
},
"dns": {
"servers": ["1.1.1.1", "1.0.0.1"],
"queryStrategy": "UseIP"
},
"routing": {
"balancers": [
{
"tag": "Super_Balancer",
"selector": ["proxy"],
"strategy": {
"type": "leastLoad",
"settings": {
"maxRTT": "1s",
"expected": 2,
"baselines": ["1s"],
"tolerance": 0.01
}
},
"fallbackTag": "direct"
}
],
"rules": [
{
"protocol": ["bittorrent"],
"outboundTag": "direct"
},
{
"network": "tcp,udp",
"balancerTag": "Super_Balancer"
}
],
"domainMatcher": "hybrid",
"domainStrategy": "IPIfNonMatch"
},
"inbounds": [
{
"tag": "socks",
"port": 10808,
"listen": "127.0.0.1",
"protocol": "socks",
"settings": {
"udp": true,
"auth": "noauth"
},
"sniffing": {
"enabled": true,
"routeOnly": false,
"destOverride": ["http", "tls", "quic"]
}
},
{
"tag": "http",
"port": 10809,
"listen": "127.0.0.1",
"protocol": "http",
"settings": {
"allowTransparent": false
},
"sniffing": {
"enabled": true,
"routeOnly": false,
"destOverride": ["http", "tls", "quic"]
}
}
],
"outbounds": [
{
"tag": "direct",
"protocol": "freedom"
},
{
"tag": "block",
"protocol": "blackhole"
}
]
}
请注意:
"subjectSelector": ["proxy"]— Observatory 将监控标签以proxy开头的所有 outbound(即proxy、proxy-2、proxy-3)。"selector": ["proxy"]—Super_Balancer负载均衡器将在相同的 outbound 之间分配流量。- 模板的
outbounds中只指定了direct和block— 主机的 outbound 将自动添加在它们之前。
步骤 4. 将模板分配给虚拟主机
打开虚拟主机 (Virtual Host) 的卡片,进入 Advanced 部分,在 Xray JSON Template 字段中选择创建的模板。
确保虚拟主机的 Hide Host 开关已关闭 — 它应该在订阅中可见。
步骤 5. 结果
请求订阅时,面板会自动:
- 获取分配给虚拟主机的模板。
- 从中删除
remnawave对象。 - 对于
injectHosts中的每个组,通过selector选择隐藏主机并组装其 outbound。 - 将 outbound 插入到
outbounds数组的开头。 - 从虚拟主机的备注设置
remarks。
客户端收到的最终配置
[
{
"dns": {
"servers": ["1.1.1.1", "1.0.0.1"],
"queryStrategy": "UseIP"
},
"routing": {
"rules": [
{
"protocol": ["bittorrent"],
"outboundTag": "direct"
},
{
"network": "tcp,udp",
"balancerTag": "Super_Balancer"
}
],
"balancers": [
{
"tag": "Super_Balancer",
"selector": ["proxy"],
"strategy": {
"type": "leastLoad",
"settings": {
"maxRTT": "1s",
"expected": 2,
"baselines": ["1s"],
"tolerance": 0.01
}
},
"fallbackTag": "direct"
}
],
"domainMatcher": "hybrid",
"domainStrategy": "IPIfNonMatch"
},
"inbounds": [
{
"tag": "socks",
...omitted...
},
{
"tag": "http",
...omitted...
}
],
"outbounds": [
{
"tag": "proxy",
"protocol": "vless",
"settings": {...omitted...},
"streamSettings": {...omitted...}
},
{
"tag": "proxy-2",
"protocol": "vless",
"settings": {...omitted...},
"streamSettings": {...omitted...}
},
{
"tag": "proxy-3",
"protocol": "vless",
"settings": {...omitted...},
"streamSettings": {...omitted...}
},
{
"tag": "direct",
"protocol": "freedom"
},
{
"tag": "block",
"protocol": "blackhole"
}
],
"burstObservatory": {
"pingConfig": {
"timeout": "3s",
"interval": "1m",
"sampling": 1,
"destination": "http://www.gstatic.com/generate_204",
"connectivity": ""
},
"subjectSelector": ["proxy"]
},
"remarks": "Virtual Host"
}
]
发生了什么:
remnawave对象已从最终配置中删除。- 三个 outbound(
proxy、proxy-2、proxy-3)被插入到outbounds数组的开头,在direct和block之前。 - 负载均衡器中的
"selector": ["proxy"]自动捕获了所有三个 outbound,因为它们的标签以proxy开头(前缀匹配)。 - Observatory 中的
"subjectSelector": ["proxy"]同样捕获了所有三个 outbound 进行监控。 "remarks": "Virtual Host"— 取自虚拟主机的备注。
虚拟主机地址和实际 inbound
在此场景中,虚拟主机作为模板和元数据(备注、服务器描述)的"包装器",而不是实际的连接点。
在其设置中可以指定任何地址(例如 balancer.host.com)— 它不参与用户的实际连接。
实际入口点是注入主机的特定 inbound。重要的是,请求订阅的用户通过小队可以访问此 inbound,否则虚拟主机根本不会出现在他们的订阅中。
实际连接参数(地址、端口、密钥等)取自注入主机,其 outbound 配置被注入到客户端的最终配置中。
重要说明
- 虚拟主机必须已启用且未隐藏。 正是它决定将使用哪个模板,
remarks和description都取自它。 - 注入主机必须已启用。 默认只选择隐藏主机(
selectFrom: "HIDDEN")。此行为可以更改为"NOT_HIDDEN"或"ALL"。如果主机被禁用或未通过选择器找到 — 将被跳过。 - 所有参与主机必须对最终用户可访问 — 它们绑定的 inbound 必须在用户的小队中启用。
remnawave对象将被删除 — 客户端不会看到它。- Outbound 添加到开头
outbounds数组。如果启用了addVirtualHostAsOutbound,带有proxy标签的虚拟主机 outbound 排在第一位,然后是注入的,然后是模板中的静态 outbound(direct、block)。 - 主机顺序决定 outbound 的顺序和分配给它们的标签。对于
uuids选择器 —values数组中的 UUID 顺序。可以使用useHostRemarkAsTag或useHostTagAsTag代替tagPrefix,以便从主机属性生成标签。 - 模板选择和主机隐藏在主机卡片的 Advanced 部分。