Модуль stream в Nginx: полное руководство по настройке TCP/UDP прокси и балансировки | AdminWiki

Модуль stream в Nginx: полное руководство по настройке TCP/UDP прокси и балансировки

26 июля 2026 10 мин. чтения

Введение: что такое модуль stream и когда он нужен

Модуль stream в Nginx предназначен для работы с TCP и UDP трафиком на 4-м уровне модели OSI. В отличие от HTTP-модуля, он не анализирует заголовки запросов, cookies или URI. Его задача - принимать входящие соединения, устанавливать соединения с бэкендами и передавать байты в обе стороны с минимальными накладными расходами. Модуль доступен в стандартной поставке Nginx с версии 1.9.0 и не требует отдельной компиляции.

Типовые сценарии использования модуля stream: прокси для баз данных (MySQL, PostgreSQL), балансировка кэширующих систем (Redis, Memcached), организация отказоустойчивого доступа к почтовым серверам (SMTP, IMAP), проксирование DNS-запросов и любого другого трафика, который не является HTTP.

Минимальная рабочая конфигурация выглядит так:

stream {
    server {
        listen 3306;
        proxy_pass 192.168.1.10:3306;
    }
}

Эти четыре строки забирают TCP-соединения с порта 3306 и перенаправляют их на сервер 192.168.1.10:3306. Никакой дополнительной логики не требуется. Если вам нужна более сложная маршрутизация TCP/UDP трафика, сравнение подходов с HAProxy и готовые конфигурации с SSL-терминацией разобраны в руководстве по балансировке на уровне L4.

Базовая конфигурация TCP/UDP прокси

Конфигурация модуля stream размещается в блоке stream {}, который находится на одном уровне с блоками http {} и events {} в файле nginx.conf. Внутри блока stream определяются серверы (server {}), которые слушают порты и проксируют трафик.

Директива listen: порты и протоколы

Директива listen определяет, на каком IP-адресе и порту Nginx принимает соединения. Для TCP синтаксис стандартный, для UDP необходимо явно указать протокол.

Синтаксис:

listen адрес:порт [udp];

Примеры:

  • listen 3306; - принимать TCP-соединения на порту 3306 на всех интерфейсах;
  • listen 53 udp; - принимать UDP-датаграммы на порту 53;
  • listen 127.0.0.1:11211; - принимать TCP-соединения только на loopback-интерфейсе, порт 11211;
  • listen 10.0.0.1:5432; - привязка к конкретному IP-адресу.

Ошибка с UDP - одна из самых частых. Если не указать ключевое слово udp, Nginx будет ожидать TCP-соединения, и DNS-запросы или syslog-сообщения не дойдут до бэкенда.

Директива proxy_pass: куда отправлять трафик

Директива proxy_pass указывает адрес, на который Nginx будет проксировать входящие соединения. Можно передать IP-адрес с портом, имя upstream-группы или переменную.

Синтаксис:

proxy_pass адрес;

Примеры:

  • proxy_pass backend_mysql; - отправка трафика в upstream-группу backend_mysql;
  • proxy_pass 192.168.1.10:3306; - проксирование на конкретный сервер;
  • proxy_pass $backend; - динамический выбор бэкенда через переменную (например, на основе IP-адреса клиента через map).

Использование переменных в proxy_pass даёт гибкость: можно направить разных клиентов на разные бэкенды без изменения upstream-групп. Переменная вычисляется при каждом новом соединении.

Балансировка нагрузки с upstream

Upstream-группа в stream определяет пул серверов, между которыми Nginx распределяет входящие соединения. Директива upstream размещается внутри блока stream. Методы балансировки идентичны тем, что используются в HTTP-модуле, и выбираются под характер трафика конкретного сервиса.

Round-robin: равномерное распределение

Метод по умолчанию. Соединения распределяются между серверами последовательно, по кругу. Подходит для сервисов с короткоживущими соединениями и примерно одинаковой нагрузкой на каждый запрос.

stream {
    upstream dns_servers {
        server 10.0.0.1:53;
        server 10.0.0.2:53;
        server 10.0.0.3:53;
    }
    server {
        listen 53 udp;
        proxy_pass dns_servers;
    }
}

