Прозрачный туннель для разработки без установки локальных корневых SSL-сертификатов. Направляет только заблокированные AI-сервисы (ChatGPT, Google Antigravity, Gemini, Grok) через бинарный WebSocket-мост к глобальной сети Cloudflare. Весь остальной сетевой трафик идёт напрямую на полной скорости провайдера.
Никакого глобального VPN, занижающего скорость домашнего интернета. Разделение потоков происходит на сетевом уровне ядра.
chatgpt.com на 443 порт.
127.0.0.1 только для целевых AI-доменов. Все остальные домены идут в 1.1.1.1.
bridge.mjs считывает ClientHello SNI по RFC 6066 без расшифровки и открывает WebSocket к Cloudflare.
Почему разработчики выбирают CF-PROXY вместо стандартных VPN и навязчивых MITM-прокси.
Вам не нужно генерировать самоподписанные сертификаты, добавлять их в системный Keychain или ломать валидацию TLS в Node.js / Python через NODE_TLS_REJECT_UNAUTHORIZED=0.
Туннелируется строго то, что вы внесли в dnsmasq.conf. Госуслуги, интернет-банкинг, локальная сеть (LAN) и тяжёлые загрузки продолжают работать через прямого провайдера без задержек.
Современные AI-редакторы (Google Antigravity, Cursor, Copilot) часто сбрасывают TLS-соединение при обнаружении неизвестных промежуточных сертификатов. CF-PROXY передает сырые байты, исключая сбои.
Пакеты упаковываются в стандартный защищенный WebSocket-поток (WSS). Это полностью обходит DPI-фильтры провайдеров и инспектирование сетевых пакетов на границе сети.
Использует инфраструктуру Cloudflare Workers в 300+ точках присутствия по всему миру. Запросы выходят в интернет через высокоскоростной Anycast с минимальным пингом.
Всё упаковано в docker-compose.yml. Никаких зависимостей на хост-машине. Чистый запуск, изолированное окружение, автоперезапуск при падении.
Полный и прозрачный стек: изучайте, адаптируйте под свои домены и запускайте локально.
services:
sni-bridge:
image: node:22-alpine
container_name: cf-proxy-bridge
restart: unless-stopped
environment:
- WORKER_HOST=switcher.richcorp.online
#extra_hosts:
#- "geo-nicdns.catvoodoo0.workers.dev:162.159.135.42"
ports:
- "127.0.0.1:443:443"
volumes:
- ./bridge.mjs:/app/bridge.mjs:ro
command: node /app/bridge.mjs
dnsmasq:
image: alpine:3.20
container_name: cf-proxy-dns
restart: unless-stopped
command: sh -c "apk add --no-cache dnsmasq && dnsmasq -k --log-facility=-"
ports:
- "127.0.0.1:53:53/udp"
- "127.0.0.1:53:53/tcp"
volumes:
- ./dnsmasq.conf:/etc/dnsmasq.conf:ro
import net from "node:net";
// Впиши сюда свой привязанный поддомен на .online (без https:// и слэшей)
const WORKER_HOST = "switcher.richcorp.online";
function extractSNI(buf) {
try {
if (buf.length < 43 || buf[0] !== 0x16 || buf[5] !== 0x01) return null;
let pos = 43;
if (pos >= buf.length) return null;
pos += 1 + buf[pos];
if (pos + 2 > buf.length) return null;
pos += 2 + buf.readUInt16BE(pos);
if (pos + 1 > buf.length) return null;
pos += 1 + buf[pos];
if (pos + 2 > buf.length) return null;
const extTotalLen = buf.readUInt16BE(pos);
pos += 2;
const end = Math.min(buf.length, pos + extTotalLen);
while (pos + 4 <= end) {
const extType = buf.readUInt16BE(pos);
const extLen = buf.readUInt16BE(pos + 2);
pos += 4;
if (extType === 0x0000 && pos + 5 <= end) {
const nameLen = buf.readUInt16BE(pos + 3);
if (pos + 5 + nameLen <= end) {
return buf.toString("utf8", pos + 5, pos + 5 + nameLen);
}
}
pos += extLen;
}
} catch (_) {}
return null;
}
net.createServer((client) => {
client.setNoDelay(true);
const chunks = [];
const onFirstData = (chunk) => {
chunks.push(chunk);
const fullBuf = Buffer.concat(chunks);
if (fullBuf.length < 5) return;
const recordLen = fullBuf.readUInt16BE(3);
if (fullBuf.length < 5 + recordLen && fullBuf.length < 2048) return;
client.removeListener("data", onFirstData);
const sni = extractSNI(fullBuf);
if (!sni || sni === WORKER_HOST) {
client.destroy();
return;
}
console.log(`[CONNECT] ${sni} -> wss://${WORKER_HOST}`);
const ws = new WebSocket(`wss://${WORKER_HOST}/?host=${encodeURIComponent(sni)}&port=443`);
ws.binaryType = "arraybuffer";
const queue = [fullBuf];
const onQueueData = (c) => queue.push(c);
client.on("data", onQueueData);
ws.onopen = () => {
client.removeListener("data", onQueueData);
for (const c of queue) ws.send(c);
queue.length = 0;
client.on("data", (c) => {
if (ws.readyState === WebSocket.OPEN) ws.send(c);
});
};
ws.onmessage = (e) => {
if (!client.destroyed) client.write(new Uint8Array(e.data));
};
ws.onclose = (e) => {
if (e.code !== 1000 && e.code !== 1005) {
console.log(`[WS CLOSED] ${sni} | Code: ${e.code} | Reason: ${e.reason}`);
}
client.destroy();
};
ws.onerror = (err) => {
console.error(`[WS ERROR] ${sni}:`, err.message || "Connection error");
client.destroy();
};
client.on("close", () => { try { ws.close(); } catch (_) {} });
client.on("error", () => { try { ws.close(); } catch (_) {} });
};
client.on("data", onFirstData);
client.on("error", () => client.destroy());
}).listen(443, () => {
console.log(`SNI Tunnel Bridge active -> wss://${WORKER_HOST}`);
});
no-resolv
server=1.1.1.1
server=8.8.8.8
# ChatGPT / OpenAI
address=/chatgpt.com/127.0.0.1
address=/openai.com/127.0.0.1
address=/oaistatic.com/127.0.0.1
address=/oaiusercontent.com/127.0.0.1
# Google Antigravity
address=/antigravity.google/127.0.0.1
address=/daily-cloudcode-pa.googleapis.com/127.0.0.1
address=/cloudcode-pa.googleapis.com/127.0.0.1
address=/cloudaicompanion.googleapis.com/127.0.0.1
address=/generativelanguage.googleapis.com/127.0.0.1
address=/aiplatform.googleapis.com/127.0.0.1
address=/businessaicode.googleapis.com/127.0.0.1
address=/gemini.google.com/127.0.0.1
# xAI Grok
address=/grok.com/127.0.0.1
events {
worker_connections 1024;
}
http {
resolver 1.1.1.1 8.8.8.8 ipv6=off;
# Увеличиваем лимиты на размер заголовков и Cookie от браузера
client_header_buffer_size 64k;
large_client_header_buffers 8 64k;
underscores_in_headers on;
# Увеличиваем буферы для ответов от воркера
proxy_buffer_size 128k;
proxy_buffers 8 256k;
proxy_busy_buffers_size 256k;
server {
listen 443 ssl;
server_name _;
ssl_certificate /etc/nginx/certs/cert.pem;
ssl_certificate_key /etc/nginx/certs/key.pem;
ssl_protocols TLSv1.2 TLSv1.3;
location / {
set $worker_host "frisky-squid-8674.catvoodoo.deno.net"; # домен на deno.dev / workers.dev
# Защита от случайной петли
if ($host = $worker_host) {
return 508 "Loop detected";
}
proxy_pass https://$worker_host;
proxy_ssl_server_name on;
proxy_ssl_name $worker_host;
proxy_ssl_protocols TLSv1.2 TLSv1.3;
proxy_set_header Host $worker_host;
proxy_set_header X-Target-Host $host;
proxy_set_header Accept-Encoding ""; # чтобы воркер не путался со сжатием
proxy_buffering off;
proxy_http_version 1.1;
proxy_set_header Connection "";
client_max_body_size 100M;
}
}
}
Почему классические методы уступают связке селективного DNS и прямого SNI-моста.
| Критерий оценки | CF-PROXY (Edge Bridge) | Классический VPN | MITM Прокси (Charles/Mitmproxy) | SOCKS5 Прокси |
|---|---|---|---|---|
| Установка корневых Root CA | НЕ ТРЕБУЕТСЯ (0 сертов) | Не требуется | ОБЯЗАТЕЛЬНА (риск компрометации) | Не требуется |
| Совместимость с Google Antigravity & IDE | 100% Нативная (без сбоев) | Часто сбоит при смене IP | Ломает валидацию сертификатов | Требует явной настройки прокси |
| Локальная скорость провайдера (Банки/Видео) | 100% Прямое соединение | Весь трафик замедляется | Ограничено локальным демоном | Только настроенные программы |
| Шифрование данных (E2E TLS) | Непрерывное (End-to-End) | Защищено туннелем | Расшифровывается в plaintext | Сквозное |
| Обход DPI блокировок | Высокий (WSS на 443 порт) | Часто блокируется по протоколу | Средний | Низкий (легко детектируется) |
| Потребление системных ресурсов | < 50 МБ RAM | 200–500 МБ RAM | 300+ МБ (Java / Python) | 20–50 МБ |
Пакетные правила для бесперебойной работы ключевых сервисов генеративного интеллекта.
ChatGPT Web, Whisper, DALL-E, API эндпоинты и CDN статических ресурсов oaistatic.com.
Платформа Antigravity, Gemini API, Vertex AI, Cloud Code тетрады и фоновые телеметрические шлюзы.
Веб-клиент grok.com, портал x.ai и сопутствующие сервисы потоковой генерации ответов.
Claude 3.5 Sonnet / Opus веб-интерфейс, организация сессий и фоновые WebSocket каналы.
Да, для корректной маршрутизации WebSocket в Cloudflare рекомендуется привязать любой дешевый домен (например, в зоне .online, .xyz или свой рабочий домен). Ворк-хост указывается в переменной WORKER_HOST в файлах bridge.mjs и docker-compose.yml.
Нет. bridge.mjs считывает только заголовок ClientHello, в котором серверное имя (SNI) передается открыто по спецификации TLS. Никакой расшифровки полезной нагрузки (payload) не происходит. Сессия TLS шифруется непосредственно между вашим браузером/IDE и сервером OpenAI/Google.
На Linux порт 53 часто резервируется службой systemd-resolved. В нашей документации подробно описано, как освободить порт или назначить слушающий интерфейс 127.0.0.1 без конфликтов с локальными резолверами.