Módulo Stream#

O módulo stream principal implementa a funcionalidade básica para manipular conexões TCP e UDP: isso inclui definição de blocos de servidor, roteamento de tráfego, configuração de proxy, suporte a SSL/TLS e gerenciamento de conexões para serviços de streaming, como bancos de dados, DNS e outros protocolos que operam sobre TCP e UDP.

Os outros módulos nesta seção estendem essa funcionalidade, permitindo configurar e otimizar de forma flexível o servidor de stream para diversos cenários e requisitos.

Ao compilar a partir do código-fonte, este módulo não é incluído por padrão; ele deve ser habilitado com a --with-stream opção de compilação. Nos pacotes e imagens dos nossos repositórios, o módulo já está incluído na compilação.

Exemplo de Configuração#

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;
    }
}

Diretivas#

listen#

Sintaxe

listen endereço[:porta] [ssl] [udp] [proxy_protocol] [setfib=número] [fastopen=número] [backlog=número] [rcvbuf=tamanho] [sndbuf=tamanho] [accept_filter=filtro] [deferred] [bind] [ipv6only=on | off] [reuseport] [so_keepalive=on|off|[keepidle]:[samp:keepintvl]:[samp:keepcnt]];

Padrão

Contexto

server

Define o endereço e a porta do socket no qual o servidor aceitará conexões. É possível especificar apenas a porta, para que o Angie escute em todas as interfaces IPv4 (e IPv6, se habilitado). O endereço também pode ser um hostname, por exemplo:

listen 127.0.0.1:12345;
listen *:12345;
listen 12345;     # equivalente a *:12345
listen localhost:12345;

Endereços IPv6 são especificados entre colchetes:

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

Sockets de domínio UNIX são especificados com o prefixo unix::

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

Intervalos de portas são especificados com a primeira e a última porta separadas por hífen:

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

Nota

Servidores diferentes devem escutar em pares únicos de endereço:porta.

ssl

permite especificar que todas as conexões aceitas nesta porta devem operar em modo SSL.

udp

configura um socket de escuta para trabalhar com datagramas. Para lidar com pacotes do mesmo endereço e porta na mesma sessão, o parâmetro reuseport também deve ser especificado.

proxy_protocol

permite especificar que todas as conexões aceitas nesta porta devem usar o protocolo PROXY.

A diretiva listen pode ter vários parâmetros adicionais específicos para chamadas de sistema relacionadas a sockets.

setfib=número

define a tabela de roteamento associada, FIB (a opção SO_SETFIB) para o socket de escuta. Atualmente funciona apenas no FreeBSD.

fastopen=número

habilita o "TCP Fast Open" para o socket de escuta e limita o comprimento máximo da fila de conexões que ainda não completaram o three-way handshake.

Aviso

Não habilite este recurso a menos que o servidor consiga lidar com o recebimento do mesmo pacote SYN com dados mais de uma vez.

backlog=número

define o parâmetro backlog na chamada listen(), que limita o comprimento máximo da fila de conexões pendentes. Por padrão, backlog é definido como -1 no FreeBSD, DragonFly BSD e macOS, e como 511 em outras plataformas.

rcvbuf=tamanho

define o tamanho do buffer de recepção (opção SO_RCVBUF) para o socket de escuta.

sndbuf=tamanho

define o tamanho do buffer de envio (opção SO_SNDBUF) para o socket de escuta.

accept_filter=filtro

define o nome do filtro de aceitação (opção SO_ACCEPTFILTER) para o socket de escuta, que filtra conexões recebidas antes de passá-las para accept(). Funciona apenas em FreeBSD e NetBSD 5.0+. Valores aceitáveis: dataready e httpready.

deferred

instrui a usar accept() diferido (opção TCP_DEFER_ACCEPT) no Linux.

bind

instrui a fazer uma chamada bind() separada para um par endereço:porta específico. Se houver várias diretivas listen com a mesma porta mas endereços diferentes, e uma delas escutar em todos os endereços para a porta dada (*:porta), o Angie fará bind() apenas em *:porta. Nesse caso, será feita a chamada getsockname() para determinar o endereço que aceitou a conexão. Se os parâmetros setfib, fastopen, backlog, rcvbuf, sndbuf, accept_filter, deferred, ipv6only, reuseport ou so_keepalive forem usados, sempre será feita uma chamada bind() separada para o par endereço:porta.

ipv6only=on | off

define (via opção IPV6_V6ONLY) se um socket IPv6 escutando em [::] aceitará apenas conexões IPv6 ou tanto IPv6 quanto IPv4. Esse parâmetro é ativado por padrão. Só pode ser definido na inicialização.

