Xray JSON – Advanced
Descripción general
Para las plantillas de suscripción de tipo XRAY_JSON en Remnawave, se proporcionan directivas Remnawave — instrucciones especiales que se agregan a la plantilla JSON. El panel las procesa al generar la suscripción y las elimina de la configuración final — el cliente nunca las verá.
Actualmente está disponible la directiva injectHosts, que permite insertar dinámicamente las configuraciones de outbound de los hosts en la plantilla. Esto es útil cuando necesita construir una configuración Xray compleja con balanceadores de carga, enrutamiento personalizado o varios outbounds, con los datos de conexión (dirección, puerto, claves) insertados automáticamente desde el panel.
Las configuraciones presentadas a continuación son ejemplos para demostrar el mecanismo de inyección. Adáptelas a sus necesidades.
Requiere Remnawave versión 2.6.3 o más reciente.
Condiciones de funcionamiento
- El host virtual (el host al que se le asigna la plantilla con inyección) debe estar habilitado y no oculto.
- Los hosts a inyectar (seleccionados a través de
selector) deben estar habilitados. Por defecto solo se seleccionan los hosts ocultos (el comportamiento se puede cambiar a través deselectFrom). - Todos los hosts — tanto el virtual como los a inyectar — deben ser accesibles para el usuario final: el inbound al que están vinculados debe estar incluido en el squad del usuario.
- Del host virtual pasan a la configuración final la observación (remark) y la descripción del servidor (Server Description, si está configurada).
Estructura de remnawave
El objeto remnawave se agrega al nivel raíz de la plantilla JSON. Admite los siguientes campos:
| Campo | Descripción |
|---|---|
injectHosts | Array de grupos de inyección. Cada grupo contiene un selector para la selección de hosts y parámetros de formación de tags. |
addVirtualHostAsOutbound | Si es true — el host virtual se agregará como outbound con el tag proxy al inicio del array outbounds. Por defecto es false. Ver addVirtualHostAsOutbound. |
El campo injectHosts es un array de grupos de inyección. Cada grupo contiene un selector para la selección de hosts y su propio tagPrefix:
"remnawave": {
"injectHosts": [
{
"selector": { "type": "uuids", "values": ["uuid-host-1", "uuid-host-2"] },
"tagPrefix": "proxy"
},
{
"selector": { "type": "remarkRegex", "pattern": "^RU-" },
"tagPrefix": "backup"
}
]
},
Cada elemento del array injectHosts:
| Campo | Descripción |
|---|---|
selector | Objeto que define qué hosts serán seleccionados. Campo obligatorio. |
selectFrom | De qué grupo seleccionar hosts: "HIDDEN" (por defecto), "NOT_HIDDEN" o "ALL". |
tagPrefix | Prefijo de tag para los outbounds creados. Ver reglas de formación de tags. |
useHostRemarkAsTag | Si es true — el tag del outbound será la observación (remark) del host. |
useHostTagAsTag | Si es true — el tag del outbound será el tag del host (si no se establece un tag, se usa la observación). |
Se debe especificar exactamente uno de los tres campos: tagPrefix, useHostRemarkAsTag o useHostTagAsTag.
Puede haber cualquier número de grupos — cada uno forma su propio conjunto independiente de outbounds con su propio prefijo. Esto permite, por ejemplo, crear un balanceador de carga separado para cada grupo de servidores.
Tipos de selectores
uuids
Selecciona hosts por una lista de UUID. El orden de los UUID determina el orden de los outbounds.
"selector": {
"type": "uuids",
"values": [
"8478b271-95d3-4312-85ae-ecf63fb53d1d",
"d31d6161-1315-4c1e-9a4b-141ab1c022f6"
]
}
remarkRegex
Selecciona hosts cuya observación (remark) coincide con la expresión regular. Sintaxis — JavaScript RegExp.
"selector": {
"type": "remarkRegex",
"pattern": "^Balancer"
}
El ejemplo anterior seleccionará todos los hosts ocultos cuya observación comience con «Balancer» (por ejemplo, «Balancer #1», «Balancer RU»).
tagRegex
Selecciona hosts cuyo tag de host (campo tag en la configuración del host) coincide con la expresión regular.
"selector": {
"type": "tagRegex",
"pattern": "^balancer-"
}
El ejemplo anterior seleccionará todos los hosts ocultos con un tag que comience con balancer-.
sameTagAsRecipient
Selecciona todos los hosts ocultos cuyo tag de host coincide con el tag del host virtual. No requiere parámetros adicionales.
"selector": {
"type": "sameTagAsRecipient"
}
Conveniente cuando desea agrupar hosts automáticamente: basta con asignar el mismo tag al host virtual y a los hosts a inyectar.
Por defecto, todos los selectores trabajan solo con hosts ocultos. Para cambiar este comportamiento, use el campo selectFrom: el valor "NOT_HIDDEN" seleccionará solo los hosts visibles (habilitados, pero no ocultos), y "ALL" — todos los hosts (habilitados, ocultos).
Reglas de formación de tags
El tag de un outbound se determina por cuál de los tres campos está especificado en el grupo de inyección:
tagPrefix — El primer host recibe un tag igual a tagPrefix. Cada siguiente — {tagPrefix}-{N}, comenzando desde 2.
Ejemplo para tres hosts con tagPrefix: "proxy":
| Orden | Tag del outbound |
|---|---|
| 1.° | proxy |
| 2.° | proxy-2 |
| 3.° | proxy-3 |
useHostRemarkAsTag — Cada outbound recibe un tag igual a la observación (remark) del host.
{
"selector": { "type": "tagRegex", "pattern": "^ru-" },
"useHostRemarkAsTag": true
}
Si los hosts tienen las observaciones «Moscú», «Petersburgo», «Kazán» — los outbounds recibirán los tags Moscú, Petersburgo, Kazán.
useHostTagAsTag — Cada outbound recibe un tag igual al tag del host. Si no se establece el tag del host, se usa su observación.
{
"selector": { "type": "tagRegex", "pattern": "^ru-" },
"useHostTagAsTag": true
}
Coincidencia por prefijo en Xray
Los campos selector (en routing.balancers) y subjectSelector (en burstObservatory) en Xray funcionan como comparadores de prefijo — se comparan con el inicio del tag del outbound, no con su valor exacto.
Por ejemplo, si la configuración contiene outbounds con los tags proxy, proxy-2, proxy-3, direct:
| Valor de selector / subjectSelector | Qué outbounds serán seleccionados |
|---|---|
["proxy"] | proxy, proxy-2, proxy-3 |
["proxy-"] | proxy-2, proxy-3 |
"selector": ["proxy"]— capturará todos los outbounds inyectados, incluido el primero."selector": ["proxy-"]— capturará todos excepto el primero (soloproxy-2,proxy-3, ...).
El primer host seleccionado siempre recibe un tag sin el sufijo -{N} (simplemente proxy). Esto permite usarlo como fallbackTag en el balanceador de carga: si todos los outbounds del selector no están disponibles, el tráfico irá al primer host. Para ello, configure "selector": ["proxy-"] (solo proxy-2, proxy-3, ...) y "fallbackTag": "proxy".
addVirtualHostAsOutbound
Por defecto, al usar la directiva remnawave, solo los hosts inyectados entran en la configuración final. El host virtual (recipient) en sí se usa solo como fuente de remarks y serverDescription.
Si necesita que el host virtual también se convierta en un outbound con el tag proxy, agregue el campo addVirtualHostAsOutbound: true en el nivel del objeto remnawave:
"remnawave": {
"addVirtualHostAsOutbound": true,
"injectHosts": [
{
"selector": { "type": "uuids", "values": ["uuid-host-1", "uuid-host-2"] },
"tagPrefix": "proxy"
},
{
"selector": { "type": "remarkRegex", "pattern": "^RU-" },
"tagPrefix": "backup"
}
]
}
En este caso, el array outbounds final se verá así:
- Outbound del host virtual con el tag
proxy. - Outbounds inyectados (de
injectHosts). - Outbounds estáticos de la plantilla (
direct,blocketc.).
Esto es útil cuando en las reglas de routing se usa "outboundTag": "proxy" para dirigir el tráfico a través del host principal, mientras que los hosts inyectados atienden grupos de tráfico separados (por ejemplo, a través de balanceadores de carga).
addVirtualHostAsOutbound se puede usar junto con injectHosts o sin ellos. Si injectHosts no está especificado o está vacío, solo se agregará el outbound del host virtual a la configuración.
Ejemplo paso a paso: balanceador de carga con tres hosts
En este ejemplo crearemos una configuración en la que tres outbounds se combinan en un balanceador de carga con la estrategia leastLoad y son monitoreados por un observatory.
Paso 1. Crear los hosts
Cree en el panel los hosts que participarán en la inyección. En nuestro ejemplo son:
- Virtual Host — el host virtual al que se le asignará la plantilla con inyección. No está oculto y el usuario final recibirá la configuración a través de él.
- Balancer #1, Balancer #2, Balancer #3 — hosts cuyos outbounds serán insertados en la plantilla.
Paso 2. Ocultar los hosts a inyectar
Abra la tarjeta de cada host balanceador (Balancer #1, #2, #3), vaya a la sección Avanzado y habilite el interruptor Ocultar host.
Los hosts ocultos no aparecen en la suscripción normal — solo son accesibles a través del mecanismo de inyección.
Paso 3. Crear la plantilla de suscripción
Cree una plantilla de suscripción de tipo XRAY_JSON. Describa en ella la configuración completa: dns, routing, inbounds, outbounds, burstObservatory y otras secciones necesarias.
Coloque en el array outbounds solo los outbounds estáticos (direct, block) — los outbounds de los hosts inyectados se agregarán automáticamente.
En el nivel raíz del JSON agregue el objeto remnawave con el selector de hosts ocultos.
Ejemplo de plantilla
{
"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"
}
]
}
Observe:
"subjectSelector": ["proxy"]— el observatory monitoreará todos los outbounds cuyo tag comience conproxy(es decir,proxy,proxy-2,proxy-3)."selector": ["proxy"]— el balanceador de cargaSuper_Balancerdistribuirá el tráfico entre los mismos outbounds.- En el
outboundsde la plantilla solo se indicandirectyblock— los outbounds de los hosts se agregarán automáticamente antes de ellos.
Paso 4. Asignar la plantilla al host virtual
Abra la tarjeta del host virtual (Virtual Host), vaya a la sección Avanzado y en el campo Plantilla Xray JSON seleccione la plantilla creada.
Asegúrese de que el interruptor Ocultar host para el host virtual esté deshabilitado — debe ser visible en la suscripción.
Paso 5. Resultado
Al solicitar la suscripción, el panel automáticamente:
- Toma la plantilla asignada al host virtual.
- Elimina el objeto
remnawavede ella. - Para cada grupo en
injectHostsselecciona los hosts ocultos porselectory recopila sus outbounds. - Inserta los outbounds al inicio del array
outbounds. - Establece
remarksdesde la observación del host virtual.
Configuración final que recibirá el cliente
[
{
"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"
}
]
Lo que sucedió:
- El objeto
remnawavefue eliminado de la configuración final. - Tres outbounds (
proxy,proxy-2,proxy-3) fueron insertados al inicio del arrayoutbounds, antes dedirectyblock. "selector": ["proxy"]en el balanceador de carga capturó automáticamente los tres outbounds, ya que sus tags comienzan conproxy(coincidencia por prefijo)."subjectSelector": ["proxy"]en el observatory capturó igualmente los tres outbounds para su monitoreo."remarks": "Virtual Host"— tomado de la observación del host virtual.
Dirección del host virtual e inbound real
El host virtual en este escenario sirve como «envoltorio» para la plantilla y los metadatos (observación, descripción del servidor), no como un punto de conexión real.
En su configuración se puede indicar cualquier dirección (por ejemplo, balancer.host.com) — no participa en la conexión real del usuario.
El punto de entrada real es el inbound específico de los hosts inyectados. Es importante que el usuario que solicita la suscripción tenga acceso a ese inbound a través de los squads, de lo contrario el host virtual no aparecerá en su suscripción.
Los parámetros de conexión reales (direcciones, puertos, claves, etc.) se toman de los hosts inyectados, cuyas configuraciones de outbound se insertan en la configuración final del lado del cliente.
Notas importantes
- El host virtual debe estar habilitado y no oculto. Es él quien determina qué plantilla se utilizará, y de él se toman
remarksydescription. - Los hosts a inyectar deben estar habilitados. Por defecto solo se seleccionan los hosts ocultos (
selectFrom: "HIDDEN"). Este comportamiento se puede cambiar a"NOT_HIDDEN"o"ALL". Si un host está deshabilitado o no se encuentra por el selector — será omitido. - Todos los hosts participantes deben ser accesibles para el usuario final — el inbound al que están vinculados debe estar incluido en el squad del usuario.
- El objeto
remnawavees eliminado de la configuración final — el cliente no lo verá. - Los outbounds se agregan al inicio del array
outbounds. SiaddVirtualHostAsOutboundestá habilitado, el outbound del host virtual con el tagproxyva primero, luego los inyectados, luego los outbounds estáticos de la plantilla (direct,block). - El orden de los hosts determina el orden de los outbounds y los tags asignados. Para el selector
uuids— el orden de los UUID en el arrayvalues. En lugar detagPrefixse puede usaruseHostRemarkAsTagouseHostTagAsTagpara que los tags se formen a partir de las propiedades de los hosts. - La selección de plantilla y el ocultamiento del host se encuentran en la sección Avanzado en la tarjeta del host.