Зачем ноде Remnawave вообще CDN перед собой
Механику белых списков разбираем отдельно — здесь только вывод. При блокировке по чёрным спискам режут конкретные домены и IP, и голая нода живёт долго. При переходе оператора на белый список логика инвертируется: проходит только явно разрешённое, всё остальное режется по умолчанию. IP вашей ноды на обычном не-российском VPS (Hetzner, DigitalOcean, любой не-whitelist хостинг) в белый список не входит по определению — падает первым и целиком, вместе с доменом, портом и протоколом.
CDN для Remnawave решает ровно одну задачу — подменяет точку входа. Клиент больше не стучится в IP ноды напрямую, он идёт на домен CDN, а edge-узел имеет IP, который либо уже в whitelist оператора, либо статистически переживает белые списки лучше одиночного VPS. Нода при этом остаётся где угодно — она становится origin'ом за фронтом.
Граница возможностей важна: CDN спасает доступность точки входа, но не делает трафик «легальным» и не прячет сам факт VPN от DPI по содержимому — за это отвечает транспорт. CDN и транспорт работают в паре, не заменяя друг друга.
Как устроена связка клиент → CDN → нода
Цепочка для Remnawave за CDN:
- Клиент (Happ, v2rayNG, Streisand) получает из подписки Host, где
address— домен CDN, а не IP ноды. - CDN edge принимает TLS на 443, терминирует его (сертификат на домен CDN) и по
Host-заголовку и пути проксирует запрос на origin. - Origin (ваша нода) получает уже расшифрованный CDN'ом HTTP-поток, а внутри него — туннель Xray.
Два следствия определяют всю дальнейшую настройку:
- TLS терминируется на CDN. Значит Reality на фронте невозможен: Reality требует настоящий TLS-handshake напрямую с целевым сайтом, а CDN этот handshake перехватывает. За CDN живут только транспорты поверх HTTP — WebSocket, XHTTP, gRPC, HTTPUpgrade.
- CDN видит только HTTP-обёртку, а не содержимое VLESS. Поэтому транспорт маскируется под обычный веб-запрос по пути (
/path), а origin отвечает только на этот путь и молчит (404/заглушка) на всё остальное — иначе выглядит подозрительно.
Между CDN и origin желательно оставить второй слой TLS (режим origin-over-HTTPS, сертификат на отдельный origin-домен) — чтобы расшифрованный трафик не шёл открытым HTTP. Минимально рабочая схема допускает plain HTTP на origin за локальным reverse-proxy, но по integrity она хуже.
Выбор транспорта: WS, XHTTP, gRPC, HTTPUpgrade
Что реально ставить под CDN:
- WebSocket (ws) — самый совместимый. Проксируется практически любым CDN, конфиг простой, всё решают
path+Host. Минус — WS давно на радаре DPI как «типичный VPN-транспорт», но за whitelisted-CDN это вторично: задача CDN — доступность IP, а не невидимость. - XHTTP — современный транспорт Xray, гибче WS. Подводный камень именно на CDN: если CDN не пропускает
POSTи долгие стримы, оставляя толькоGET, XHTTP обязан работать в режимеpacket-up(неstream-up). Отсюда классический баг «в одном приложении подписка работает, в другом нет» — часть клиентов не согласует режим. Ставите XHTTP за CDN — фиксируйтеmodeявно и тестируйте на нескольких клиентах. Детали XHTTP-режимов — в отдельной статье. - gRPC — работает только за CDN со сквозным HTTP/2. На практике многие CDN ломают gRPC на границе (буферизация, отсутствие end-to-end h2), поэтому капризнее WS.
- HTTPUpgrade — по сути «WS без апгрейда до фрейминга», лёгкий и CDN-дружелюбный; хорошая альтернатива WS, если ваши клиенты его поддерживают.
Рекомендация: начните с WebSocket, а XHTTP берите осознанно, когда контролируете режим и готовы тестировать. Reality за CDN не протащить — не тратьте на это время.
Config Profile, inbound и reverse-proxy на ноде
В Remnawave транспорт задаётся в Config Profile (это Xray-конфиг с inbound'ами), нода использует выбранный inbound, а Host в подписке ссылается на него. Пример inbound VLESS+WebSocket, слушающего локально (TLS снимает reverse-proxy или сам CDN):
{
"tag": "vless-ws-cdn",
"listen": "127.0.0.1",
"port": 8080,
"protocol": "vless",
"settings": { "clients": [], "decryption": "none" },
"streamSettings": {
"network": "ws",
"security": "none",
"wsSettings": { "path": "/braid", "host": "cdn.example.com" }
}
}
security: none — TLS снимает фронт. Массив clients заполняет сам Remnawave по пользователям, вручную не трогаем.
Вариант XHTTP под GET-only CDN — с явным режимом:
{
"tag": "vless-xhttp-cdn",
"listen": "127.0.0.1",
"port": 8080,
"protocol": "vless",
"settings": { "clients": [], "decryption": "none" },
"streamSettings": {
"network": "xhttp",
"security": "none",
"xhttpSettings": { "path": "/braid", "mode": "packet-up" }
}
}
Перед нодой на 443 держите reverse-proxy с валидным сертификатом на origin-домен — именно на этот origin ходит CDN. Для WS критичны заголовки Upgrade/Connection, иначе соединение молча рвётся:
location /braid {
proxy_pass http://127.0.0.1:8080;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_read_timeout 300s;
}
Путь на proxy и path в inbound должны совпадать; всё остальное отдавайте 404 или заглушку. Для gRPC/XHTTP набор proxy_set_header иной (без Upgrade, с HTTP/2 на listener) — сверяйтесь с требованиями транспорта.
Настройка Hosts в Remnawave — самое важное
Host в Remnawave — это то, что реально уезжает клиенту в подписке. Здесь нода «переезжает» за CDN, при этом сам origin не меняется. Это ядро настройки Remnawave за CDN. Ключевые поля:
- Address — домен CDN, а не IP и не origin-домен ноды. Это адрес, куда пойдёт клиент.
- Port —
443. - Security —
tls(TLS до CDN настоящий). - SNI — домен CDN (тот же, что Address); должен совпадать с сертификатом, которым отвечает CDN.
- Host (header) — домен CDN. Для WS/XHTTP это HTTP-заголовок маршрутизации; расхождение SNI и Host — частая причина «не коннектится».
- Path — тот же
/braid, что в inbound и на reverse-proxy. - ALPN —
http/1.1для WS; для gRPC/XHTTP —h2. Неверный ALPN ломает соединение на CDN молча. - Fingerprint —
chrome(маскировка TLS ClientHello под браузер). - Allow Insecure —
off. Если пришлось включать — сертификат/SNI настроены неверно; чините причину, а не симптом.
Смысл: inbound на ноде остаётся один, а через несколько Hosts вы отдаёте один узел под разными фронтами (прямой домен и домен CDN) и переключаете аудиторию, не трогая ноду. Когда прямой IP ложится под белым списком — активным остаётся Host с CDN-адресом. Удобно держать оба Host'а заранее и включать резервный по факту блокировки.
Проверка, типичные ошибки и слой устойчивости
Порядок проверки после настройки:
- С origin-сервера —
curl -vk https://127.0.0.1/braid --resolve...или проще проверьте локальноcurl -v http://127.0.0.1:8080/braid: reverse-proxy и inbound живы, если нет ошибки соединения. - Снаружи через CDN —
curl -v https://cdn.example.com/braid. CDN должен принять TLS и дотянуться до origin; ответ 400/404 от вашего proxy — норма (путь живёт, просто не VLESS-рукопожатие), а вот5xxс edge означает, что origin недоступен или путь не совпал. - Подключение реальным клиентом из подписки — проверяйте на двух-трёх разных клиентах, особенно для XHTTP (история с
packet-up). - Отключите CDN-Host и убедитесь, что прямой доступ тоже работает — так отделяете проблемы CDN от проблем ноды.
Частые грабли:
- SNI ≠ Host — рвётся молча; держите оба равными домену CDN.
- Path не совпал в inbound / reverse-proxy / Host — CDN отдаёт 404, клиент «не подключается».
- Reality под CDN — не работает в принципе, TLS терминирует CDN.
- XHTTP на GET-only CDN без
packet-up— работает выборочно по клиентам. - WS без Upgrade-заголовков на nginx — 502/400 на apgrade'е.
- iOS-клиенты кэшируют подписку — после смены Host обновление «залипает»; лечится no-cache на выдаче подписки или переустановкой подписки на устройстве.
Стратегический итог: обычный публичный CDN даёт доступность, но его edge-IP тоже могут не входить в белый список конкретного оператора. Максимальную устойчивость даёт фронт через whitelisted-CDN — сеть, edge-IP которой заведомо в белых списках российских операторов (по этому принципу построен наш Clearway). Тогда падение IP ноды в дата-центре перестаёт означать падение сервиса: клиент входит через белый фронт, а нода прячется за ним как origin.