reuseport

instrui a criar um socket de escuta individual para cada processo worker (usando a opção SO_REUSEPORT no Linux 3.9+ e DragonFly BSD, ou SO_REUSEPORT_LB no FreeBSD 12+), permitindo ao kernel distribuir conexões recebidas entre os processos. Funciona apenas em Linux 3.9+, DragonFly BSD e FreeBSD 12+.

Aviso

Uso inadequado dessa opção pode ter implicações de segurança.

multipath

habilita a aceitação de conexões via protocolo Multipath TCP (MPTCP), suportado no kernel Linux a partir da versão 5.6. Este parâmetro é incompatível com udp.

so_keepalive=on | off | [keepidle]:[samp:keepintvl]:[samp:keepcnt]

Configura o comportamento de "TCP keepalive" para o socket de escuta.

''

se este parâmetro for omitido, as configurações do sistema operacional terão efeito sobre o socket

on

a opção SO_KEEPALIVE é ativada para o socket

off

a opção SO_KEEPALIVE é desativada para o socket

Alguns sistemas operacionais permitem definir parâmetros de TCP keepalive por socket usando as opções TCP_KEEPIDLE, TCP_KEEPINTVL e TCP_KEEPCNT. Nesses sistemas (atualmente, Linux 2.4+, NetBSD 5+ e FreeBSD 9.0-STABLE), eles podem ser configurados usando os parâmetros keepidle, keepintvl e keepcnt. Um ou dois parâmetros podem ser omitidos, caso em que será usado o valor padrão do sistema para a opção correspondente.

Por exemplo,

so_keepalive=30m::10

definirá o tempo de inatividade (TCP_KEEPIDLE) em 30 minutos, deixará o intervalo de sondagem (TCP_KEEPINTVL) no valor padrão do sistema e definirá a contagem de sondagens (TCP_KEEPCNT) em 10.

preread_buffer_size#

Sintaxe

preread_buffer_size tamanho;

Padrão

preread_buffer_size 16k;

Contexto

stream, server

Especifica o tamanho do buffer de preread.

preread_timeout#

Sintaxe

preread_timeout tempo;

Padrão

preread_timeout 30s;

Contexto

stream, server

Especifica um tempo limite da fase de preread.

proxy_protocol_timeout#

Sintaxe

proxy_protocol_timeout tempo;

Padrão

proxy_protocol_timeout 30s;

Contexto

stream, server

Especifica um tempo limite para leitura do cabeçalho do protocolo PROXY. Se o cabeçalho completo não for transmitido dentro desse tempo, a conexão será fechada.

resolver#

Sintaxe

resolver endereço ... [valid=tempo] [ipv4=on | off] [ipv6=on | off] [status_zone=zona];

Padrão

Contexto

stream, server, upstream

Configura os servidores de nomes usados para resolver nomes de servidores upstream em endereços, por exemplo:

resolver 127.0.0.53 [::1]:5353;

O endereço pode ser especificado como um nome de domínio ou endereço IP, com uma porta opcional. Se a porta não for especificada, a porta 53 será usada. Os servidores de nomes são consultados em esquema round-robin.

Por padrão, o Angie armazena respostas em cache usando o valor TTL da resposta. O parâmetro opcional valid permite sobrescrevê-lo:

valid

parâmetro opcional que permite sobrescrever a validade da entrada em cache

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

Por padrão, o Angie resolve tanto endereços IPv4 quanto IPv6.

ipv4=off

desabilita a resolução de endereços IPv4

ipv6=off

desabilita a resolução de endereços IPv6

status_zone

parâmetro opcional; habilita a coleta de métricas de requisições e respostas de servidores DNS (/status/resolvers/<zone>) na zona especificada

Dica

Para prevenir spoofing de DNS, recomenda-se usar servidores DNS em uma rede local confiável e devidamente protegida.

Dica

Ao executar em Docker, utilize o endereço DNS interno correspondente, como 127.0.0.11.

resolver_timeout#

Sintaxe

resolver_timeout tempo;

Padrão

resolver_timeout 30s;

Contexto

stream, server, upstream

Define um tempo limite para resolução de nomes, por exemplo:

resolver_timeout 5s;

server#

Sintaxe

server { ... }

Padrão

Contexto

stream

Define a configuração de um servidor.

server_name#

Sintaxe

server_name nome ...;

Padrão

server_name "";

Contexto

server

Define os nomes de um servidor virtual.

Aviso

