Потоковый модуль#

Базовый потоковый модуль реализует основную функциональность для обработки TCP- и UDP-соединений: это определение серверных блоков, маршрутизация трафика, настройка проксирования, поддержка SSL/TLS и управление подключениями для потоковых сервисов, таких как базы данных, DNS и другие протоколы, работающие на основе TCP и UDP.

Остальные модули этого раздела расширяют эту функциональность, позволяя гибко настраивать и оптимизировать работу потокового сервера под различные сценарии и требования.

При сборке из исходного кода модуль не собирается по умолчанию; его необходимо включить с помощью параметра сборки ‑‑with‑stream. В пакетах и образах из наших репозиториев модуль включен в сборку.

Пример конфигурации#

worker_processes auto;

error_log /var/log/angie/error.log info;

events {
    worker_connections  1024;
}

stream {
    upstream backend {
        hash $remote_addr consistent;

        server backend1.example.com:12345 weight=5;
        server 127.0.0.1:12345            max_fails=3 fail_timeout=30s;
        server unix:/tmp/backend3;
    }

    upstream dns {
       server 192.168.0.1:53535;
       server dns.example.com:53;
    }

    server {
        listen 12345;
        proxy_connect_timeout 1s;
        proxy_timeout 3s;
        proxy_pass backend;
    }

    server {
        listen 127.0.0.1:53 udp reuseport;
        proxy_timeout 20s;
        proxy_pass dns;
    }

    server {
        listen [::1]:12345;
        proxy_pass unix:/tmp/stream.socket;
    }
}

Директивы#

listen#

Синтаксис

listen адрес[:порт] [ssl] [udp] [proxy_protocol] [setfib=число] [fastopen=число] [backlog=число] [rcvbuf=размер] [sndbuf=размер] [accept_filter=фильтр] [deferred] [bind] [ipv6only=on|off] [reuseport] [so_keepalive=on|off|[keepidle]:[keepintvl]:[keepcnt]];

По умолчанию

Контекст

server

Задает адрес и порт для сокета, на котором сервер будет принимать соединения. Можно указать только порт. Кроме того, адрес может быть именем хоста, например:

listen 127.0.0.1:12345;
listen *:12345;
listen 12345;     # то же, что и *:12345
listen localhost:12345;

IPv6-адреса задаются в квадратных скобках:

listen [::1]:12345;
listen [::]:12345;

UNIX-сокеты задаются префиксом unix:

listen unix:/var/run/angie.sock;

Диапазоны портов задаются при помощи указания первого и последнего порта через дефис:

listen 127.0.0.1:12345-12399;
listen 12345-12399;

Важно

Разные серверы должны слушать на разных парах адрес:порт.

ssl

указывает на то, что все соединения, принимаемые на данном слушающем сокете, должны работать в режиме SSL.

udp

конфигурирует слушающий сокет для работы с датаграммами. Для обработки пакетов с одного адреса и порта в рамках одной сессии необходимо также указывать параметр reuseport.

proxy_protocol

указывает на то, что все соединения, принимаемые на данном порту, должны использовать протокол PROXY.

В директиве listen можно также указать несколько дополнительных параметров, специфичных для связанных с сокетами системных вызовов.

setfib=число

устанавливает связанную таблицу маршрутизации, FIB (параметр SO_SETFIB) для слушающего сокета. Пока это работает только на FreeBSD.

fastopen=число

включает "TCP Fast Open" для слушающего сокета и ограничивает максимальную длину очереди соединений, которые еще не завершили процесс трехстороннего рукопожатия.

Осторожно

Не включайте "TCP Fast Open", не убедившись, что сервер может адекватно обрабатывать многократное получение одного и того же SYN-пакета с данными.

backlog=число

задает параметр backlog в вызове listen(), который ограничивает максимальный размер очереди ожидающих приема соединений. По умолчанию backlog устанавливается равным -1 для FreeBSD, DragonFly BSD и macOS, и 511 для других платформ.

rcvbuf=размер

задает размер буфера приема (параметр SO_RCVBUF) для слушающего сокета.

sndbuf=размер

задает размер буфера передачи (параметр SO_SNDBUF) для слушающего сокета.

