Что решает CDN, а что нет
Классика — клиент идёт прямо на IP ноды с VLESS/Reality в ДЦ. Пока блокировки по чёрным спискам, это рабочая схема: срезали один IP — подняли другой. Но при белых списках логика инвертируется: пропускается только то, что в allowlist, остальное режется по умолчанию. Одиночный IP в европейском или азиатском ДЦ в такой список не попадёт почти никогда, и нода становится недоступна целыми регионами — независимо от протокола и маскировки.
Поэтому важно развести два слоя и не путать их:
- Reality / TLS-маскировка прячет *характер* трафика от DPI.
- CDN-фронт прячет *адрес*: реальный IP ноды уходит за домен и диапазоны CDN.
CDN не борется с DPI — он решает проблему достижимости адреса. Клиент видит только cdn-domain.example, коннектится к ближайшей точке присутствия, а та идёт на ваш origin. Для наблюдателя это обычный HTTPS к крупной сети, которую нельзя вырезать точечно без сопутствующего ущерба. В зоне жёстких allowlist именно второй слой становится решающим — от DPI вы уже, скорее всего, закрыты, а вот адрес выпадает из белого списка.
Как CDN-фронт проходит белые списки
Механика прямая: во время белых списков оператор (ТСПУ) пропускает трафик только к разрешённым сетям. Если IP-диапазоны CDN в этом whitelist — а у CDN, обслуживающего платёжки, госуслуги и медиа, шансы выше, — подключение к фронту физически проходит тогда, когда прямой коннект к ноде уже мёртв.
Отсюда ключевой тезис: устойчивость даёт не нода, а фронт через whitelisted-CDN. Сервер в ДЦ блокируется легко и первым; CDN-слой перед ним переживает отключения, потому что делит инфраструктуру с сервисами, которые нельзя ронять. Это и есть смысл запроса «vless за cdn обход блокировок» — вы меняете уязвимый одиночный адрес на диапазон, который трудно срезать точечно.
Честно про ограничения:
- Попадание конкретного CDN в whitelist — не константа. У разных операторов списки отличаются; конкретный
/24может быть, а может и не быть в allowlist. Проверять надо по факту на своём канале и по каждой /24 отдельно — соседний диапазон того же CDN может вести себя иначе. - «CDN, который всегда в whitelist» не существует. Есть кандидаты с более высокой вероятностью и есть специализированные whitelist-CDN, которые целенаправленно держат диапазоны в разрешённых сетях именно под задачу фронта для VPN-нод — это единственный случай, где попадание не случайность, а SLA.
Быстро прикинуть, жива ли /24 при включённых списках, можно с устройства в зоне блокировки: curl -s -o /dev/null -w "%{http_code} %{time_connect}\n" https://<edge-ip>/ --resolve cdn-domain.example:443:<edge-ip> — есть коннект к нескольким edge-IP, значит диапазон проходит.
XHTTP vs gRPC vs WebSocket под CDN
Сырой TCP/Reality через CDN не пустить — CDN понимает только HTTP(S). Нужен транспорт поверх HTTP:
| Транспорт | Плюсы под CDN | Минусы |
|---|---|---|
| WebSocket (WS) | Максимально совместим, поддерживают почти все CDN, гайдов больше всего | Одна TCP-сессия на соединение; часть CDN рвёт upgrade или закрывает по idle-таймауту |
| gRPC | Мультиплекс поверх HTTP/2, стабилен на длинных сессиях | Требует end-to-end HTTP/2; часть CDN даунгрейдит до 1.1 и ломает стриминг |
| XHTTP (splithttp) | Гибкий по HTTP-семантике, живёт через обычные HTTP-прокси и кэширующие CDN, режимы под разные ограничения | Новее, требует аккуратной настройки mode; больше нюансов |
Под новый фронт практичнее всего VLESS + XHTTP (vless xhttp cdn): он изначально рассчитан на промежуточный HTTP-посредник и разносит upload/download, что важно для CDN, по-разному обрабатывающих направления.
Главный подводный камень: многие CDN не пропускают POST к произвольным путям и разрешают только GET. XHTTP в этом случае переключается на GET, но тогда обязательно нужно явно задать mode: packet-up на обеих сторонах — иначе клиент и сервер не договорятся о направлении аплоада. Ровно отсюда растёт «в одном приложении работает, в другом нет»: разные клиенты по-разному выбирают режим, и без явной фиксации часть не сходится с сервером. Проверить, режет ли ваш CDN POST, — один запрос:
curl -s -o /dev/null -w "POST=%{http_code}\n" -X POST https://cdn-domain.example/xhttp -d x=1
curl -s -o /dev/null -w "GET=%{http_code}\n" https://cdn-domain.example/xhttp
Если POST отдаёт 403/405, а GET — 200/404 от origin, значит CDN GET-only и packet-up не опция, а требование. Не убирайте GET-совместимость «ради чистоты» конфига — сломаете рабочий фронт.
Каркас настройки (без пересказа гайдов по панелям)
Пошаговая настройка конкретных панелей — Remnawave, Marzban, 3x-ui — расписана в отдельных материалах; здесь только каркас, общий для всех.
- DNS и origin. Заводите поддомен, наводите его на CDN; в CDN origin = IP ноды. Реальный IP не светится ни в одном клиентском конфиге.
- TLS. Клиент → CDN по валидному серту CDN-домена; CDN → origin по своему TLS (или отдельному серту на ноде). SNI клиента = ваш CDN-домен.
- Inbound на ноде. VLESS + XHTTP на конкретном
path(например/xhttp). Тот же path прописываете в правилах CDN — проксировать на origin, а не кэшировать как статику. Минимальный inbound-фрагмент Xray:
{
"protocol": "vless",
"streamSettings": {
"network": "xhttp",
"xhttpSettings": { "path": "/xhttp", "mode": "packet-up" }
}
}
- Режим. CDN умеет POST — можно оставить
auto. Только GET — жёсткоpacket-upна клиенте и сервере. - Кэш. Для трафикового path отключаете кэш на CDN (
Cache-Control: no-cache), иначе CDN отдаёт устаревшие ответы. Это же лечит залипание подписки в ряде клиентов (тот же iOS Happ).
Проверка боем. Сначала — что хендшейк идёт на CDN-домен, а не на IP ноды. Потом имитируете падение прямого IP и убеждаетесь, что соединение живёт через CDN:
sudo iptables -A INPUT -s <ваш-клиентский-IP> -p tcp --dport 443 -j DROP
На ноде это режет прямой коннект; если клиент через CDN-фронт остался онлайн — фронт настроен верно.
Подводные камни и цена вопроса
- CDN — это деньги, и считать надо запросы, а не только гигабайты. XHTTP через кэширующий CDN генерирует много мелких запросов, и на масштабе счёт формирует именно их количество. Цена сырого трафика берётся из прайса конкретного CDN-провайдера и у всех разная. Закладывайте это в экономику до прода.
- Латентность растёт. Путь клиент → CDN edge → origin длиннее прямого. Для веба незаметно, для игр и голоса — чувствительно.
- Whitelist непостоянен. Диапазоны CDN выпадают из белых списков после изменений у оператора. Держите fallback: прямой Reality-inbound на ноде, когда списки сняты, и CDN-фронт, когда включены — переключение между ними и даёт стабильность.
- Не всякий CDN дружит с транспортом. Часть ломает gRPC или обрывает длинные WS. Тестируйте выбранный транспорт именно на своём CDN, а не по чужому гайду.
- Origin надо прятать. Утечёт реальный IP (старые A-записи, прямой коннект в обход CDN, засветка в сертификате origin) — весь смысл фронта теряется, блокируют напрямую. Файрволом пускайте на 443 ноды только диапазоны своего CDN.