No módulo stream, a diretiva server_name é baseada em Server Name Indication (SNI) e funciona apenas com conexões TLS. Para usá-la, é necessário configurar terminação TLS ou habilitar TLS preread no bloco server correspondente.

Exemplo de configuração:

server {
    listen 443 ssl;
    server_name example.com www.example.com;
    ssl_certificate /etc/angie/cert.pem;
    ssl_certificate_key /etc/angie/key.pem;
}

O primeiro nome se torna o nome principal do servidor.

Nomes de servidor podem incluir um asterisco (*) para substituir a primeira ou a última parte de um nome:

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

Esses nomes são chamados de curingas (wildcards).

Também é possível usar expressões regulares em nomes de servidor precedendo o nome com um til (~):

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

Expressões regulares podem incluir capturas que podem ser usadas em outras diretivas:

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

    proxy_pass www.$2:12345;
}

Capturas nomeadas em expressões regulares criam variáveis que podem ser usadas em outras diretivas:

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

    proxy_pass www.$domain:12345;
}

Se o parâmetro da diretiva for definido como $hostname, o hostname da máquina será inserido.

Ao procurar um servidor virtual por nome, se o nome corresponder a mais de uma variante especificada (por exemplo, tanto um curinga quanto uma expressão regular), a primeira variante correspondente será escolhida na seguinte ordem de prioridade:

  • Nome exato

  • O maior nome curinga começando com asterisco, por exemplo, *.example.com

  • O maior nome curinga terminando com asterisco, por exemplo, mail.*

  • A primeira expressão regular correspondente (na ordem em que aparece no arquivo de configuração)

server_names_hash_bucket_size#

Sintaxe

server_names_hash_bucket_size tamanho;

Padrão

server_names_hash_bucket_size 32|64|128;

Contexto

stream

Define o tamanho do bucket para as tabelas de hash dos nomes de servidor. O valor padrão depende do tamanho da linha de cache do processador.

server_names_hash_max_size#

Sintaxe

server_names_hash_max_size tamanho;

Padrão

server_names_hash_max_size 512;

Contexto

stream

Define o tamanho máximo das tabelas de hash de nomes de servidor.

status_zone#

Sintaxe

status_zone zona | chave zone=zona[:count];

Padrão

Contexto

server

Aloca uma zona de memória compartilhada para coletar métricas para /status/stream/server_zones/<zone>.

Vários contextos server podem compartilhar a mesma zona para coleta de dados.

A sintaxe de valor único zona agrega todas as métricas do contexto atual em uma zona de memória compartilhada:

server {

    listen 80;
    server_name *.example.com;

    status_zone single;
    # ...
}

A sintaxe alternativa permite especificar os seguintes parâmetros:

chave

Uma string com variáveis, cujo valor determina o agrupamento das conexões na zona. Todas as conexões que produzem valores idênticos após substituição são agrupadas juntas. Se a substituição resultar em valor vazio, as métricas não são atualizadas.

zona

O nome da zona de memória compartilhada.

count (opcional)

O número máximo de grupos separados para coleta de métricas. Se novos valores de chave excederem esse limite, eles serão agrupados sob zona.

O valor padrão é 1.

No exemplo a seguir, todas as conexões com o mesmo valor de $server_addr são agrupadas em host_zone. As métricas são coletadas separadamente para cada $server_addr único até que o número de grupos de métricas alcance 10. Após isso, quaisquer novos valores de $server_addr serão adicionados ao grupo server_zone:

stream {

    upstream backend {
        server 192.168.0.1:3306;
        server 192.168.0.2:3306;
        # ...
    }

    server {

        listen 3306;
        proxy_pass backend;

        status_zone $server_addr zone=server_zone:10;
    }
}

As métricas resultantes são divididas entre servidores individuais na saída da API.

stream#

Sintaxe

stream { ... }

Padrão

Contexto

main

Fornece o contexto do arquivo de configuração no qual as diretivas do servidor stream são especificadas.

tcp_nodelay#

Sintaxe

tcp_nodelay on | off;

Padrão

tcp_nodelay on;

Contexto

stream, server

Habilita ou desabilita o uso da opção TCP_NODELAY. A opção é aplicada tanto às conexões de clientes quanto às conexões para servidores de proxy.

variables_hash_bucket_size#

Sintaxe

variables_hash_bucket_size tamanho;

Padrão

variables_hash_bucket_size 64;

Contexto

stream

Define o tamanho do bucket para a tabela de hash de variáveis. Detalhes sobre a configuração de tabelas de hash estão disponíveis em um documento separado.