accept_filter=фильтр

задает имя принимающего фильтра (параметр SO_ACCEPTFILTER) для слушающего сокета, который фильтрует входящие соединения перед их передачей в accept(). Работает только на FreeBSD и NetBSD 5.0+. Допустимые значения: dataready и httpready.

deferred

указывает использовать отложенный accept() (параметр TCP_DEFER_ACCEPT) на Linux.

bind

указывает, что для данного слушающего сокета нужно делать bind() отдельно. Это нужно потому, что если описаны несколько директив listen с одинаковым портом, но разными адресами, и одна из директив listen слушает на всех адресах для данного порта (*:порт), то Angie сделает bind() только на *:порт. Необходимо заметить, что в этом случае для определения адреса, на который пришло соединение, делается системный вызов getsockname(). Если же используются параметры setfib, fastopen, backlog, rcvbuf, sndbuf, accept_filter, deferred, ipv6only, reuseport или so_keepalive, то для данной пары адрес:порт всегда делается отдельный вызов bind().

ipv6only=on | off

определяет (через параметр сокета IPV6_V6ONLY), будет ли слушающий на wildcard-адресе [::] IPv6-сокет принимать только IPv6-соединения, или же одновременно IPv6- и IPv4-соединения.
По умолчанию параметр включен. Установить его можно только один раз на старте.

reuseport

указывает, что нужно создавать отдельный слушающий сокет для каждого рабочего процесса (через параметр сокета SO_REUSEPORT для Linux 3.9+ и DragonFly BSD или SO_REUSEPORT_LB для FreeBSD 12+), позволяя ядру распределять входящие соединения между рабочими процессами. В настоящий момент это работает только на Linux 3.9+, DragonFly BSD и FreeBSD 12+.

Осторожно

Ненадлежащее использование параметра reuseport может быть небезопасно.

so_keepalive=on | off | [keepidle]:[keepintvl]:[keepcnt]
конфигурирует для слушающего сокета поведение "TCP keepalive".

''

если параметр опущен, для сокета будут действовать настройки операционной системы

on

для сокета включается параметр SO_KEEPALIVE

off

для сокета параметр SO_KEEPALIVE выключается

Некоторые операционные системы поддерживают настройку параметров "TCP keepalive" на уровне сокета посредством параметров TCP_KEEPIDLE, TCP_KEEPINTVL и TCP_KEEPCNT. На таких системах их можно сконфигурировать с помощью параметров keepidle, keepintvl и keepcnt. Один или два параметра могут быть опущены, в таком случае для соответствующего параметра сокета будут действовать стандартные системные настройки.

Например,

so_keepalive=30m::10

установит таймаут бездействия (TCP_KEEPIDLE) в 30 минут, для интервала проб (TCP_KEEPINTVL) будет действовать стандартная системная настройка, а счетчик проб (TCP_KEEPCNT) будет равен 10.

preread_buffer_size#

Синтаксис

preread_buffer_size размер;

По умолчанию

preread_buffer_size 16k;

Контекст

stream, server

Задает размер буфера предварительного чтения.

preread_timeout#

Синтаксис

preread_timeout время;

По умолчанию

preread_timeout 30s;

Контекст

stream, server

Задает время фазы предварительного чтения.

proxy_protocol_timeout#

Синтаксис

proxy_protocol_timeout время;

По умолчанию

proxy_protocol_timeout 30s;

Контекст

stream, server

Задает время для завершения операции чтения заголовка протокола PROXY. Если по истечении этого времени заголовок полностью не получен, соединение закрывается.

resolver#

Синтаксис

resolver адрес ... [valid=время] [ipv4=on|off] [ipv6=on|off] [status_zone=зона];

По умолчанию

Контекст

stream, server, upstream

Задает серверы DNS, используемые для преобразования имен вышестоящих серверов в адреса, например:

resolver 127.0.0.53 [::1]:5353;

Адрес может быть указан в виде доменного имени или IP-адреса, и необязательного порта. Если порт не указан, используется порт 53. Серверы DNS опрашиваются циклически.

По умолчанию Angie кэширует ответы, используя значение TTL из ответа. Необязательный параметр valid позволяет это переопределить:

valid