Этот пример распределяет DNS-запросы между тремя серверами. Каждый новый UDP-датаграммный сеанс уходит на следующий сервер в списке.

Least_conn: для долгоживущих соединений

Метод least_conn отправляет новое соединение на сервер с наименьшим количеством активных соединений. Приоритетен для баз данных и других сервисов, где клиенты держат постоянные соединения.

stream {
    upstream postgres_cluster {
        least_conn;
        server db1:5432;
        server db2:5432;
        server db3:5432;
    }
    server {
        listen 5432;
        proxy_pass postgres_cluster;
    }
}

PostgreSQL использует модель с отдельными соединениями на клиента. Если один сервер обрабатывает 50 соединений, а другой 5, least_conn направит нового клиента на второй сервер. Это предотвращает перегрузку отдельных узлов кластера.

Ip_hash: привязка клиента к серверу

Метод ip_hash вычисляет хэш от IP-адреса клиента и направляет все соединения с одного адреса на один и тот же бэкенд. Полезен для stateful-сервисов, где важна сессионная привязка.

stream {
    upstream redis_stateful {
        ip_hash;
        server redis1:6379;
        server redis2:6379;
    }
    server {
        listen 6379;
        proxy_pass redis_stateful;
    }
}

Предупреждение: ip_hash теряет эффективность, если клиенты находятся за NAT или общим прокси. Все пользователи офиса с одним внешним IP попадут на один сервер, создавая неравномерную нагрузку. В таких случаях лучше использовать least_conn или рассмотреть альтернативные прокси-решения.

Мониторинг и отказоустойчивость

Модуль stream не имеет встроенных активных health check в open-source версии Nginx. Активные проверки доступны в Nginx Plus или через сторонние патчи. Базовая версия полагается на пассивные проверки и резервные серверы.

Пассивные проверки: max_fails и fail_timeout

Пассивные проверки работают на основе неудачных попыток соединения. Параметры max_fails и fail_timeout задают порог отказов и время изоляции проблемного сервера.

stream {
    upstream mysql_production {
        server db1:3306 max_fails=3 fail_timeout=30s;
        server db2:3306 max_fails=3 fail_timeout=30s;
        server db3:3306 max_fails=3 fail_timeout=30s;
    }
    server {
        listen 3306;
        proxy_pass mysql_production;
    }
}

Логика работы: если Nginx трижды не может подключиться к db1, он помечает сервер как недоступный на 30 секунд. Трафик уходит на db2 и db3. Через 30 секунд Nginx пробует снова. Если соединение успешно, сервер возвращается в пул. Этот механизм защищает клиентов от guaranteed fail при отказе бэкенда.

Резервные серверы: backup

Сервер, помеченный как backup, получает трафик только тогда, когда все основные серверы недоступны. Это классический сценарий для катастрофоустойчивости.

stream {
    upstream smtp_ha {
        server mail1:25 max_fails=2 fail_timeout=10s;
        server mail2:25 max_fails=2 fail_timeout=10s;
        server mail_dr:25 backup;
    }
    server {
        listen 25;
        proxy_pass smtp_ha;
    }
}

В нормальном режиме работают mail1 и mail2. Если оба отказали, трафик уходит на mail_dr - сервер в другом дата-центре или с меньшей производительностью, который обеспечивает непрерывность сервиса.

Зона состояния: zone

Директива zone создаёт разделяемую область памяти для хранения состояния серверов upstream-группы. Это необходимо для сбора статистики и корректной работы параметров max_fails и fail_timeout в конфигурациях с несколькими рабочими процессами.

stream {
    upstream redis_monitored {
        zone redis_zone 64k;
        least_conn;
        server redis1:6379;
        server redis2:6379;
        server redis3:6379;
    }
    server {
        listen 6379;
        proxy_pass redis_monitored;
    }
}

Размер зоны 64 КБ достаточен для отслеживания десятков серверов. Статистику из зоны можно получить через API Nginx Plus или через stub_status при мониторинге производительности. Для глубокого контроля состояния бэкендов с визуализацией в Grafana используйте руководство по мониторингу upstream с health checks.

