Назад к блогу

WebSocket через прокси: полное руководство по проксированию WS и WSS соединений

WebSocket-соединения работают иначе, чем обычные HTTP-запросы — и стандартные прокси часто их обрывают. Разбираемся, как правильно проксировать WS и WSS трафик без потери соединения.

📅7 августа 2026 г.

WebSocket — это не обычный HTTP-запрос. После первоначального «рукопожатия» (handshake) соединение остаётся открытым, и данные идут в обе стороны непрерывным потоком. Именно поэтому стандартные HTTP-прокси часто обрывают WS-соединения или вообще не умеют их обрабатывать. В этой статье разберём, как правильно проксировать WebSocket-трафик: какие прокси подходят, как их настроить и какие ошибки встречаются чаще всего.

Как работает WebSocket и почему он сложен для прокси

Чтобы понять проблему, нужно разобраться в механике. WebSocket-соединение начинается как обычный HTTP-запрос — клиент отправляет заголовок Upgrade: websocket и Connection: Upgrade. Сервер отвечает кодом 101 Switching Protocols — и с этого момента соединение перестаёт быть HTTP. Оно превращается в постоянный двунаправленный канал, по которому данные идут во фреймах.

Стандартный HTTP/1.1-прокси, который умеет только пересылать запросы и ответы, сталкивается с проблемой: он не знает, что делать с соединением после ответа 101. Многие прокси-серверы просто закрывают соединение в этот момент или возвращают ошибку 502 Bad Gateway. Другие держат соединение, но не умеют корректно передавать WebSocket-фреймы, что приводит к обрывам или искажению данных.

Вот ключевые отличия WebSocket от обычного HTTP с точки зрения проксирования:

Параметр HTTP WebSocket
Тип соединения Запрос → Ответ → Закрытие Постоянное, двунаправленное
Время жизни Секунды (один запрос) Минуты, часы, дни
Инициатор данных Только клиент Клиент и сервер
Протокол после handshake HTTP Собственный (RFC 6455)
Порты 80, 443 80 (WS), 443 (WSS)

Именно из-за смены протокола после handshake большинство простых прокси-решений не справляются с WebSocket. Нужно либо использовать прокси, который явно поддерживает туннелирование, либо применять SOCKS5 — протокол, который работает на более низком уровне и не разбирает содержимое трафика.

Какие типы прокси поддерживают WebSocket

Не все прокси одинаково полезны для WebSocket. Разберём каждый тип:

Тип прокси Поддержка WS Механизм Сложность
HTTP-прокси ⚠️ Частично Через CONNECT-туннель Средняя
HTTPS-прокси ✅ Да CONNECT + TLS Средняя
SOCKS4 ⚠️ Ограниченно TCP-туннель без auth Низкая
SOCKS5 ✅ Полная Прозрачный TCP/UDP Низкая
Transparent proxy ❌ Нет Только HTTP

Вывод: для WebSocket-задач оптимальным выбором является SOCKS5. Этот протокол работает на транспортном уровне и просто туннелирует TCP-соединение, не вникая в содержимое трафика. Ему всё равно, идёт ли внутри HTTP, WebSocket, SSH или что-то ещё. HTTP-прокси тоже могут работать с WS, но только через метод CONNECT — и здесь есть нюансы, которые разберём ниже.

Метод CONNECT: как HTTP-прокси туннелирует WebSocket

HTTP-метод CONNECT — это специальный механизм, который позволяет HTTP-прокси создавать «слепой» туннель до целевого сервера. Прокси не анализирует трафик внутри туннеля, а просто перенаправляет байты. Именно так работает HTTPS через HTTP-прокси — и именно так можно проксировать WebSocket.

Процесс выглядит следующим образом:

  1. Клиент отправляет прокси запрос: CONNECT example.com:443 HTTP/1.1
  2. Прокси устанавливает TCP-соединение с example.com:443
  3. Прокси отвечает клиенту: 200 Connection Established
  4. С этого момента прокси просто передаёт байты туда и обратно — не разбирая их
  5. Клиент выполняет TLS-handshake напрямую с сервером через туннель
  6. Затем — WebSocket-handshake поверх TLS

Ключевое ограничение: метод CONNECT обычно разрешён только для порта 443. Если ваш WebSocket-сервер работает на нестандартном порту (например, 8080 или 9000), прокси может отклонить соединение. В этом случае SOCKS5 предпочтительнее — он не имеет ограничений по портам.