необязательный параметр, позволяет переопределить срок кэширования ответа

resolver 127.0.0.53 [::1]:5353 valid=30s;

По умолчанию Angie будет искать как IPv4-, так и IPv6-адреса при преобразовании имен в адреса.

ipv4=off

запрещает поиск IPv4-адресов

ipv6=off

запрещает поиск IPv6-адресов

status_zone

необязательный параметр; включает сбор метрик запросов и ответов DNS-сервера (/status/resolvers/<zone>) в указанной зоне

Совет

Для предотвращения DNS-спуфинга рекомендуется использовать DNS-серверы в защищенной доверенной локальной сети.

resolver_timeout#

Синтаксис

resolver_timeout время;

По умолчанию

resolver_timeout 30s;

Контекст

stream, server, upstream

Задает таймаут для преобразования имени в адрес, например:

resolver_timeout 5s;

server#

Синтаксис

server { ... }

По умолчанию

Контекст

stream

Задает конфигурацию для сервера.

server_name#

Синтаксис

server_name имя ...;

По умолчанию

server_name "";

Контекст

server

Задает имена виртуального сервера, например:

server {
    server_name example.com www.example.com;
}

Первое имя становится основным именем сервера.

Имена серверов могут включать звездочку (*), заменяющую первую или последнюю часть имени:

server {
    server_name example.com *.example.com www.example.*;
}

Такие имена называются шаблонными именами.

Первые два примера, приведенные выше, можно объединить в один:

server {
    server_name .example.com;
}

Также можно использовать регулярные выражения в именах серверов, предваряя имя тильдой (~):

server {
    server_name www.example.com ~^www\d+\.example\.com$;
}

Регулярные выражения могут включать захваты, которые можно использовать в других директивах:

server {
    server_name ~^(www\.)?(.+)$;

    proxy_pass www.$2:12345;
}

Именованные захваты в регулярных выражениях создают переменные, которые можно использовать в других директивах:

server {
    server_name ~^(www\.)?(?<domain>.+)$;

    proxy_pass www.$domain:12345;
}

Если параметр директивы установлен на $hostname, будет вставлено имя хоста машины.

При поиске виртуального сервера по имени, если имя совпадает с более чем одним из указанных вариантов (например, совпадают и шаблонное имя, и регулярное выражение), будет выбрано первое совпавшее имя в следующем порядке приоритета:

  • Точное имя

  • Самое длинное шаблонное имя, начинающееся с звездочки, например, *.example.com

  • Самое длинное шаблонное имя, заканчивающееся звездочкой, например, mail.*

  • Первое совпавшее регулярное выражение (в порядке появления в конфигурационном файле)

Внимание

Для TLS-соединений используйте модуль SSL Preread.

server_names_hash_bucket_size#

Синтаксис

server_names_hash_bucket_size размер;

По умолчанию

server_names_hash_bucket_size 32|64|128;

Контекст

stream

Задает размер корзины для хэш-таблиц имен серверов. Значение по умолчанию зависит от размера кэш-линии процессора.

server_names_hash_max_size#

Синтаксис

server_names_hash_max_size размер;

По умолчанию

server_names_hash_max_size 512;

Контекст

stream

Задает максимальный размер хэш-таблиц имен серверов.

status_zone#

Синтаксис

status_zone зона;

По умолчанию

Контекст

server

Выделяет зону разделяемой памяти для сбора метрик /status/stream/server_zones/<zone>.

Несколько контекстов server могут совместно использовать одну и ту же зону для сбора данных.

stream#

Синтаксис

stream { ... }

По умолчанию

Контекст

main

Предоставляет контекст конфигурационного файла, в котором указываются директивы stream-сервера.

tcp_nodelay#

Синтаксис

tcp_nodelay on | off;

По умолчанию

tcp_nodelay on;

Контекст

stream, server

Разрешает или запрещает использование параметра TCP_NODELAY. Параметр включается как для клиентских соединений, так и для соединений с проксируемыми серверами.

variables_hash_bucket_size#

Синтаксис

variables_hash_bucket_size размер;

По умолчанию

variables_hash_bucket_size 64;

Контекст

stream