Логирование и отладка

Модуль stream поддерживает собственные директивы access_log и error_log, независимые от HTTP-логов. Это позволяет отделить записи о TCP/UDP соединениях от веб-трафика и настроить формат под конкретные нужды.

Настройка access_log

Лог соединений включается директивой access_log в контексте stream или server. Можно использовать предопределённые форматы или создать свой.

stream {
    log_format stream_log '$remote_addr [$time_local] $protocol $status '
                          '$bytes_sent $bytes_received $session_time';
    access_log /var/log/nginx/stream.log stream_log;
    
    server {
        listen 3306;
        proxy_pass mysql_backend;
    }
}

Переменные, доступные в формате stream:

  • $remote_addr - IP-адрес клиента;
  • $time_local - локальное время соединения;
  • $protocol - протокол (TCP или UDP);
  • $status - статус соединения (200 - успех, 502 - ошибка бэкенда);
  • $bytes_sent - количество отправленных клиенту байт;
  • $bytes_received - количество полученных от клиента байт;
  • $session_time - длительность сессии в секундах с миллисекундной точностью.

Использование error_log для диагностики

Уровень логирования ошибок настраивается от warn до debug. Debug-уровень включает максимально детальную информацию о каждом соединении, но генерирует огромный объём данных.

stream {
    error_log /var/log/nginx/stream_error.log debug;
    
    server {
        listen 5432;
        proxy_pass pg_backend;
    }
}

Используйте debug только для поиска проблем на тестовом окружении. В production достаточно уровня warn или error. После завершения отладки верните уровень логирования обратно - переполнение диска логами способно остановить сервер.

Production-кейсы: готовые конфигурации

Следующие конфигурации проверены на Nginx версий 1.26–1.28 в 2026 году и готовы к использованию после замены IP-адресов на ваши.

Прокси для MySQL

Единая точка входа для кластера MySQL с балансировкой по наименьшему числу соединений и пассивными проверками.

stream {
    upstream mysql {
        least_conn;
        server db1:3306 max_fails=3 fail_timeout=30s;
        server db2:3306 max_fails=3 fail_timeout=30s;
        server db3:3306 max_fails=3 fail_timeout=30s;
    }
    server {
        listen 3306;
        proxy_pass mysql;
        proxy_connect_timeout 5s;
        proxy_timeout 300s;
    }
}

Параметр proxy_connect_timeout ограничивает время ожидания подключения к бэкенду пятью секундами. Если сервер не отвечает, соединение быстро перебрасывается на другой узел. proxy_timeout задаёт максимальную длительность неактивного соединения - 300 секунд достаточно для большинства приложений.

Прокси для PostgreSQL

Аналогичная конфигурация для PostgreSQL на порту 5432.

stream {
    upstream postgresql {
        least_conn;
        server pg1:5432 max_fails=2 fail_timeout=15s;
        server pg2:5432 max_fails=2 fail_timeout=15s;
        server pg3:5432 max_fails=2 fail_timeout=15s;
    }
    server {
        listen 5432;
        proxy_pass postgresql;
        proxy_connect_timeout 3s;
    }
}

PostgreSQL использует отдельные долгоживущие соединения, поэтому least_conn здесь работает эффективно. Быстрый fail_timeout в 15 секунд ускоряет восстановление после кратковременных сбоев.

Балансировка Redis

Распределение нагрузки между экземплярами Redis с least_conn.

stream {
    upstream redis_cluster {
        least_conn;
        server redis1:6379 max_fails=3 fail_timeout=20s;
        server redis2:6379 max_fails=3 fail_timeout=20s;
        server redis3:6379 max_fails=3 fail_timeout=20s;
    }
    server {
        listen 6379;
        proxy_pass redis_cluster;
        proxy_timeout 600s;
    }
}

Важное ограничение: модуль stream не анализирует протокол Redis. Он не может маршрутизировать запросы по ключу или слоту. Для шардирования на уровне приложения используйте клиентские библиотеки Redis Cluster. Stream обеспечивает только балансировку TCP-соединений между экземплярами.

Балансировка Memcached

Настройка для Memcached аналогична Redis.

