TCP и UDP туннелирование: как это работает
Большинство туннельных инструментов работают только с HTTP. А если вам нужно открыть доступ к PostgreSQL, игровому серверу или DNS-резолверу? Тут на сцену выходят TCP- и UDP-туннели. Если вы только знакомитесь с темой, начните со статьи «Что такое туннелирование».
Ниже мы разберём, как устроено туннелирование TCP и UDP изнутри: мультиплексирование, жизненный цикл пакетов, NAT traversal, фрейминг данных и реальные сценарии с fxTunnel.
TCP vs UDP: ключевые различия
Зачем вообще разбираться в протоколах, если мы просто пробрасываем трафик? Потому что TCP и UDP устроены принципиально по-разному, и туннель должен это учитывать.
| Характеристика | TCP | UDP |
|---|---|---|
| Соединение | Устанавливается (3-way handshake) | Без соединения |
| Гарантия доставки | Да (подтверждения, повторная передача) | Нет |
| Порядок пакетов | Гарантирован | Не гарантирован |
| Контроль потока | Да (скользящее окно) | Нет |
| Заголовок | 20–60 байт | 8 байт |
| Задержка | Выше (handshake + ACK) | Ниже (без установления соединения) |
| Типичное применение | Базы данных, SSH, HTTP, Redis | Игры, VoIP, DNS, IoT, видеостриминг |
| Поведение при потере пакета | Повторная передача | Пакет утерян |
Если коротко: TCP даёт надёжность ценой задержки, UDP жертвует надёжностью ради скорости. И при туннелировании каждый требует своего подхода.
Как работает TCP-туннелирование
TCP-туннель создаёт виртуальный канал между публичным портом на сервере и локальным портом на вашей машине. Все входящие TCP-соединения мультиплексируются через одно управляющее TLS-соединение между клиентом и сервером. Протокол TCP сам обеспечивает доставку и порядок, поэтому туннелю достаточно просто гонять байтовые потоки.
Жизненный цикл TCP-соединения через туннель
- Регистрация — клиент fxTunnel подключается к серверу и регистрирует TCP-туннель на указанный локальный порт.
- Выделение порта — сервер выделяет публичный порт (например,
tunnel.fxtun.dev:41234). - Входящее соединение — внешний клиент подключается к публичному порту, проходит TCP handshake с сервером.
- Мультиплексирование — сервер создаёт новый логический поток в мультиплексоре и передаёт данные клиенту fxTunnel.
- Локальное соединение — клиент fxTunnel устанавливает TCP-соединение с локальным сервисом и проксирует данные в обоих направлениях.
- Завершение — при закрытии любой из сторон соединение корректно завершается по всей цепочке.
Фрейминг и мультиплексирование TCP-потоков
Мультиплексирование — ключевой механизм TCP-туннелирования. Через одно физическое TLS-соединение между клиентом и сервером проходят десятки и сотни независимых TCP-потоков. Каждый поток имеет уникальный идентификатор, а данные разбиваются на фреймы с заголовком:
┌──────────────────────────────────────┐ │ Frame Header │ │ ┌──────────┬────────┬─────────────┐ │ │ │ Stream ID│ Length │ Flags │ │ │ │ (4 bytes)│(4 bytes)│ (1 byte) │ │ │ └──────────┴────────┴─────────────┘ │ │ ┌──────────────────────────────────┐ │ │ │ Payload (up to 64 KB) │ │ │ └──────────────────────────────────┘ │ └──────────────────────────────────────┘
Такой подход позволяет избежать создания отдельного TLS-соединения на каждый TCP-поток, что снижает overhead и ускоряет установку соединений. Подробнее об архитектуре мультиплексирования fxTunnel.
Схема TCP-туннелирования
Внешний клиент (psql, redis-cli, ssh)
│
│ TCP-соединение
▼
┌──────────────────────────────┐
│ fxTunnel Server │
│ Публичный порт: 41234 │
│ │
│ ┌────────────────────────┐ │
│ │ Мультиплексор │ │
│ │ Stream #1 ─┐ │ │
│ │ Stream #2 ─┼─► TLS │ │
│ │ Stream #N ─┘ conn │ │
│ └────────────────────────┘ │
└──────────────┬───────────────┘
│ одно TLS-соединение
│ (все потоки мультиплексированы)
▼
┌──────────────────────────────┐
│ fxTunnel Client │
│ │
│ ┌────────────────────────┐ │
│ │ Демультиплексор │ │
│ │ Stream #1 → :5432 │ │
│ │ Stream #2 → :5432 │ │
│ │ Stream #N → :5432 │ │
│ └────────────────────────┘ │
└──────────────────────────────┘
│
▼
localhost:5432
(PostgreSQL)
Каждый логический поток (Stream) соответствует одному TCP-соединению от внешнего клиента. Мультиплексор упаковывает данные всех потоков в единый TLS-канал, а демультиплексор на стороне клиента распаковывает их и направляет в локальный сервис.
Как работает UDP-туннелирование
С UDP всё заметно сложнее. Туннель должен сам отслеживать виртуальные сессии, инкапсулировать датаграммы внутри надёжного TCP-соединения и корректно обрабатывать NAT traversal. Именно поэтому большинство туннельных инструментов UDP просто не поддерживают.
Основные вызовы UDP-туннелирования
- Отсутствие состояния соединения — UDP не имеет handshake и не отслеживает соединения. Туннель должен создавать виртуальные сессии на основе пар адрес:порт отправителя.
- NAT traversal — без установленного соединения NAT-таблицы не гарантируют стабильную маршрутизацию. Туннель решает эту проблему, инкапсулируя датаграммы внутри TCP.
- Порядок и потеря пакетов — UDP не гарантирует ни порядок, ни доставку. Инкапсуляция в TCP добавляет гарантии на участке клиент-сервер, но конечный получатель по-прежнему работает с «сырым» UDP.
- Размер датаграмм — UDP-пакеты имеют фиксированные границы, которые нужно сохранить при инкапсуляции. Потоковый TCP не имеет понятия «пакет», поэтому требуется фрейминг.
Инкапсуляция UDP в TCP
fxTunnel решает проблему туннелирования UDP путём инкапсуляции датаграмм внутри фреймов TCP-соединения. Каждая UDP-датаграмма оборачивается в фрейм с метаданными: адрес отправителя, длина и идентификатор виртуальной сессии.
UDP-датаграмма от игрока
│
▼
┌──────────────────────────────┐
│ fxTunnel Server │
│ Публичный UDP-порт: 52001 │
│ │
│ ┌────────────────────────┐ │
│ │ Виртуальные сессии │ │
│ │ Addr A:1234 → Sess #1│ │
│ │ Addr B:5678 → Sess #2│ │
│ └────────────┬───────────┘ │
│ │ │
│ ┌────────────▼───────────┐ │
│ │ Инкапсуляция │ │
│ │ ┌──────┬──────┬─────┐ │ │
│ │ │SessID│ Len │ Data│ │ │
│ │ └──────┴──────┴─────┘ │ │
│ └────────────┬───────────┘ │
└───────────────┼──────────────┘
│ TLS-соединение (TCP)
▼
┌──────────────────────────────┐
│ fxTunnel Client │
│ │
│ ┌────────────────────────┐ │
│ │ Декапсуляция │ │
│ │ Sess #1 → UDP :27015 │ │
│ │ Sess #2 → UDP :27015 │ │
│ └────────────────────────┘ │
└──────────────────────────────┘
│
▼
localhost:27015
(игровой сервер)
На стороне сервера входящие UDP-датаграммы группируются по виртуальным сессиям (на основе адреса и порта отправителя), инкапсулируются во фреймы и передаются клиенту через TLS-соединение. Клиент декапсулирует фреймы и отправляет «сырые» UDP-датаграммы на локальный порт. Ответные датаграммы идут обратным путём.
Управление виртуальными сессиями
Поскольку UDP не имеет понятия «соединение», fxTunnel создаёт виртуальные сессии с таймаутом неактивности. Если от конкретного отправителя не поступает датаграмм в течение заданного времени (по умолчанию 60 секунд), сессия удаляется и ресурсы освобождаются. Это предотвращает утечку памяти при большом количестве кратковременных UDP-клиентов.
Сценарии использования TCP-туннелей
Нужно открыть доступ к сервису, который работает по TCP? Вот самые частые ситуации.
Базы данных (PostgreSQL, MySQL)
# Пробрасываем PostgreSQL
fxtunnel tcp 5432
# → tunnel.fxtun.dev:41234
# Подключаемся с удалённой машины
psql -h tunnel.fxtun.dev -p 41234 -U myuser mydb
Это позволяет дать коллеге или CI-серверу доступ к локальной базе данных без деплоя и конфигурации сети.
SSH-доступ
# Пробрасываем SSH
fxtunnel tcp 22
# → tunnel.fxtun.dev:43210
# Подключаемся к машине за NAT
ssh -p 43210 user@tunnel.fxtun.dev
TCP-туннель для SSH позволяет получить доступ к машине за NAT без статического IP и проброса портов. Идеально для Raspberry Pi и домашних серверов.
Redis и кэш-серверы
# Пробрасываем Redis
fxtunnel tcp 6379
# → tunnel.fxtun.dev:44567
# Подключаемся с любой машины
redis-cli -h tunnel.fxtun.dev -p 44567
Сценарии использования UDP-туннелей
В приложениях реального времени главное — минимальная задержка, а не гарантия доставки каждого пакета. Здесь UDP-туннели незаменимы.
Игровые серверы
# Пробрасываем игровой сервер (например, Counter-Strike, Minecraft)
fxtunnel udp 27015
# → tunnel.fxtun.dev:52001
# Игроки подключаются через публичный адрес
Игровые серверы работают по UDP, потому что потеря одного пакета с координатами игрока менее критична, чем задержка при повторной передаче.
DNS-сервер
# Пробрасываем локальный DNS
fxtunnel udp 53
# → tunnel.fxtun.dev:53001
# Тестируем DNS-запросы
dig @tunnel.fxtun.dev -p 53001 example.com
VoIP и IoT
VoIP (SIP, RTP), потоковое видео и IoT-устройства работают по UDP, потому что задержка критичнее потери отдельных пакетов. Через туннель можно пробросить любой UDP-порт наружу без возни с NAT.
Как fxTunnel обрабатывает оба протокола
fxTunnel мультиплексирует TCP-потоки и инкапсулированные UDP-датаграммы через единое управляющее TLS-соединение. Это ключевое архитектурное решение: один клиент может одновременно держать HTTP, TCP и UDP туннели, и все они используют один зашифрованный канал до сервера. Подробнее об архитектуре fxTunnel.
┌─────────────────────────────────────────────┐ │ Единое TLS-соединение клиент ↔ сервер │ │ │ │ ┌─────────────┐ ┌───────────┐ ┌─────────┐ │ │ │ HTTP streams│ │TCP streams│ │UDP frames│ │ │ │ (мультиплекс)│(мультиплекс)│(инкапсул.)│ │ │ └─────────────┘ └───────────┘ └─────────┘ │ │ │ │ Control plane: регистрация, heartbeat, │ │ управление туннелями │ └─────────────────────────────────────────────┘
Преимущества единого соединения:
- Одна точка аутентификации — токен проверяется один раз при подключении.
- Минимальный overhead — не нужно устанавливать отдельное TLS-соединение для каждого туннеля.
- Простота для файрвола — весь трафик идёт через один исходящий порт.
- Быстрое переподключение — при разрыве восстанавливается одно соединение, и все туннели возобновляют работу.
Подробное сравнение с ngrok и Cloudflare Tunnel — в отдельной статье. Если коротко: fxTunnel — один из немногих инструментов, который поддерживает UDP наряду с HTTP и TCP.
Практические примеры с fxTunnel
Установка
# Установка fxTunnel (Linux/macOS)
curl -fsSL https://fxtun.dev/install.sh | bash
TCP-туннели
# PostgreSQL — доступ к локальной БД
fxtunnel tcp 5432
# Redis — доступ к локальному кэшу
fxtunnel tcp 6379
# SSH — удалённый доступ к машине за NAT
fxtunnel tcp 22
UDP-туннели
# Игровой сервер — игроки подключаются через публичный адрес
fxtunnel udp 27015
# DNS — тестирование локального DNS-сервера
fxtunnel udp 53
После запуска fxTunnel выведет публичный адрес:
fxTunnel v1.x — tunnel is active
Protocol: TCP
Public addr: tunnel.fxtun.dev:41234
Forwarding: tunnel.fxtun.dev:41234 → localhost:5432
Press Ctrl+C to stop
Подробнее о том, как открыть localhost для доступа из интернета.
FAQ
В чём разница между TCP и UDP туннелем?
TCP-туннель передаёт потоковые соединения с гарантированной доставкой и порядком пакетов — то, что нужно для баз данных, SSH и Redis. UDP-туннель работает с датаграммами без установления соединения — подходит для игр, VoIP и DNS, где скорость важнее полноты доставки.
Поддерживает ли fxTunnel одновременно TCP и UDP?
Да, через один и тот же CLI доступны HTTP, TCP и UDP туннели. У большинства конкурентов — только HTTP и TCP (ngrok) или вообще один HTTP в бесплатном тарифе (Cloudflare Tunnel).
Почему UDP-туннелирование сложнее TCP?
Потому что у UDP нет понятия соединения. Туннелю приходится самостоятельно придумывать виртуальные сессии (по парам адрес:порт), оборачивать каждую датаграмму во фрейм на TCP-линке до сервера и решать вопросы NAT traversal. С TCP проще — протокол сам берёт на себя надёжность и порядок.
Какую задержку добавляет TCP/UDP туннель?
Ориентируйтесь на +1–5 мс поверх базовой задержки сети. Для TCP-сервисов (базы данных, SSH) это практически незаметно. У UDP-приложений (игры, VoIP) overhead чуть выше из-за инкапсуляции датаграмм, но для большинства сценариев он приемлем.
Можно ли пробросить PostgreSQL или Redis через туннель?
Конечно. Запустите fxtunnel tcp 5432 для PostgreSQL или fxtunnel tcp 6379 для Redis — и вы получите публичный адрес, по которому можно подключиться откуда угодно.