Также важно учитывать, что некоторые корпоративные HTTP-прокси (например, Squid в стандартной конфигурации) явно блокируют метод CONNECT для определённых портов или требуют аутентификацию. Если вы работаете с коммерческими прокси-провайдерами, большинство из них поддерживают CONNECT без ограничений.

# Пример CONNECT-запроса через curl (для проверки)
curl -v -x http://proxy_host:proxy_port \
  --proxytunnel \
  https://echo.websocket.org

# Если прокси поддерживает CONNECT — вы увидите:
# * CONNECT tunnel established, response 200

SOCKS5 и WebSocket: почему это лучший вариант

SOCKS5 — это протокол проксирования на уровне TCP/UDP-соединений. В отличие от HTTP-прокси, SOCKS5 не знает ничего о прикладном протоколе, который идёт внутри. Он просто создаёт туннель между клиентом и целевым сервером, и всё. Это делает его идеальным для WebSocket по нескольким причинам:

  • Нет ограничений по протоколу: SOCKS5 туннелирует любой TCP-трафик, включая WS, WSS, SSH, FTP и т.д.
  • Нет ограничений по портам: работает с любым портом, не только 443 или 80
  • Нет разрыва при смене протокола: прокси не «видит» переход от HTTP к WebSocket
  • Поддержка аутентификации: SOCKS5 поддерживает логин/пароль, что удобно для коммерческих прокси
  • Поддержка UDP: если ваше приложение использует WebRTC или UDP рядом с WS — SOCKS5 справится

Практически все современные библиотеки для работы с WebSocket поддерживают SOCKS5 либо напрямую, либо через дополнительные пакеты. Ниже рассмотрим конкретные примеры для Python и Node.js.

💡 Когда выбирать SOCKS5, а когда HTTP CONNECT?

Используйте SOCKS5, если: нестандартный порт, нужна поддержка UDP, хотите минимум настроек.
Используйте HTTP CONNECT, если: прокси-провайдер не поддерживает SOCKS5, или вы работаете через корпоративный прокси.

Примеры кода: WebSocket через прокси на Python

Рассмотрим несколько сценариев для Python. Самые популярные библиотеки для WebSocket в Python — это websockets и websocket-client.

Вариант 1: websocket-client через HTTP-прокси

import websocket

# Настройки HTTP-прокси
proxy_host = "proxy.example.com"
proxy_port = 8080
proxy_user = "username"
proxy_pass = "password"

ws = websocket.WebSocket()

ws.connect(
    "wss://echo.websocket.org",
    http_proxy_host=proxy_host,
    http_proxy_port=proxy_port,
    http_proxy_auth=(proxy_user, proxy_pass),
    proxy_type="http"  # или "socks5"
)

ws.send("Hello, WebSocket!")
result = ws.recv()
print(f"Получено: {result}")

ws.close()

Вариант 2: websocket-client через SOCKS5

import websocket

# Для SOCKS5 нужен пакет: pip install PySocks
ws = websocket.WebSocket()

ws.connect(
    "wss://echo.websocket.org",
    http_proxy_host="socks5_proxy.example.com",
    http_proxy_port=1080,
    http_proxy_auth=("username", "password"),
    proxy_type="socks5"
)

ws.send("Test message")
print(ws.recv())
ws.close()

Вариант 3: библиотека websockets (asyncio) через SOCKS5

Библиотека websockets (asyncio) не имеет встроенной поддержки прокси, поэтому используем python-socks для создания туннеля:

# pip install websockets python-socks[asyncio]
import asyncio
import websockets
from python_socks.async_.asyncio import Proxy

async def connect_via_socks5():
    proxy = Proxy.from_url("socks5://username:[email protected]:1080")
    
    # Создаём TCP-соединение через прокси
    sock = await proxy.connect(
        dest_host="echo.websocket.org",
        dest_port=443
    )
    
    # Передаём сокет в websockets
    async with websockets.connect(
        "wss://echo.websocket.org",
        sock=sock
    ) as ws:
        await ws.send("Hello via SOCKS5!")
        response = await ws.recv()
        print(f"Ответ: {response}")

asyncio.run(connect_via_socks5())

Вариант 4: глобальный патч через PySocks