stream {
    upstream memcached_pool {
        least_conn;
        server mem1:11211 max_fails=2 fail_timeout=10s;
        server mem2:11211 max_fails=2 fail_timeout=10s;
        server mem3:11211 max_fails=2 fail_timeout=10s;
    }
    server {
        listen 11211;
        proxy_pass memcached_pool;
        proxy_connect_timeout 1s;
    }
}

Memcached-соединения обычно короткие, поэтому агрессивный fail_timeout в 10 секунд и быстрое переключение уместны.

Отказоустойчивый доступ к SMTP и IMAP

Обеспечение высокой доступности почтовых серверов с резервным узлом.

stream {
    upstream smtp {
        server mail1:25 max_fails=2 fail_timeout=30s;
        server mail2:25 max_fails=2 fail_timeout=30s;
        server mail_backup:25 backup;
    }
    upstream imap {
        server mail1:143 max_fails=2 fail_timeout=30s;
        server mail2:143 max_fails=2 fail_timeout=30s;
        server mail_backup:143 backup;
    }
    server {
        listen 25;
        proxy_pass smtp;
        proxy_connect_timeout 10s;
    }
    server {
        listen 143;
        proxy_pass imap;
        proxy_connect_timeout 10s;
    }
}

Резервный сервер mail_backup вступает в работу только при полном отказе основных. Это может быть менее мощный сервер в другом дата-центре, который поддерживает работу почты в аварийном режиме.

Ограничения и подводные камни

Модуль stream работает на 4-м уровне OSI и не анализирует протоколы прикладного уровня. Нельзя маршрутизировать соединения по HTTP-заголовкам, Redis-ключам или SQL-запросам. Для сложной маршрутизации на 7-м уровне потребуется HTTP-модуль Nginx или специализированные прокси вроде Envoy.

Метод ip_hash даёт сбой при массовом использовании NAT. Все клиенты за одним публичным IP попадают на один бэкенд. Решение: переключиться на least_conn или использовать Nginx Plus с sticky-сессиями.

UDP требует явного указания протокола в директиве listen. Пропуск ключевого слова udp - частая ошибка при настройке DNS или syslog прокси. Nginx будет молча ожидать TCP-соединения, и трафик не дойдёт до бэкенда.

Активные health check отсутствуют в open-source версии. Пассивные проверки через max_fails и fail_timeout реагируют только на факт отказа соединения, но не на деградацию сервиса (например, медленные ответы). Для проактивного мониторинга рассмотрите Nginx Plus или внешние инструменты.

Готовые конфигурации для типовых задач с комментариями собраны в подборке рабочих конфигураций Nginx для 2026 года. Если вы настраиваете веб-часть сервера параллельно с stream, используйте разбор структуры nginx.conf с практическими примерами.

Заключение: когда стоит использовать модуль stream

Модуль stream - оптимальный выбор, когда нужно проксировать или балансировать не-HTTP трафик в инфраструктуре, где уже используется Nginx. Единая конфигурация для HTTP и TCP/UDP упрощает управление, а производительность stream сопоставима с HAProxy на сопоставимом железе.

Используйте stream для:

  • проксирования баз данных (MySQL, PostgreSQL, MongoDB);
  • балансировки кэшей (Redis, Memcached);
  • отказоустойчивого доступа к почтовым серверам (SMTP, IMAP, POP3);
  • проксирования DNS (UDP) и syslog;
  • любого TCP/UDP трафика, где не нужен анализ содержимого пакетов.

Рассмотрите альтернативы, если требуется сложная маршрутизация на 7-м уровне, content-based switching или активные health check в open-source. В этих случаях подойдут HAProxy (богаче health check) или Envoy (для service mesh).

Для развёртывания отказоустойчивой инфраструктуры с Nginx stream на облачных серверах подойдёт Timeweb Cloud с гибким масштабированием VDS и управляемыми базами данных. Если вы автоматизируете генерацию конфигураций или документации, обратите внимание на AiTunnel - агрегатор API для доступа к GPT и Claude без VPN с оплатой в рублях.

Поделиться:
Сохранить гайд? В закладки браузера