Потоковый модуль#
Базовый потоковый модуль реализует основную функциональность для обработки 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#
|
|
По умолчанию |
— |
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. |
|
конфигурирует слушающий сокет для работы с датаграммами. Для обработки пакетов с одного адреса и порта в рамках одной сессии необходимо также указывать параметр reuseport. |
|
указывает на то, что все соединения, принимаемые на данном порту, должны использовать протокол PROXY. |
В директиве listen можно также указать несколько дополнительных параметров, специфичных для связанных с сокетами системных вызовов.
|
устанавливает связанную таблицу маршрутизации, FIB (параметр
|
|
включает "TCP Fast Open" для слушающего сокета и ограничивает максимальную длину очереди соединений, которые еще не завершили процесс трехстороннего рукопожатия. |
Осторожно
Не включайте "TCP Fast Open", не убедившись, что сервер может адекватно обрабатывать многократное получение одного и того же SYN-пакета с данными.
|
задает параметр backlog в вызове listen(), который ограничивает максимальный размер очереди ожидающих приема соединений. По умолчанию backlog устанавливается равным -1 для FreeBSD, DragonFly BSD и macOS, и 511 для других платформ. |
|
задает размер буфера приема (параметр SO_RCVBUF) для слушающего сокета. |
|
задает размер буфера передачи (параметр SO_SNDBUF) для слушающего сокета. |
|
задает имя принимающего фильтра (параметр |
|
указывает использовать отложенный |
|
указывает, что для данного слушающего сокета нужно делать bind() отдельно. Это нужно потому, что если описаны несколько директив listen с одинаковым портом, но разными адресами, и одна из директив listen слушает на всех адресах для данного порта (*:порт), то Angie сделает bind() только на *:порт. Необходимо заметить, что в этом случае для определения адреса, на который пришло соединение, делается системный вызов getsockname(). Если же используются параметры setfib, fastopen, backlog, rcvbuf, sndbuf, accept_filter, deferred, ipv6only, reuseport или so_keepalive, то для данной пары адрес:порт всегда делается отдельный вызов bind(). |
|
определяет (через параметр сокета IPV6_V6ONLY), будет ли слушающий на wildcard-адресе [::] IPv6-сокет принимать только IPv6-соединения, или же одновременно IPv6- и IPv4-соединения. |
|
указывает, что нужно создавать отдельный слушающий сокет для каждого рабочего процесса (через параметр сокета 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".
|
если параметр опущен, для сокета будут действовать настройки операционной системы |
|
для сокета включается параметр SO_KEEPALIVE |
|
для сокета параметр 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_timeout#
Задает время фазы предварительного чтения.
proxy_protocol_timeout#
|
|
По умолчанию |
|
stream, server |
Задает время для завершения операции чтения заголовка протокола PROXY. Если по истечении этого времени заголовок полностью не получен, соединение закрывается.
resolver#
|
|
По умолчанию |
— |
stream, server, upstream |
Задает серверы DNS, используемые для преобразования имен вышестоящих серверов в адреса, например:
resolver 127.0.0.53 [::1]:5353;
Адрес может быть указан в виде доменного имени или IP-адреса, и необязательного порта. Если порт не указан, используется порт 53. Серверы DNS опрашиваются циклически.
По умолчанию Angie кэширует ответы, используя значение TTL из ответа. Необязательный параметр valid позволяет это переопределить:
|
необязательный параметр, позволяет переопределить срок кэширования ответа |
resolver 127.0.0.53 [::1]:5353 valid=30s;
По умолчанию Angie будет искать как IPv4-, так и IPv6-адреса при преобразовании имен в адреса.
|
запрещает поиск IPv4-адресов |
|
запрещает поиск IPv6-адресов |
|
необязательный параметр; включает сбор метрик запросов и ответов DNS-сервера (/status/resolvers/<зона>) в указанной зоне |
Совет
Для предотвращения DNS-спуфинга рекомендуется использовать DNS-серверы в защищенной доверенной локальной сети.
resolver_timeout#
|
|
По умолчанию |
|
stream, server, upstream |
Задает таймаут для преобразования имени в адрес, например:
resolver_timeout 5s;
server#
Задает конфигурацию для сервера.
server_name#
Задает имена виртуального сервера, например:
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#
|
|
По умолчанию |
|
stream |
Задает размер корзины для хэш-таблиц имен серверов. Значение по умолчанию зависит от размера кэш-линии процессора.
server_names_hash_max_size#
|
|
По умолчанию |
|
stream |
Задает максимальный размер хэш-таблиц имен серверов.
status_zone#
Выделяет зону разделяемой памяти для сбора метрик /status/stream/server_zones/<зона>.
Несколько контекстов server
могут совместно использовать одну и ту же зону для сбора данных.
stream#
Предоставляет контекст конфигурационного файла, в котором указываются директивы stream-сервера.
tcp_nodelay#
Разрешает или запрещает использование параметра TCP_NODELAY. Параметр включается как для клиентских соединений, так и для соединений с проксируемыми серверами.
variables_hash_bucket_size#
|
|
По умолчанию |
|
stream |
Задает размер корзины в хэш-таблице переменных. Подробнее настройка хэш-таблиц обсуждается отдельно.
variables_hash_max_size#
|
|
По умолчанию |
|
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
#
статус сессии, может принимать одно из следующих значений:
|
сессия завершена успешно |
|
невозможно разобрать данные, полученные от клиента, например заголовок протокола PROXY |
|
доступ запрещен, например при ограничении доступа для определенных адресов клиентов |
|
внутренняя ошибка сервера |
|
плохой шлюз, например если невозможно выбрать сервер группы или сервер недоступен |
|
сервис недоступен, например при ограничении по числу соединений |
$time_iso8601
#
локальное время в формате по стандарту ISO 8601
$time_local
#
локальное время в Common Log Format