Если вы хотите направить весь трафик Python-приложения через SOCKS5 без изменения каждого вызова — используйте socks.setdefaultproxy():

# pip install PySocks
import socks
import socket
import websocket

# Патчим socket глобально
socks.set_default_proxy(
    socks.SOCKS5,
    "proxy.example.com",
    1080,
    username="user",
    password="pass"
)
socket.socket = socks.socksocket

# Теперь все соединения идут через SOCKS5
ws = websocket.WebSocket()
ws.connect("wss://echo.websocket.org")
ws.send("Global SOCKS5 proxy!")
print(ws.recv())
ws.close()

Примеры кода: WebSocket через прокси на Node.js

В экосистеме Node.js наиболее популярная библиотека для WebSocket — ws. Для проксирования через HTTP/SOCKS5 используется пакет https-proxy-agent или socks-proxy-agent.

Вариант 1: WSS через HTTP CONNECT прокси

// npm install ws https-proxy-agent
const WebSocket = require('ws');
const { HttpsProxyAgent } = require('https-proxy-agent');

const proxyUrl = 'http://username:[email protected]:8080';
const agent = new HttpsProxyAgent(proxyUrl);

const ws = new WebSocket('wss://echo.websocket.org', { agent });

ws.on('open', () => {
  console.log('Соединение установлено через HTTP-прокси');
  ws.send('Hello from Node.js!');
});

ws.on('message', (data) => {
  console.log(`Получено: ${data}`);
  ws.close();
});

ws.on('error', (err) => {
  console.error('Ошибка:', err.message);
});

Вариант 2: WSS через SOCKS5

// npm install ws socks-proxy-agent
const WebSocket = require('ws');
const { SocksProxyAgent } = require('socks-proxy-agent');

const proxyUrl = 'socks5://username:[email protected]:1080';
const agent = new SocksProxyAgent(proxyUrl);

const ws = new WebSocket('wss://echo.websocket.org', { agent });

ws.on('open', () => {
  console.log('Соединение через SOCKS5 установлено');
  ws.send(JSON.stringify({ type: 'ping', data: 'test' }));
});

ws.on('message', (data) => {
  console.log('Ответ:', data.toString());
});

ws.on('close', (code, reason) => {
  console.log(`Закрыто: ${code} - ${reason}`);
});

Вариант 3: WS (без TLS) через HTTP-прокси вручную

Для нешифрованного WS (порт 80) через HTTP-прокси нужно вручную отправить CONNECT-запрос, так как стандартные агенты часто работают только с HTTPS:

const net = require('net');
const WebSocket = require('ws');

function createTunnel(proxyHost, proxyPort, targetHost, targetPort) {
  return new Promise((resolve, reject) => {
    const socket = net.connect(proxyPort, proxyHost, () => {
      const connectReq = 
        `CONNECT ${targetHost}:${targetPort} HTTP/1.1\r\n` +
        `Host: ${targetHost}:${targetPort}\r\n` +
        `Proxy-Authorization: Basic ${Buffer.from('user:pass').toString('base64')}\r\n` +
        `\r\n`;
      
      socket.write(connectReq);
    });

    socket.once('data', (data) => {
      if (data.toString().includes('200')) {
        resolve(socket);
      } else {
        reject(new Error(`Прокси отклонил CONNECT: ${data.toString()}`));
      }
    });

    socket.on('error', reject);
  });
}

async function main() {
  const socket = await createTunnel(
    'proxy.example.com', 8080,
    'echo.websocket.org', 80
  );

  const ws = new WebSocket('ws://echo.websocket.org', { socket });
  
  ws.on('open', () => {
    ws.send('Manual CONNECT tunnel!');
  });

  ws.on('message', (data) => {
    console.log('Получено:', data.toString());
    ws.close();
  });
}

main().catch(console.error);

WSS (WebSocket Secure): особенности проксирования с TLS

WSS — это WebSocket поверх TLS (аналогично HTTPS для HTTP). При проксировании WSS через SOCKS5 или HTTP CONNECT возникает важный нюанс: TLS-шифрование устанавливается между клиентом и конечным сервером, а не между клиентом и прокси. Это означает:

  • Прокси-сервер не видит содержимое WSS-трафика — только IP-адрес и порт назначения
  • Сертификат сервера проверяется клиентом напрямую
  • Прокси не может «подменить» или «перехватить» данные без установки собственного CA-сертификата

