Проблема с маскировкой за ру cdn по типу timeweb и яша.
cап, ntcparty. уже несколько дней убил на реверс-инжиниринг и чтение китайских ишью в репо xtls, так что пришел с просьбой о помощи коллективного разума сюда.
Что я хочу сделать:
пытаюсь собрать для личного использования (семья/друзья) максимально надежный fallback-канал (разумеется надёжный с учётом текущих условий
) для условий жестких бс, в частности по Мск и МО на мобильном инете.
Входные данные:
- впска в нидерландах (тестил vdsina и 62yun).
- привязанный домен с валидными SSL (делал как обычно через certbot тобишь let’s encrypt)
- архитектура: Client (Happ) ➝ RU CDN (Timeweb) ➝ Origin VPS (нидерланды) ➝ Nginx (TLS Termination) ➝ Xray-core (VLESS)
В чём самая соль:
без cdn, тобишь если идти напрямую на origin-сервер, всё идеально ворк. проблемы начинаются как раз при использовании подключения за cdn timeweb и яши через CNAME записи, начинаются танцы с бубном, на сколько я понял но L7. при попытке коннекта (ws/xhttp/и др что писал в заголовке) туннель вроде даже начинает пробиваться, и даже в логах на origin-серваке есть некоторые признаки работы в логах nginx, но потом сразу идут 101 ошибки Switching Protocols. затем трафик либо не идёт совсем, хотя туннель формально есть, либо просто терминируется сессия. если пустить браузер через всю эту свистопляску, то ловлю классический PR_END_OF_FILE_ERROR. проблема на сколько я понял комплексная и тд, поэтому ошибок было много, как и перепробованных конфигов. думаю понятно что я не смогу приложить всё сюда, поэтому выделю самое важное из проделанной работы.
Более подробно про проблемы с которыми я сталкивался:
-
борьба с кэширующими Edge-нодами (403 Edge HIT)
сначала при использовании xhttp ловил от CDN глухой 403 Forbidden. прострел через curl показал заголовок < x-cdn-edge-cache: HIT, то есть балансировщик Timeweb один раз словил отбой от моего Nginx, закэшировал ошибку прямо на Edge-узле и дальше даже не пытался стучаться на Origin.
что сделал: сбросил кэш в панелию. в корень / положил белый index.html с нужными правами (www-data), чтобы анти-фрод сканнеры CDN успокоились и видели легитимный сайт. -
TLS Handshake и Double TLS конфликты
сначала ловил SSL_ERROR_BAD_CERT_DOMAIN и x509: certificate is valid for *.a.abcdef.net… это классика: нода терминирует TLS и отдает свой дефолтный серт.
что сделал: чтобы исключить отвал по соображениям безопасности на клиенте, пробовал два пути:
а) на стороне, в частности Happ, ставил allowInsecure: true.
б) заливал свои ключи fullchain.pem и Let’s Encrypt прямо в панель Timeweb и привязывал к ресурсу.
хэндшейки чинятся, но от разрыва самой сессии это не спасает. также убрал security: “tls” на inbound-е Xray origin-сервера, чтобы не ловить ошибку двойного шифрования, так как трафик ко мне приходит уже расшифрованным от Nginx. -
ошибки буферизации (104 и PR_END_OF_FILE)
пытался завести модный xhttp через grpc_pass (http2) в Nginx. ловил в error.log сплошные таймауты: upstream timed out (110: Unknown error) while reading upstream.
что сделал: вернулся на классический ws через дефолтный proxy_pass. добавил proxy_buffering off; и proxy_request_buffering off;, выкрутил таймауты на 3600s. только после этого в access-логах стабильно пошли статусы 101 Switching Protocols. но радовался недолго - соединение висит пару секунд и падает с 499 Client Closed Request в Nginx и 104: Unknown error внутри проксирующего слоя. -
исключение клиентских петель (Routing Loops)
у меня была гипотеза, что Happ в режиме TUN чудит с маршрутизацией (захватывает пакеты, идущие до IP CDN-ноды, и пытается пихнуть их внутрь самого туннеля).
что сделал: отказался от Happ для чистоты эксперимента. cобрал голый xray-core на ПК, благо у меня линух, дело пары минут. запустил чистый локальный SOCKS5. в качестве Address хардкодом вписал технический домен ноды abcdefg.cdn.abcdefg.ru, а Host и SNI жестко привязал к cdn.example.com. результат тот же: 101-й статус есть, трафика 0.
Какая-то часть конфигов которая у меня осталась от экспериментов
Вариант 1: конфиги для xhttp:
-
настройки панели CDN:
- источник: 185.0.0.0, Порт: 443, Протокол: HTTPS
- заголовки запроса: cdn.example.com
-
Nginx (origin сервер):
server {
listen 443 ssl http2;
server_name cdn.example.com;
ssl_certificate /etc/letsencrypt/live/cdn.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/cdn.example.com/privkey.pem;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256;
# декой для сканеров антифрода
location / {
root /var/www/html;
index index.html;
}
# сам туннель
location /api/v1/update {
client_max_body_size 0;
grpc_read_timeout 315s;
grpc_send_timeout 5m;
grpc_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
grpc_pass grpc://127.0.0.1:10000;
}
}
- Xray (origin сервер):
{
"log": {
"loglevel": "debug"
},
"inbounds": [
{
"port": 10000,
"listen": "127.0.0.1",
"protocol": "vless",
"settings": {
"clients": [
{
"id": "00000000-0000-0000-0000-000000000000",
"flow": ""
}
],
"decryption": "none"
},
"streamSettings": {
"network": "xhttp",
"security": "none",
"xhttpSettings": {
"path": "/api/v1/update",
"mode": "auto"
}
}
}
],
"outbounds": [
{
"protocol": "freedom",
"tag": "direct"
}
]
}
- Конфиг клиента
vless://00000000-0000-0000-0000-000000000000@node-123.cdn.provider.ru:443?encryption=none&security=tls&sni=cdn.example.com&alpn=h2&type=xhttp&host=cdn.example.com&path=%2Fapi%2Fv1%2Fupdate#CDN_XHTTP_Test
- Логи:
- Лог Nginx (error.log):
[error] 785338#785338: *645 upstream timed out (110: Unknown error) while reading upstream, client: 89.0.X.X, server: cdn.example.com, request: "GET /api/v1/update/95e445f2-0f93-4ce8-9fc7-413ce408449b HTTP/2.0", upstream: "grpc://127.0.0.1:10000", host: "cdn.example.com"...
- Ответ CDN (через curl):
> GET /api/v1/update HTTP/2
> Host: cdn.example.com
> Upgrade: websocket
> Connection: Upgrade
* Request completely sent off
< HTTP/2 403
< server: nginx
< x-cdn-edge-id: 2018
< x-cdn-edge-cache: HIT
< x-cdn-request-id: 845931565f08efb41c88fc72578db376
<html><body><center><h1>403 Forbidden</h1></center></body></html>
Вариант 2: конфиги для ws (nginx в режиме unbuffered):
-
Настройки панели CDN как в варианте выше
-
Конфиг Nginx (ogrigin сервер):
server {
listen 443 ssl http2;
server_name cdn.example.com;
ssl_certificate /etc/letsencrypt/live/cdn.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/cdn.example.com/privkey.pem;
location / {
root /var/www/html;
index index.html;
}
location /api/v1/update {
if ($http_upgrade != "websocket") {
return 404;
}
proxy_pass http://127.0.0.1:10000;
# хэдеры для ws
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
# отрубаем buffering
proxy_buffering off;
proxy_request_buffering off;
# конские таймауты
proxy_read_timeout 3600s;
proxy_send_timeout 3600s;
}
}
- Конфиг Xray (origin server):
{
"inbounds": [
{
"port": 10000,
"listen": "127.0.0.1",
"protocol": "vless",
"settings": {
"clients": [
{
"id": "00000000-0000-0000-0000-000000000000",
"flow": ""
}
],
"decryption": "none"
},
"streamSettings": {
"network": "ws",
"security": "none",
"wsSettings": {
"path": "/api/v1/update",
"headers": {
"Host": "cdn.example.com"
}
}
}
}
],
"outbounds": [{"protocol": "freedom","tag": "direct"}]
}
- Клиентский конфиг (Happ):
{
"inbounds": [{"listen": "127.0.0.1", "port": 10808, "protocol": "socks"}],
"outbounds": [
{
"protocol": "vless",
"settings": {
"vnext": [{
"address": "node-123.cdn.provider.ru",
"port": 443,
"users": [{"id": "00000000-0000-0000-0000-000000000000", "encryption": "none", "level": 8}]
}]
},
"streamSettings": {
"network": "ws",
"security": "tls",
"tlsSettings": {
"allowInsecure": true,
"serverName": "cdn.example.com",
"fingerprint": "chrome"
},
"wsSettings": {
"host": "cdn.example.com",
"path": "/api/v1/update"
}
}
}
]
}
- Логи:
тут можно наблюдать пробой L7 фильтрации, видно в логах Nginx (access.log) что хоть что-то пришло на сервер:
193.39.X.X - - [14/May/2026:14:56:51 +0300] "GET /api/v1/update HTTP/1.1" 101 13907 "-" "Go-http-client/1.1"
193.39.X.X - - [14/May/2026:14:56:51 +0300] "GET /api/v1/update HTTP/1.1" 101 61009 "-" "Go-http-client/1.1"
но тем не менее, клиент выдаёт одну из двух ошибок:
-
- ошибка 1: PR_END_OF_FILE_ERROR;
-
- ошибка 2 (access.log в Nginx на origin сервере):
499 Client Closed Request
- ошибка 2 (access.log в Nginx на origin сервере):
193.39.X.X - - [14/May/2026:14:56:51 +0300] "GET /api/v1/update HTTP/1.1" 499 0 "-" "Go-http-client/1.1"
Варик номер 3: попытка обхода кэширующих аномалий WAF
-
Настройки панели CDN как и в остальных вариантах
-
Конфиг Nginx (origin сервер):
server {
listen 443 ssl http2;
server_name cdn.example.com;
ssl_certificate /etc/letsencrypt/live/cdn.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/cdn.example.com/privkey.pem;
location / {
# проверка на ws
if ($http_upgrade = "websocket") {
proxy_pass http://127.0.0.1:10000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
break;
}
# выдаём декой
root /var/www/html;
index index.html;
}
}
- Конфиг Xray (origin сервер и клиент):
по факту от предыдущего отличается только этим:
"wsSettings": {
"path": "/",
"headers": { "Host": "cdn.example.com" }
}
для этого конфига сохранившихся логов не нашёл, но, по-моему, проблема была в том, что трафик до cdn шёл, а на сервер просто не приходил, т.е. на сервере логов вообще не было никаких, а на клиенте вроде как всё было адекватно, ну разумеется кроме статуса N/A.
Недо вариант 4: сервер без Nginx, онли Xray
- Конфиг Xray:
{
"inbounds": [
{
"port": 443,
"protocol": "vless",
"settings": {
"clients": [{"id": "00000000-0000-0000-0000-000000000000", "flow": ""}],
"decryption": "none"
},
"streamSettings": {
"network": "xhttp",
"security": "tls",
"tlsSettings": {
"certificates": [
{
"certificateFile": "/path/to/cert/fullchain.pem",
"keyFile": "/path/to/cert/privkey.pem"
}
]
},
"xhttpSettings": {
"path": "/api/v1/update",
"mode": "auto",
"scMaxConcurrentPosts": 10,
"scMaxEachPostBytes": 1000000,
"scMinPostsIntervalMs": 30
}
}
}
]
}
проблема идентичная варианту выше.
Собственно, вопросы к гуру:
глядя на все эти танцы с бубнами, которые я перепробовал, и дропы сессий, у меня складывается стойкое ощущение, что я уперся в L7 WAF отечественных CDN. похоже, их фильтры каким-то образом палят, что внутри ws, xhttp или (подставить любой друго протокол) трубы бегает не типичный веб-трафик, и они агрессивно делают сеппуку long-lived сессиям.
тот же MWS, например, у коммерсов живет, но хрен знает каким образом.
Подскажите, плз:
-
как сейчас модно обманывать анти-фрод / WAF того же Timeweb’а или Яши? Режут ли они сейчас ws сессии по таймаутам на обычных тарифах, или я банально где-то обосрался на стыке Nginx ↔ Xray в плане хэдеров/буферов?
-
нужны ли сейчас какие-то специфические настройки мультика/чанкинга (mux, smux, ограничение scMaxEachPostBytes) именно под ру-балансировщики, чтобы маскировать VLESS внутри?
-
или без Enterprise-аккаунта “для своих” (где можно вырубить инспекцию трафика на Edge-нодах) ловить за такими CDN сейчас вообще нечего и надо искать другие пути диверсификации?
буду чертовски благодарен за любые пинки в нужное русло или примеры живых конфигов под эти условия. заранее выражаю благодарность!