variables_hash_max_size#

Sintaxe

variables_hash_max_size tamanho;

Padrão

variables_hash_max_size 1024;

Contexto

stream

Define o tamanho máximo da tabela de hash de variáveis. Detalhes sobre a configuração de tabelas de hash estão disponíveis em um documento separado.

Variáveis Embutidas#

O módulo stream principal oferece suporte às seguintes variáveis embutidas:

$angie_version#

versão do Angie

$binary_remote_addr#

endereço do cliente em forma binária, com comprimento sempre de 4 bytes para IPv4 ou 16 bytes para IPv6

$bytes_received#

número de bytes recebidos de um cliente

$bytes_sent#

número de bytes enviados a um cliente

$connection#

número serial da conexão

$hostname#

nome do host

$msec#

hora atual em segundos com resolução em milissegundos

$pid#

PID do processo worker

$protocol#

protocolo usado para comunicação com o cliente: TCP ou UDP

$proxy_protocol_addr#

endereço do cliente a partir do cabeçalho do protocolo PROXY. O protocolo PROXY deve estar habilitado previamente definindo o parâmetro proxy_protocol na diretiva listen.

$proxy_protocol_port#

porta do cliente a partir do cabeçalho do protocolo PROXY. O protocolo PROXY deve estar habilitado previamente definindo o parâmetro proxy_protocol na diretiva listen.

$proxy_protocol_server_addr#

endereço do servidor a partir do cabeçalho do protocolo PROXY. O protocolo PROXY deve estar habilitado previamente definindo o parâmetro proxy_protocol na diretiva listen.

$proxy_protocol_server_port#

porta do servidor a partir do cabeçalho do protocolo PROXY. O protocolo PROXY deve estar habilitado previamente definindo o parâmetro proxy_protocol na diretiva listen.

$proxy_protocol_tlv_<nome>#

TLV obtido do cabeçalho do protocolo PROXY. O nome pode ser um nome de tipo TLV ou seu valor numérico. Neste último caso, o valor é especificado em hexadecimal e deve começar com 0x:

$proxy_protocol_tlv_alpn
$proxy_protocol_tlv_0x01

TLVs SSL também podem ser acessados tanto pelo nome do tipo quanto por seu valor numérico, ambos devem começar com ssl_:

$proxy_protocol_tlv_ssl_version
$proxy_protocol_tlv_ssl_0x21

Os seguintes nomes de tipos TLV são suportados:

  • alpn (0x01) - protocolo de camada superior usado sobre a conexão

  • authority (0x02) - valor do nome do host passado pelo cliente

  • unique_id (0x05) - identificador único da conexão

  • netns (0x30) - nome do namespace

  • ssl (0x20) - estrutura SSL TLV em formato binário

Os seguintes nomes de tipos TLV SSL são suportados:

  • ssl_version (0x21) - versão SSL usada na conexão do cliente

  • ssl_cn (0x22) - Common Name do certificado

  • ssl_cipher (0x23) - nome da cifra utilizada

  • ssl_sig_alg (0x24) - algoritmo usado para assinar o certificado

  • ssl_key_alg (0x25) - algoritmo da chave pública

Também é suportado o seguinte nome de tipo SSL TLV especial:

  • ssl_verify - resultado da verificação do certificado do cliente: 0 se o cliente apresentou um certificado e este foi verificado com sucesso, ou diferente de zero caso contrário

O protocolo PROXY deve estar habilitado previamente definindo o parâmetro proxy_protocol na diretiva listen.

$remote_addr#

endereço do cliente

$remote_port#

porta do cliente

$server_addr#

endereço do servidor que aceitou a conexão. Calcular o valor dessa variável normalmente requer uma chamada de sistema. Para evitar a chamada, as diretivas listen devem especificar endereços e usar o parâmetro bind.

$server_port#

porta do servidor que aceitou a conexão

$session_time#

duração da sessão em segundos com resolução em milissegundos

$status#

status da sessão, que pode ser um dos seguintes:

200

sessão concluída com sucesso

400

dados do cliente não puderam ser analisados, por exemplo, o cabeçalho do protocolo PROXY

403

acesso proibido, por exemplo, quando o acesso é limitado para certos endereços de clientes

500

erro interno do servidor

502

bad gateway, por exemplo, se um servidor upstream não pôde ser selecionado ou alcançado

503

serviço indisponível, por exemplo, quando o acesso é limitado pelo número de conexões

$time_iso8601#

hora local no formato padrão ISO 8601

$time_local#

hora local no formato Common Log Format