Это хорошая новость с точки зрения безопасности. Но есть и практические нюансы при настройке:

Проверка сертификата через прокси

Иногда при использовании корпоративных прокси (которые делают SSL-инспекцию) вы можете получить ошибку проверки сертификата. В этом случае прокси подменяет сертификат сервера своим. Для работы в таком окружении нужно добавить CA-сертификат прокси в доверенные:

# Python: передаём CA-сертификат корпоративного прокси
import ssl
import websocket

ssl_context = ssl.create_default_context()
ssl_context.load_verify_locations("/path/to/corporate-ca.crt")

ws = websocket.WebSocket(sslopt={"context": ssl_context})
ws.connect(
    "wss://internal.example.com",
    http_proxy_host="corp-proxy.company.com",
    http_proxy_port=8080,
    proxy_type="http"
)

# В тестовых средах (НЕ для продакшена!) можно отключить проверку:
ws_test = websocket.WebSocket(sslopt={"cert_reqs": ssl.CERT_NONE})
ws_test.connect("wss://test.example.com", http_proxy_host="proxy", http_proxy_port=8080)

⚠️ Важно

Отключение проверки TLS-сертификата (CERT_NONE) допустимо только в тестовой среде. В продакшене это создаёт уязвимость для атак типа MITM (man-in-the-middle).

SNI (Server Name Indication) через прокси

При использовании SOCKS5 клиент может самостоятельно разрешать DNS или делегировать это прокси. Режим socks5h (SOCKS5 with hostname resolution) означает, что DNS-запрос выполняется на стороне прокси-сервера. Это важно для WSS, так как SNI-заголовок в TLS-handshake должен совпадать с именем хоста:

# socks5  — DNS разрешается локально (клиентом)
# socks5h — DNS разрешается прокси-сервером (рекомендуется для анонимности)

from python_socks.async_.asyncio import Proxy

# DNS через прокси (рекомендуется):
proxy = Proxy.from_url("socks5h://user:[email protected]:1080")

# DNS локально:
proxy = Proxy.from_url("socks5://user:[email protected]:1080")

Типичные ошибки и как их исправить

Собрали самые частые проблемы при проксировании WebSocket с решениями:

Ошибка 1: 407 Proxy Authentication Required

Прокси требует аутентификацию, но вы не передали учётные данные или передали их неверно.

# ❌ Неверно — нет авторизации
ws.connect("wss://example.com", http_proxy_host="proxy.example.com", http_proxy_port=8080)

# ✅ Верно — передаём логин и пароль
ws.connect(
    "wss://example.com",
    http_proxy_host="proxy.example.com",
    http_proxy_port=8080,
    http_proxy_auth=("username", "password")
)

Ошибка 2: Connection reset by peer / 502 Bad Gateway

Прокси не поддерживает WebSocket или метод CONNECT. Решение: переключитесь на SOCKS5 или проверьте, поддерживает ли ваш провайдер WebSocket-трафик.

Ошибка 3: Соединение обрывается через 30-60 секунд

Многие прокси-серверы закрывают «неактивные» TCP-соединения по таймауту. WebSocket-соединение может выглядеть неактивным, если нет обмена данными. Решение — включить ping/pong:

# Python — включаем keepalive ping каждые 20 секунд
import websocket
import threading

def run():
    ws = websocket.WebSocketApp(
        "wss://echo.websocket.org",
        on_message=lambda ws, msg: print(msg),
        on_error=lambda ws, err: print(f"Ошибка: {err}"),
        on_close=lambda ws, c, m: print("Закрыто")
    )
    ws.run_forever(
        ping_interval=20,   # отправлять ping каждые 20 сек
        ping_timeout=10,    # ждать pong не более 10 сек
        http_proxy_host="proxy.example.com",
        http_proxy_port=8080,
        proxy_type="socks5"
    )

thread = threading.Thread(target=run)
thread.start()

Ошибка 4: SSL: CERTIFICATE_VERIFY_FAILED

Чаще всего возникает при использовании корпоративного прокси с SSL-инспекцией. Решение: добавьте CA-сертификат прокси в доверенные (см. раздел выше) или используйте SOCKS5 вместо HTTP-прокси — SOCKS5 не делает SSL-инспекцию.

Ошибка 5: Handshake status 403 Forbidden

