# Xray JSON – Advanced

**URL:** https://f.docs.rw/t/topic/208
**Category:** Блог
**Created:** 2026-06-17T00:57:25Z
**Posts:** 1

## Post 1 by @remnawave — 2026-06-17T00:57:25Z

## **Обзор**

Для шаблонов подписки типа **XRAY\_JSON** в Remnawave предусмотрены **Remnawave-директивы** — специальные инструкции, которые вы добавляете в JSON-шаблон. Панель обрабатывает их при генерации подписки и удаляет из итогового конфига — клиент их никогда не увидит.

На данный момент доступна директива `injectHosts`, позволяющая динамически подставлять outbound-конфигурации хостов в шаблон. Это полезно, когда вам нужно собрать сложную конфигурацию Xray с балансировщиками, кастомным роутингом или несколькими outbound’ами, при этом данные подключения (адрес, порт, ключи) подставятся автоматически из панели.

> [!tip] Совет  
> Представленные ниже конфигурации являются **примерами** для демонстрации механизма инжекта. Адаптируйте их под свои нужды.

## **Условия работы**

- **Виртуальный хост** (хост, которому назначен шаблон с инжектом) должен быть **включён** и **не скрыт**.
- **Инжектируемые хосты** (выбранные через `selector`) должны быть **включены**. По умолчанию выбираются только **скрытые** хосты (поведение можно изменить через `selectFrom`).
- **Все хосты** — и виртуальный, и инжектируемые — должны быть доступны конечному пользователю: инбаунд, к которому они привязаны, должен быть включён в сквад пользователя.
- Из виртуального хоста в итоговый конфиг попадают **примечание** (remark) и **описание сервера** (Server Description, если задано).

## **Структура remnawave**

Объект `remnawave` добавляется на корневой уровень JSON-шаблона. Он поддерживает следующие поля:

| **Поле** | **Описание** |
| --- | --- |
| `injectHosts` | Массив групп инжекта. Каждая группа содержит **селектор** для выбора хостов и параметры формирования тегов. |
| `addVirtualHostAsOutbound` | Если `true` — виртуальный хост будет добавлен как outbound с тегом `proxy` в начало массива `outbounds`. По умолчанию `false`. См. [addVirtualHostAsOutbound](#p-416-addvirtualhostasoutbound-11). |

Поле `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’ов. См. [правила формирования тегов](#p-416-h-9). |
| `useHostRemarkAsTag` | Если `true` — тегом outbound’а будет **примечание** (remark) хоста. |
| `useHostTagAsTag` | Если `true` — тегом outbound’а будет **тег хоста** (если тег не задан, используется remark). |

> [!warning] Внимание  
> Необходимо указать **ровно одно** из трёх полей: `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"
}
```

Удобно, когда вы хотите автоматически группировать хосты: достаточно присвоить одинаковый тег виртуальному и инжектируемым хостам.

> [!tip] Совет  
> По умолчанию все селекторы работают только со **скрытыми** хостами. Чтобы изменить это поведение, используйте поле `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**

Поля `selector` (в `routing.balancers`) и `subjectSelector` (в `burstObservatory`) в Xray работают как **префиксные матчеры** — они сопоставляются с **началом** тега outbound’а, а не с его точным значением.

Например, если в конфиге есть outbound’ы с тегами `proxy`, `proxy-2`, `proxy-3`, `direct`:

| **Значение selector / subjectSelector** | **Какие outbound’ы будут выбраны** |
| --- | --- |
| `["proxy"]` | `proxy`, `proxy-2`, `proxy-3` |
| `["proxy-"]` | `proxy-2`, `proxy-3` |

- `"selector": ["proxy"]` — подхватит **все** инжектированные outbound’ы, включая первый.
- `"selector": ["proxy-"]` — подхватит все **кроме первого** (только `proxy-2`, `proxy-3`, …).

> [!cite] **Fallback через первый хост**  
> Первый выбранный хост всегда получает тег без суффикса `-{N}` (просто `proxy`). Это позволяет использовать его как `fallbackTag` в балансировщике: если все outbound’ы из `selector` окажутся недоступны, трафик уйдёт на первый хост. Для этого задайте `"selector": ["proxy-"]` (только `proxy-2`, `proxy-3`, …) и `"fallbackTag": "proxy"`.

