---
sidebar_position: 3
title: Xray JSON – Advanced
---
## Обзор
Для шаблонов подписки типа **XRAY_JSON** в Remnawave предусмотрены **Remnawave-директивы** — специальные инструкции, которые вы добавляете в JSON-шаблон. Панель обрабатывает их при генерации подписки и удаляет из итогового конфига — клиент их никогда не увидит.
На данный момент доступна директива `injectHosts`, позволяющая динамически подставлять outbound-конфигурации хостов в шаблон. Это полезно, когда вам нужно собрать сложную конфигурацию Xray с балансировщиками, кастомным роутингом или несколькими outbound'ами, при этом данные подключения (адрес, порт, ключи) подставятся автоматически из панели.
:::tip Совет
Представленные ниже конфигурации являются **примерами** для демонстрации механизма инжекта. Адаптируйте их под свои нужды.
:::
:::warning Внимание
Требуется Remnawave версии 2.6.3 или новее.
:::
## Условия работы
- **Виртуальный хост** (хост, которому назначен шаблон с инжектом) должен быть **включён** и **не скрыт**.
- **Инжектируемые хосты** (выбранные через `selector`) должны быть **включены**. По умолчанию выбираются только **скрытые** хосты (поведение можно изменить через `selectFrom`).
- **Все хосты** — и виртуальный, и инжектируемые — должны быть доступны конечному пользователю: инбаунд, к которому они привязаны, должен быть включён в сквад пользователя.
- Из виртуального хоста в итоговый конфиг попадают **примечание** (remark) и **описание сервера** (Server Description, если задано).
## Структура remnawave
Объект `remnawave` добавляется на корневой уровень JSON-шаблона. Он поддерживает следующие поля:
| Поле | Описание |
| -------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `injectHosts` | Массив групп инжекта. Каждая группа содержит **селектор** для выбора хостов и параметры формирования тегов. |
| `addVirtualHostAsOutbound` | Если `true` — виртуальный хост будет добавлен как outbound с тегом `proxy` в начало массива `outbounds`. По умолчанию `false`. См. [addVirtualHostAsOutbound](#addVirtualHostAsOutbound). |
Поле `injectHosts` — это **массив** групп инжекта. Каждая группа содержит **селектор** для выбора хостов и собственный `tagPrefix`:
```json
"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'а будет **тег хоста** (если тег не задан, используется remark). |
:::warning
Необходимо указать **ровно одно** из трёх полей: `tagPrefix`, `useHostRemarkAsTag` или `useHostTagAsTag`.
:::
Групп может быть сколько угодно — каждая формирует свой независимый набор outbound'ов с собственным префиксом. Это позволяет, например, завести отдельный балансировщик для каждой группы серверов.
### Типы селекторов
#### uuids
Выбирает хосты по списку UUID. Порядок UUID определяет порядок outbound'ов.
```json
"selector": {
"type": "uuids",
"values": [
"8478b271-95d3-4312-85ae-ecf63fb53d1d",
"d31d6161-1315-4c1e-9a4b-141ab1c022f6"
]
}
```
#### remarkRegex
Выбирает хосты, у которых **примечание** (remark) совпадает с регулярным выражением. Синтаксис — JavaScript RegExp.
```json
"selector": {
"type": "remarkRegex",
"pattern": "^Балансер"
}
```
Пример выше выберет все скрытые хосты, чьё примечание начинается с «Балансер» (например, «Балансер #1», «Балансер RU»).
#### tagRegex
Выбирает хосты, у которых **тег хоста** (поле tag в настройках хоста) совпадает с регулярным выражением.
```json
"selector": {
"type": "tagRegex",
"pattern": "^balancer-"
}
```
Пример выше выберет все скрытые хосты с тегом, начинающимся на `balancer-`.
#### sameTagAsRecipient
Выбирает все скрытые хосты, у которых **тег хоста** совпадает с тегом виртуального хоста. Не требует дополнительных параметров.
```json
"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) хоста.
```json
{
"selector": { "type": "tagRegex", "pattern": "^ru-" },
"useHostRemarkAsTag": true
}
```
Если хосты имеют примечания «Москва», «Питер», «Казань» — outbound'ы получат теги `Москва`, `Питер`, `Казань`.
**`useHostTagAsTag`** — каждый outbound получает тег, равный **тегу хоста**. Если тег хоста не задан, используется его примечание.
```json
{
"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`, ...).
:::note Fallback через первый хост
Первый выбранный хост всегда получает тег без суффикса `-{N}` (просто `proxy`). Это позволяет использовать его как `fallbackTag` в балансировщике: если все outbound'ы из `selector` окажутся недоступны, трафик уйдёт на первый хост. Для этого задайте `"selector": ["proxy-"]` (только `proxy-2`, `proxy-3`, ...) и `"fallbackTag": "proxy"`.
:::
## addVirtualHostAsOutbound
По умолчанию при использовании `remnawave`-директивы в итоговый конфиг попадают **только** инжектированные хосты. Сам виртуальный хост (recipient) используется только как источник `remarks` и `serverDescription`.
Если вам нужно, чтобы виртуальный хост также стал outbound'ом с тегом `proxy`, добавьте поле `addVirtualHostAsOutbound: true` на уровне объекта `remnawave`:
```json
"remnawave": {
//highlight-next-line-green
"addVirtualHostAsOutbound": true,
"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'ы которых будут подставлены в шаблон.
### Шаг 2. Скройте инжектируемые хосты
Откройте карточку каждого хоста-балансировщика (Balancer #1, #2, #3), перейдите в раздел **Расширенные** и включите переключатель **Скрыть хост**.
Скрытые хосты не попадают в обычную подписку — они доступны только через механизм инжекта.
### Шаг 3. Создайте шаблон подписки
Создайте шаблон подписки типа **XRAY_JSON**. В нём опишите полную конфигурацию: `dns`, `routing`, `inbounds`, `outbounds`, `burstObservatory` и другие нужные секции.
В массив `outbounds` поместите только статические outbound'ы (`direct`, `block`) — outbound'ы инжектируемых хостов будут добавлены автоматически.
На корневом уровне JSON добавьте объект `remnawave` с селектором скрытых хостов.
#### Пример шаблона
```json
{
//highlight-next-line-green
"remnawave": {
//highlight-next-line-green
"injectHosts": [
//highlight-next-line-green
{
//highlight-next-line-green
"selector": {
//highlight-next-line-green
"type": "uuids",
//highlight-next-line-green
"values": [
//highlight-next-line-green
"8478b271-95d3-4312-85ae-ecf63fb53d1d",
//highlight-next-line-green
"d31d6161-1315-4c1e-9a4b-141ab1c022f6",
//highlight-next-line-green
"5749f69e-cd1b-4012-9407-450434085196"
//highlight-next-line-green
]
//highlight-next-line-green
},
//highlight-next-line-green
"tagPrefix": "proxy"
//highlight-next-line-green
}
//highlight-next-line-green
]
},
"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": [
{
"type": "field",
"protocol": ["bittorrent"],
"outboundTag": "direct"
},
{
"type": "field",
"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** выберите созданный шаблон.
Убедитесь, что переключатель **Скрыть хост** для виртуального хоста **выключен** — он должен быть видим в подписке.
### Шаг 5. Результат
При запросе подписки панель автоматически:
1. Возьмёт шаблон, назначенный виртуальному хосту.
2. Удалит из него объект `remnawave`.
3. Для каждой группы в `injectHosts` выберет скрытые хосты по `selector` и соберёт их outbound'ы.
4. Подставит outbound'ы **в начало** массива `outbounds`.
5. Установит `remarks` из примечания виртуального хоста.
#### Итоговый конфиг, который получит клиент
```json
[
{
"dns": {
"servers": ["1.1.1.1", "1.0.0.1"],
"queryStrategy": "UseIP"
},
"routing": {
"rules": [
{
"type": "field",
"protocol": ["bittorrent"],
"outboundTag": "direct"
},
{
"type": "field",
"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": [
{
//highlight-next-line-green
"tag": "proxy",
"protocol": "vless",
"settings": {...omitted...},
"streamSettings": {...omitted...}
},
{
//highlight-next-line-green
"tag": "proxy-2",
"protocol": "vless",
"settings": {...omitted...},
"streamSettings": {...omitted...}
},
{
//highlight-next-line-green
"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` (префиксное сопоставление).
- `"subjectSelector": ["proxy"]` в обсерватории аналогично подхватил все три outbound'а для мониторинга.
- `"remarks": "Virtual Host"` — взято из примечания виртуального хоста.
::::note
**Адрес виртуального хоста и реальный инбаунд**
Виртуальный хост в этом сценарии служит «обёрткой» для шаблона и метаданных (примечание, описание сервера), а не реальной точкой подключения.
В его настройках можно указать **любой адрес** (например, `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`, чтобы теги формировались из свойств хостов.
- **Выбор шаблона и скрытие хоста** находятся в разделе **Расширенные** в карточке хоста.