Целевой сервер блокирует соединение. Причины: IP прокси занесён в чёрный список, отсутствуют нужные заголовки (Origin, User-Agent), или сервер блокирует трафик из дата-центров. Решение: используйте резидентные прокси с реальными IP домашних пользователей — их значительно сложнее заблокировать.

Ошибка 6: [Errno 111] Connection refused

Прокси-сервер недоступен: неверный хост/порт, или прокси не запущен. Проверьте данные подключения и доступность прокси через простой HTTP-запрос перед тестированием WebSocket.

Какой тип прокси выбрать для WebSocket-задач

Выбор типа прокси зависит от конкретной задачи. Вот практическое руководство:

Задача Рекомендуемый тип Почему
Парсинг через WS (биржи, финансовые данные) Прокси дата-центров Высокая скорость, низкая задержка, стабильное соединение
Обход блокировок WebSocket-сервисов Резидентные прокси Реальные IP, минимальный риск блокировки
Мобильные приложения с WS (работа с мобильными API) Мобильные прокси IP мобильных операторов — высокое доверие со стороны сервисов
Нагрузочное тестирование WS-сервера Прокси дата-центров Дёшево, быстро, много одновременных соединений
Геолокационное тестирование WS Резидентные прокси Большой выбор стран и городов

Важные параметры прокси для WebSocket

При выборе прокси-провайдера для WebSocket-задач обращайте внимание на следующие параметры:

  • Поддержка SOCKS5: убедитесь, что провайдер предоставляет SOCKS5, а не только HTTP
  • Время сессии (session duration): для WebSocket важны «sticky» сессии — один IP на длительное время. Ротируемые прокси будут обрывать соединение
  • Таймаут соединения: прокси должен поддерживать долгоживущие TCP-соединения (от нескольких минут до часов)
  • Пропускная способность: для потокового WebSocket (видео, биржевые данные) важна высокая пропускная способность без ограничений
  • Задержка (latency): для финансовых приложений и торговых ботов критична минимальная задержка — выбирайте прокси с серверами ближе к целевому сервису

💡 Проверка поддержки WebSocket прокси-провайдером

Прежде чем покупать прокси для WebSocket-задач, протестируйте их через бесплатный эхо-сервер: wss://echo.websocket.org или wss://ws.postman-echo.com/raw. Если соединение устанавливается и сообщения возвращаются — прокси работает с WebSocket корректно.

Настройка sticky-сессии для WebSocket

Большинство провайдеров резидентных прокси используют ротацию IP по умолчанию. Для WebSocket это неприемлемо — каждая смена IP означает разрыв соединения. Убедитесь, что вы используете режим sticky session (фиксированный IP). Обычно это делается через специальный формат URL прокси:

# Пример формата sticky-сессии (зависит от провайдера):
# Ротируемый (НЕ подходит для WebSocket):
socks5://user:[email protected]:1080

# Sticky-сессия (подходит для WebSocket):
socks5://user-session-abc123:[email protected]:1080

# Или через параметр страны и сессии:
socks5://user-country-us-session-12345:[email protected]:1080

Заключение

WebSocket — это не просто «HTTP с долгим соединением». Это отдельный протокол, который требует особого подхода при проксировании. Главные выводы из этой статьи:

  • SOCKS5 — оптимальный выбор для WebSocket: работает на транспортном уровне, не разбирает протокол, поддерживает любые порты
  • HTTP-прокси через CONNECT тоже работает, но с ограничениями по портам и возможными проблемами с SSL-инспекцией
  • Sticky-сессии обязательны: ротируемые прокси будут обрывать WebSocket-соединение при каждой смене IP
  • Ping/pong keepalive необходим для предотвращения разрыва соединения по таймауту прокси
  • WSS через прокси безопасен: TLS-шифрование устанавливается напрямую между клиентом и сервером, прокси не видит содержимое

Если вы разрабатываете приложение, которое работает с WebSocket через прокси — начните с SOCKS5 и sticky-сессий. Это сэкономит вам часы отладки. Для задач, где важна высокая скорость и стабильность соединения (торговые боты, стриминг данных), отлично подойдут прокси дата-центров с низкой задержкой. Если же целевой сервис активно блокирует дата-центровые IP — рассмотрите резидентные прокси: они имеют реальные IP домашних пользователей и значительно реже попадают под блокировки даже при длительных WebSocket-сессиях.