Задает размер корзины в хэш-таблице переменных. Подробнее настройка хэш-таблиц обсуждается отдельно.

variables_hash_max_size#

Синтаксис

variables_hash_max_size размер;

По умолчанию

variables_hash_max_size 1024;

Контекст

stream

Задает максимальный размер хэш-таблиц переменных. Подробнее настройка хэш-таблиц обсуждается отдельно.

Встроенные переменные#

Модуль stream core поддерживает встроенные переменные:

$angie_version#

версия Angie

$binary_remote_addr#

адрес клиента в бинарном виде, длина значения всегда 4 байта для IPv4-адресов или 16 байт для IPv6-адресов

$bytes_received#

число байт, полученных от клиента

$bytes_sent#

число байт, переданных клиенту

$connection#

порядковый номер соединения

$hostname#

имя хоста

$msec#

текущее время в секундах с точностью до миллисекунд

$pid#

номер (PID) рабочего процесса

$protocol#

протокол, используемый для работы с клиентом: TCP или UDP

$proxy_protocol_addr#

адрес клиента, полученный из заголовка протокола PROXY
Протокол PROXY должен быть предварительно включен при помощи установки параметра proxy_protocol в директиве listen.

$proxy_protocol_port#

порт клиента, полученный из заголовка протокола PROXY
Протокол PROXY должен быть предварительно включен при помощи установки параметра proxy_protocol в директиве listen.

$proxy_protocol_server_addr#

адрес сервера, полученный из заголовка протокола PROXY
Протокол PROXY должен быть предварительно включен при помощи установки параметра proxy_protocol в директиве listen.

$proxy_protocol_server_port#

порт сервера, полученный из заголовка протокола PROXY
Протокол PROXY должен быть предварительно включен при помощи установки параметра proxy_protocol в директиве listen.

$proxy_protocol_tlv_<имя>#

TLV, полученный из заголовка протокола PROXY. Имя может быть именем типа TLV или его числовым значением. В последнем случае значение задается в шестнадцатеричном виде и должно начинаться с 0x:

$proxy_protocol_tlv_alpn
$proxy_protocol_tlv_0x01

SSL TLV могут также быть доступны как по имени типа TLV, так и по его числовому значению, оба должны начинаться с ssl_:

$proxy_protocol_tlv_ssl_version
$proxy_protocol_tlv_ssl_0x21

Поддерживаются следующие имена типов TLV:

  • alpn (0x01) - протокол более высокого уровня, используемый поверх соединения

  • authority (0x02) - значение имени хоста, передаваемое клиентом

  • unique_id (0x05) - уникальный идентификатор соединения

  • netns (0x30) - имя пространства имен

  • ssl (0x20) - структура SSL TLV в бинарном виде

Поддерживаются следующие имена типов SSL TLV:

  • ssl_version (0x21) - версия SSL, используемая в клиентском соединении

  • ssl_cn (0x22) - Common Name сертификата

  • ssl_cipher (0x23) - имя используемого шифра

  • ssl_sig_alg (0x24) - алгоритм, используемый для подписи сертификата

  • ssl_key_alg (0x25) - алгоритм публичного ключа

Также поддерживается следующее специальное имя типа SSL TLV:

  • ssl_verify - результат проверки клиентского сертификата: 0, если клиент предоставил сертификат и он был успешно верифицирован, либо ненулевое значение

Протокол PROXY должен быть предварительно включен при помощи установки параметра proxy_protocol в директиве listen.

$remote_addr#

адрес клиента

$remote_port#

порт клиента

$server_addr#

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

$server_port#

порт сервера, принявшего соединение

$session_time#

длительность сессии в секундах с точностью до миллисекунд

$status#

статус сессии, может принимать одно из следующих значений:

200

сессия завершена успешно

400

невозможно разобрать данные, полученные от клиента, например заголовок протокола PROXY

403

доступ запрещен, например при ограничении доступа для определенных адресов клиентов

500

внутренняя ошибка сервера

502

плохой шлюз, например если невозможно выбрать сервер группы или сервер недоступен

503

сервис недоступен, например при ограничении по числу соединений

$time_iso8601#

локальное время в формате по стандарту ISO 8601

$time_local#

локальное время в Common Log Format