# VLESS через XHTTP и gRPC: установка и настройка

> Пошаговая настройка VLESS с транспортами XHTTP и gRPC за nginx на своём домене. Что выбрать в 2026 году, готовые конфиги, ссылки для клиентов и разбор ошибок.

XHTTP и gRPC упаковывают VLESS в обычные HTTP/2-запросы к вашему сайту. Снаружи работает nginx с настоящим сертификатом и настоящей страницей, а Xray получает только запросы на секретный адрес. Такой вход пригодится, когда прямой VLESS по TCP у вашего провайдера подвисает или рвётся.

Ниже настройка с чистого сервера: один nginx на порту 443 и оба транспорта рядом, чтобы переключаться между ними простой заменой ссылки в клиенте.

> **XHTTP, gRPC и Reality на OBLAKO.** Эти транспорты, как и Reality, на OBLAKO разрешены для личного VPN для себя и своего домашнего круга, если сервер настроен по нашим инструкциям, а в SNI стоит ваш собственный домен. Сервер, который показывает сертификат популярного чужого сайта, система выключает автоматически. Полные правила описаны в [AUP](https://oblako.sh/ru/docs/aup).

Все конфиги из статьи мы запускали на Ubuntu 24.04 с nginx 1.24 и Xray 26.10.31 в ноябре 2026 года. В каждом варианте через туннель прошло по 20 МБ в обе стороны без искажений, а соединение пережило 130 секунд простоя. Это проверка настройки, а не обхода блокировок: реальное поведение зависит от оператора.

## XHTTP или gRPC {#xhttp-ili-grpc}

| | XHTTP | gRPC |
|---|---|---|
| Статус в Xray | основной транспорт, развивается | объявлен устаревшим, может быть удалён |
| Настройка за nginx | секретный путь | секретное имя сервиса |
| Выбор режима | `packet-up`, `stream-up`, `stream-one` | `gun`, `multi` |
| Клиенты | на ядре Xray | на ядре Xray и sing-box |

Начинайте с XHTTP. При запуске с gRPC сам Xray пишет в лог прямое предупреждение:

```text
The feature gRPC transport (with unnecessary costs, etc.) is deprecated, not recommended
for using and might be removed. Please migrate to XHTTP stream-up H2 as soon as possible.
```

gRPC пока работает, и добавить его почти ничего не стоит: это ещё один блок в конфигах. Держите его как запасной вход и для клиентов без поддержки XHTTP, но проверяйте описание релиза перед обновлением Xray.

## Что известно о работе в России

Данных мало, и почти все они взяты из отдельных сообщений пользователей. Гарантий не даёт ни один транспорт.

- **Оба транспорта не бессмертны.** На Хабре [сообщали](https://habr.com/ru/articles/1047442/), что по состоянию на 5 июня 2026 года XHTTP и gRPC уже попадали под частичные блокировки в Сибири.
- **Иногда спасает смена транспорта.** 13 апреля пользователь ntc.party [описал](https://ntc.party/t/%D1%81%D0%B1%D0%BE%D0%B9-%D0%B8%D0%BB%D0%B8-%D0%B6%D0%B5%D1%81%D1%82%D0%BA%D0%B0%D1%8F-%D0%B1%D0%BB%D0%BE%D0%BA%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B0-%D0%B4%D0%BE%D1%81%D1%82%D1%83%D0%BF%D0%BE%D0%B2-%D0%BA-%D0%B7%D0%B0%D1%80%D1%83%D0%B1%D0%B5%D0%B6%D0%BD%D1%8B%D0%BC-%D1%81%D0%B5%D1%80%D0%B2%D0%B5%D1%80%D0%B0%D0%BC-1004-1104/24071), как на сервере в Германии обрывался XHTTP с Reality, а gRPC с Reality на том же адресе заработал.
- **Иногда не спасает.** В той же теме другой пользователь рассказал, что его gRPC за nginx не работал примерно сутки, с вечера 10 апреля до вечера 11 апреля.
- **Ограничение по адресу транспортом не лечится.** В [заметке о транспортах](https://ntc.party/t/xray-core-%D0%BF%D1%80%D0%BE%D1%82%D0%BE%D0%BA%D0%BE%D0%BB%D1%8B-%D0%B8-%D1%82%D1%80%D0%B0%D0%BD%D1%81%D0%BF%D0%BE%D1%80%D1%82%D0%B0/26533) от 4 ноября отмечено, что некоторые подсети попадают под блок на 16 КБ. Как это проверить, показано [ниже](#esli-provajder-meshaet).
- **Много параллельных соединений заметно.** Участники [обсуждения на net4people](https://github.com/net4people/bbs/issues/546) в конце 2025 года связывали срабатывание с числом одновременных TLS-соединений к одному хосту. Выводы там предварительные, но держать доступ личным и не раздавать его десяткам устройств полезно в любом случае.

Если на мобильном интернете включены белые списки, не поможет ни один из этих вариантов. Про этот случай есть отдельная статья: [белые списки и каскад](https://oblako.sh/wiki/ru/rukovodstva/belye-spiski-kaskad).

## Что нужно перед началом

- VPS с Ubuntu 22.04, 24.04 или Debian 12 и [доступ по SSH](https://oblako.sh/wiki/ru/upravlenie/podklyuchenie-po-ssh).
- Свой домен, A-запись которого указывает на IP сервера. CDN не включайте. Как выбрать подходящее имя, рассказано в статье [Домен для self-steal](https://oblako.sh/wiki/ru/rukovodstva/domen-dlya-self-steal). Слова `vpn`, `proxy`, `node` в имени использовать нельзя.

В командах и конфигах встречаются четыре значения, которые нужно заменить на свои:

| Значение | Откуда взять |
|---|---|
| `ВАШ_ДОМЕН` | ваш домен или поддомен |
| `ВАШ_UUID` | команда `xray uuid` на шаге 3 |
| `ПУТЬ_XHTTP` | команда `openssl rand -hex 8` |
| `ИМЯ_GRPC` | ещё один запуск `openssl rand -hex 8` |

Путь и имя сервиса работают как второй пароль: кто их не знает, увидит только ваш сайт. Не используйте `/xhttp`, `/grpc` или примеры из чужих инструкций.

## Шаг 1. Получите сертификат

```bash
apt update && apt upgrade -y
apt install -y nginx certbot
certbot certonly --webroot -w /var/www/html -d ВАШ_ДОМЕН --deploy-hook "systemctl reload nginx"
```

На этом этапе отвечает стандартная страница nginx, через неё certbot и подтверждает домен.

Сразу создайте страницу, которую увидит случайный посетитель. Лучше написать пару осмысленных строк о себе или проекте, чем оставлять заглушку:

```bash
mkdir -p /var/www/site
nano /var/www/site/index.html
```

## Шаг 2. Настройте nginx

В этой схеме TLS целиком держит nginx. Xray не работает с сертификатами и слушает только локальные порты, поэтому ему не нужен доступ к ключам Let's Encrypt.

Удалите стандартный сайт и создайте `/etc/nginx/sites-available/site`:

```bash
rm /etc/nginx/sites-enabled/default
nano /etc/nginx/sites-available/site
```

```nginx
server {
    listen 80;
    server_name ВАШ_ДОМЕН;

    location /.well-known/acme-challenge/ {
        root /var/www/html;
    }

    location / {
        return 301 https://$host$request_uri;
    }
}

server {
    listen 443 ssl http2;
    server_name ВАШ_ДОМЕН;

    ssl_certificate /etc/letsencrypt/live/ВАШ_ДОМЕН/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/ВАШ_ДОМЕН/privkey.pem;
    ssl_protocols TLSv1.2 TLSv1.3;

    root /var/www/site;
    index index.html;

    client_header_timeout 5m;
    keepalive_timeout 5m;

    location /ПУТЬ_XHTTP/ {
        client_max_body_size 0;
        client_body_timeout 1h;
        grpc_read_timeout 1h;
        grpc_send_timeout 1h;
        grpc_pass grpc://127.0.0.1:10080;
    }

    location /ИМЯ_GRPC/ {
        if ($content_type !~ "^application/grpc") {
            return 404;
        }

        client_max_body_size 0;
        client_body_timeout 1h;
        grpc_read_timeout 1h;
        grpc_send_timeout 1h;
        grpc_pass grpc://127.0.0.1:10081;
    }
}
```

Что здесь важно:

- `grpc_pass` стоит в обоих блоках, в том числе для XHTTP. Так nginx говорит с Xray по HTTP/2, этот вариант [рекомендует автор XHTTP](https://github.com/XTLS/Xray-core/discussions/4113).
- `client_max_body_size 0` снимает ограничение на размер запроса. Со стандартным лимитом в 1 МБ отправка больших файлов обрывается в `stream-up` и gRPC.
- Без увеличенных таймаутов nginx закрывает простаивающий туннель уже через минуту.
- Проверка `$content_type` прячет имя сервиса gRPC от обычных запросов: браузер получит 404.
- Запись `listen ... http2` на новых версиях nginx вызывает предупреждение. Это не ошибка, зато такой конфиг понимает nginx из репозиториев всех перечисленных систем.

Включите сайт:

```bash
ln -s /etc/nginx/sites-available/site /etc/nginx/sites-enabled/site
nginx -t && systemctl reload nginx
```

## Шаг 3. Установите Xray

```bash
bash -c "$(curl -L https://github.com/XTLS/Xray-install/raw/main/install-release.sh)" @ install
xray version
xray uuid
```

Версия должна быть не ниже 26.10.31: в ней закрыта серьёзная уязвимость, подробности в статье [Xray в 2026](https://oblako.sh/wiki/ru/rukovodstva/xray-xhttp-i-vless-encryption).

## Шаг 4. Настройте Xray

Откройте `/usr/local/etc/xray/config.json` и вставьте конфиг целиком. Если на сервере уже работает Xray, ничего не перезаписывайте: добавьте два объекта из `inbounds` к своим.

```json
{
  "log": { "loglevel": "warning" },
  "inbounds": [
    {
      "listen": "127.0.0.1",
      "port": 10080,
      "protocol": "vless",
      "settings": {
        "clients": [{ "id": "ВАШ_UUID" }],
        "decryption": "none"
      },
      "streamSettings": {
        "network": "xhttp",
        "xhttpSettings": { "path": "/ПУТЬ_XHTTP/" }
      }
    },
    {
      "listen": "127.0.0.1",
      "port": 10081,
      "protocol": "vless",
      "settings": {
        "clients": [{ "id": "ВАШ_UUID" }],
        "decryption": "none"
      },
      "streamSettings": {
        "network": "grpc",
        "grpcSettings": { "serviceName": "ИМЯ_GRPC" }
      }
    }
  ],
  "outbounds": [
    { "protocol": "freedom", "tag": "direct" }
  ]
}
```

Блока `security` здесь нет намеренно: снаружи шифрование обеспечивает nginx, а эти порты доступны только с самого сервера. Строка `flow` тоже не нужна, Vision на этих транспортах без VLESS Encryption не работает.

Запустите Xray и откройте порты, если включён UFW:

```bash
xray run -test -c /usr/local/etc/xray/config.json
systemctl restart xray
ufw allow 80/tcp
ufw allow 443/tcp
```

## Шаг 5. Проверьте сервер

Запросы должны вернуть три разных кода:

```bash
curl -s -o /dev/null -w "%{http_code}\n" https://ВАШ_ДОМЕН/
curl -s -o /dev/null -w "%{http_code}\n" https://ВАШ_ДОМЕН/ПУТЬ_XHTTP/
curl -s -o /dev/null -w "%{http_code}\n" https://ВАШ_ДОМЕН/ИМЯ_GRPC/Tun
```

| Адрес | Ожидаемый код | Что значит |
|---|---|---|
| сайт | 200 | nginx и сертификат работают |
| путь XHTTP | 400 | запрос дошёл до Xray и отклонён как неполный |
| путь gRPC | 404 | сработала проверка `$content_type` |

Код 502 на пути XHTTP означает, что nginx не достучался до Xray: проверьте `systemctl status xray`.

## Шаг 6. Подключите клиента

Импортируйте ссылку в клиент на ядре Xray, например v2rayN или v2rayNG. Косая черта в пути записывается как `%2F`.

**XHTTP:**

```text
vless://ВАШ_UUID@ВАШ_ДОМЕН:443?encryption=none&security=tls&sni=ВАШ_ДОМЕН&fp=chrome&alpn=h2&type=xhttp&path=%2FПУТЬ_XHTTP%2F&mode=stream-up#site-xhttp
```

**gRPC:**

```text
vless://ВАШ_UUID@ВАШ_ДОМЕН:443?encryption=none&security=tls&sni=ВАШ_ДОМЕН&fp=chrome&alpn=h2&type=grpc&serviceName=ИМЯ_GRPC&mode=gun#site-grpc
```

В приложении с ручным вводом значения те же: транспорт `xhttp` или `grpc`, TLS, ALPN `h2`, SNI с вашим доменом. Клиенты на чистом sing-box, в частности Hiddify, могут не принять XHTTP. Для них подойдёт ссылка gRPC.

### Какой режим выбрать

Сервер принимает любой режим XHTTP, поэтому менять его можно только в ссылке клиента, параметром `mode`:

| Режим | Как передаёт данные | Когда брать |
|---|---|---|
| `stream-up` | отправка и получение двумя долгими запросами | основной вариант, его советует само предупреждение Xray |
| `packet-up` | отправка множеством коротких запросов | если посредник буферизует долгие запросы и туннель зависает |
| `stream-one` | всё в одном запросе | запасной вариант, если не проходят первые два |

В нашем тесте `packet-up` отправлял данные примерно на треть медленнее остальных режимов: 11,8 МБ/с против 19 МБ/с. Абсолютные цифры сняты на одной машине, важно только соотношение.

Значение `auto` лучше не оставлять без причины. В обсуждении автора указано, что с TLS и HTTP/2 оно выбирает `stream-up`, но Xray 26.10.31 в нашей проверке выбирал `packet-up`.

Для gRPC оставьте `gun`. Режим `multi` документация Xray считает экспериментальным, а прибавки к скорости в нашем тесте он не дал.

## Вариант с Reality

Если вы настроили [self-steal](https://oblako.sh/wiki/ru/rukovodstva/blokirovki-reality-self-steal), XHTTP и gRPC можно включить прямо внутри Reality, без `grpc_pass`. Такой вход занимает порт целиком, так что на 443 поместится только один из них. Остальные настройки self-steal не меняются, nginx по-прежнему отвечает на `127.0.0.1:8443`.

В существующем подключении уберите `flow` у пользователя и замените `streamSettings`. Ключи и `shortIds` оставьте свои.

Для XHTTP:

```json
"streamSettings": {
  "network": "xhttp",
  "xhttpSettings": { "path": "/ПУТЬ_XHTTP/" },
  "security": "reality",
  "realitySettings": {
    "target": "127.0.0.1:8443",
    "serverNames": ["ВАШ_ДОМЕН"],
    "privateKey": "ВАШ_PRIVATE_KEY",
    "shortIds": ["ВАШ_SHORT_ID"]
  }
}
```

Для gRPC замените первые две строки:

```json
"network": "grpc",
"grpcSettings": { "serviceName": "ИМЯ_GRPC" },
```

Ссылки для клиента:

```text
vless://ВАШ_UUID@ВАШ_ДОМЕН:443?encryption=none&security=reality&sni=ВАШ_ДОМЕН&fp=chrome&pbk=ВАШ_PUBLIC_KEY&sid=ВАШ_SHORT_ID&type=xhttp&path=%2FПУТЬ_XHTTP%2F&mode=stream-one#site-reality-xhttp
vless://ВАШ_UUID@ВАШ_ДОМЕН:443?encryption=none&security=reality&sni=ВАШ_ДОМЕН&fp=chrome&pbk=ВАШ_PUBLIC_KEY&sid=ВАШ_SHORT_ID&type=grpc&serviceName=ИМЯ_GRPC&mode=gun#site-reality-grpc
```

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

## Если провайдер мешает {#esli-provajder-meshaet}

Прежде чем перебирать настройки, выясните, что именно ограничено. Положите на сервер файл размером 1 МБ:

```bash
head -c 1M /dev/urandom > /var/www/site/test.bin
```

С проблемного интернета, с выключенным VPN, выполните:

```bash
curl -o /dev/null -w "%{http_code} %{size_download}\n" --max-time 30 https://ВАШ_ДОМЕН/test.bin
```

| Результат | Вероятная причина | Что делать |
|---|---|---|
| `200 1048576` | адрес доступен, мешают протокол или поведение | сменить транспорт или режим, попробовать `fp=firefox` |
| Обрыв примерно на 16 КБ | ограничение на адрес или подсеть | перейти к статье про [проверку блокировки IP](https://oblako.sh/wiki/ru/rukovodstva/kak-proverit-blokirovku-ip) |
| Таймаут сразу | адрес не отвечает с этой сети | проверить другие сети по той же статье |
| Не открываются никакие зарубежные сайты | на мобильной сети включены белые списки | смотреть статью про [каскад](https://oblako.sh/wiki/ru/rukovodstva/belye-spiski-kaskad) |

Закончив проверку, удалите файл: `rm /var/www/site/test.bin`.

Обратите внимание, что обычная страница сайта помещается в 16 КБ и откроется даже при таком ограничении. Поэтому открывшийся сайт ещё не доказывает, что с адресом всё в порядке.

## Частые ошибки

| Симптом | Причина и решение |
|---|---|
| Сайт открывается, а клиент не подключается ни по одной ссылке | Нет HTTP/2 в `listen`. Строка должна быть `listen 443 ssl http2;` |
| Сайт открывается, VPN подключается, но трафика нет | Путь или имя сервиса различаются в nginx, Xray и ссылке. В `serviceName` не ставьте косую черту |
| Туннель обрывается примерно через минуту простоя | В `location` нет `grpc_read_timeout` и `client_body_timeout` |
| Большие файлы не отправляются | В `location` нет `client_max_body_size 0` |
| Через VPN не открываются адреса вида `127.0.0.1` или `192.168.x.x` | Xray по умолчанию не пускает трафик клиентов на частные адреса. В логе видно `blocked target`. Так и задумано, разрешать это без необходимости не стоит |
| Клиент пишет про неизвестный транспорт `xhttp` | Клиент на старом ядре или на sing-box. Обновите его или используйте ссылку gRPC |
| Xray с Reality и `mode=auto` даёт `unexpected response version` | Такое [встречалось](https://github.com/XTLS/Xray-core/issues/5635) на старых версиях. Обновите Xray и укажите `mode=stream-one` |
| В `journalctl -u xray` предупреждение про gRPC | Это не ошибка, gRPC работает. Текст разобран [выше](#xhttp-ili-grpc) |

Если вход работает у одного оператора и не работает у другого, сравните со статьёй [VLESS Reality перестал работать](https://oblako.sh/wiki/ru/rukovodstva/reality-ne-rabotaet): порядок диагностики там тот же, хотя транспорт другой.