## **addVirtualHostAsOutbound**

По умолчанию при использовании `remnawave`-директивы в итоговый конфиг попадают **только** инжектированные хосты. Сам виртуальный хост (recipient) используется только как источник `remarks` и `serverDescription`.

Если вам нужно, чтобы виртуальный хост также стал outbound’ом с тегом `proxy`, добавьте поле `addVirtualHostAsOutbound: true` на уровне объекта `remnawave`:

```
"remnawave": {
// success-start
    "addVirtualHostAsOutbound": true,
// success-end
    "injectHosts": [
        {
            "selector": { "type": "uuids", "values": ["uuid-хоста-1", "uuid-хоста-2"] },
            "tagPrefix": "proxy"
        },
        {
            "selector": { "type": "remarkRegex", "pattern": "^RU-" },
            "tagPrefix": "backup"
        }
    ]
}
```

В этом случае итоговый массив `outbounds` будет выглядеть так:

1. **Outbound виртуального хоста** с тегом `proxy`.
2. **Инжектированные outbound’ы** (из `injectHosts`).
3. **Статические outbound’ы** из шаблона (`direct`, `block` и т. д.).

Это полезно, когда в routing-правилах используется `"outboundTag": "proxy"` для направления трафика через основной хост, а инжектированные хосты обслуживают отдельные группы трафика (например, через балансировщики).

> [!tip] Совет  
> `addVirtualHostAsOutbound` можно использовать совместно с `injectHosts` или без них. Если `injectHosts` не указан или пуст, в конфиг будет добавлен только outbound виртуального хоста.

## **Пошаговый пример: балансировщик с тремя хостами**

В этом примере мы создадим конфигурацию, в которой три outbound’а объединены в балансировщик со стратегией `leastLoad` и мониторятся обсерваторией.

### **Шаг 1. Создайте хосты**

Создайте в панели хосты, которые будут участвовать в инжекте. В нашем примере это:

- **Virtual Host** — виртуальный хост, которому будет назначен шаблон с инжектом. Он не скрыт и именно через него конечный пользователь получит конфиг.
- **Balancer #1** , **Balancer #2** , **Balancer #3** — хосты, outbound’ы которых будут подставлены в шаблон.

 ![image](https://f.docs.rw/uploads/default/original/1X/a97e295b99a9e5c2827f2ff01dad161033220b2e.jpeg)

### **Шаг 2. Скройте инжектируемые хосты**

Откройте карточку каждого хоста-балансировщика (Balancer #1, #2, #3), перейдите в раздел **Расширенные** и включите переключатель **Скрыть хост**.

Скрытые хосты не попадают в обычную подписку — они доступны только через механизм инжекта.

 ![image](https://f.docs.rw/uploads/default/original/1X/fd61a4918671b365c34cc922a925524248828fd9.jpeg)

### **Шаг 3. Создайте шаблон подписки**

Создайте шаблон подписки типа **XRAY\_JSON**. В нём опишите полную конфигурацию: `dns`, `routing`, `inbounds`, `outbounds`, `burstObservatory` и другие нужные секции.

В массив `outbounds` поместите только статические outbound’ы (`direct`, `block`) — outbound’ы инжектируемых хостов будут добавлены автоматически.

На корневом уровне JSON добавьте объект `remnawave` с селектором скрытых хостов.

#### **Пример шаблона**

```
{
// success-start
    "remnawave": {
        "injectHosts": [
            {
                "selector": {
                    "type": "uuids",
                    "values": [
                        "8478b271-95d3-4312-85ae-ecf63fb53d1d",
                        "d31d6161-1315-4c1e-9a4b-141ab1c022f6",
                        "5749f69e-cd1b-4012-9407-450434085196"
                    ]
                },
                "tagPrefix": "proxy"
            }
        ]
    },
// success-end
    "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"]` — обсерватория будет мониторить **все** outbound’ы, тег которых начинается с `proxy` (т. е. `proxy`, `proxy-2`, `proxy-3`).
- `"selector": ["proxy"]` — балансировщик `Super_Balancer` будет распределять трафик между теми же outbound’ами.
- В `outbounds` шаблона указаны только `direct` и `block` — outbound’ы хостов добавятся автоматически перед ними.

### **Шаг 4. Назначьте шаблон виртуальному хосту**

Откройте карточку виртуального хоста (Virtual Host), перейдите в раздел **Расширенные** и в поле **Шаблон Xray JSON** выберите созданный шаблон.

Убедитесь, что переключатель **Скрыть хост** для виртуального хоста **выключен** — он должен быть видим в подписке.

 ![image](https://f.docs.rw/uploads/default/original/1X/d8993738fd3a22bb751eafd8f1ef1d1c76b211bc.jpeg)

### **Шаг 5. Результат**

При запросе подписки панель автоматически:

1. Возьмёт шаблон, назначенный виртуальному хосту.
2. Удалит из него объект `remnawave`.
3. Для каждой группы в `injectHosts` выберет скрытые хосты по `selector` и соберёт их outbound’ы.
4. Подставит outbound’ы **в начало** массива `outbounds`.
5. Установит `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": [
            {
// success-start
                "tag": "proxy",
// success-end
                "protocol": "vless",
                "settings": {...omitted...},
                "streamSettings": {...omitted...}
            },
            {
// success-start
                "tag": "proxy-2",
// success-end
                "protocol": "vless",
                "settings": {...omitted...},
                "streamSettings": {...omitted...}
            },
            {
// success-start
                "tag": "proxy-3",
// success-end
                "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` (префиксное сопоставление).
- `"subjectSelector": ["proxy"]` в обсерватории аналогично подхватил все три outbound’а для мониторинга.
- `"remarks": "Virtual Host"` — взято из примечания виртуального хоста.

> [!cite] Заметка  
> **Адрес виртуального хоста и реальный инбаунд**
> 
> Виртуальный хост в этом сценарии служит «обёрткой» для шаблона и метаданных (примечание, описание сервера), а не реальной точкой подключения.  
> В его настройках можно указать **любой адрес** (например, `balancer.host.com`) - он **не участвует в реальном подключении пользователя**.  
> Фактическая точка входа - это **конкретный инбаунд** инжектируемых хостов. Важно, чтобы у пользователя, запрашивающего подписку, был доступ к этому инбаунду через сквады, иначе виртуальный хост в подписке у него вообще не появится.  
> Фактические параметры подключения (адреса, порты, ключи и т. д.) берутся из инжектируемых хостов, чьи outbound-конфигурации подставляются в итоговый конфиг на стороне клиента.

## **Важные замечания**

- **Виртуальный хост должен быть включён и не скрыт.** Именно он определяет, какой шаблон будет использован, и от него берутся `remarks` и `description`.
- **Инжектируемые хосты должны быть включены.** По умолчанию выбираются только скрытые хосты (`selectFrom: "HIDDEN"`). Это поведение можно изменить на `"NOT_HIDDEN"` или `"ALL"`. Если хост выключен или не найден по селектору — он будет пропущен.
- **Все участвующие хосты** должны быть доступны конечному пользователю — инбаунд, к которому они привязаны, должен быть включён в сквад пользователя.
- **Объект `remnawave` удаляется** из итогового конфига — клиент его не увидит.
- **Outbound’ы добавляются в начало** массива `outbounds`. Если включён `addVirtualHostAsOutbound`, outbound виртуального хоста с тегом `proxy` идёт первым, затем — инжектированные, затем — статические outbound’ы из шаблона (`direct`, `block`).
- **Порядок хостов** определяет порядок outbound’ов и присваиваемые им теги. Для селектора `uuids` — порядок UUID в массиве `values`. Вместо `tagPrefix` можно использовать `useHostRemarkAsTag` или `useHostTagAsTag`, чтобы теги формировались из свойств хостов.
- **Выбор шаблона и скрытие хоста** находятся в разделе **Расширенные** в карточке хоста.

* * *
