Conexões, Sessões, Requisições, Logs#

Mecanismos de processamento de conexão#

O Angie suporta vários métodos de processamento de conexão. A disponibilidade de um método específico depende da plataforma sendo utilizada. Em plataformas que suportam múltiplos métodos, o Angie normalmente seleciona o método mais eficiente automaticamente. No entanto, se necessário, um método de processamento de conexão pode ser explicitamente escolhido usando a diretiva use.

Os seguintes métodos de processamento de conexão estão disponíveis:

Método

Descrição

select

Um método padrão. O módulo de suporte é construído automaticamente em plataformas que não possuem métodos mais eficientes. As opções de construção --with-select_module e --without-select_module podem ser usadas para forçar a habilitação ou desabilitação da construção deste módulo.

poll

Um método padrão. O módulo de suporte é construído automaticamente em plataformas que não possuem métodos mais eficientes. As opções de construção --with-poll_module e --without-poll_module podem ser usadas para forçar a habilitação ou desabilitação da construção deste módulo.

kqueue

Um método eficiente disponível no FreeBSD 4.1+, OpenBSD 2.9+, NetBSD 2.0, e macOS.

epoll

Um método eficiente disponível no Linux 2.6+.

/dev/poll

Um método eficiente disponível no Solaris 7 11/99+, HP/UX 11.22+ (eventport), IRIX 6.5.15+, e Tru64 UNIX 5.1A+.

eventport

O método event ports está disponível no Solaris 10+. (Devido a problemas conhecidos, é recomendado usar o método /dev/poll em seu lugar.)

Processamento de requisições HTTP#

Uma requisição HTTP passa por uma série de fases, onde um tipo específico de processamento é realizado em cada fase.

Post-read

A fase inicial. O módulo RealIP é invocado durante esta fase.

Server-rewrite

A fase onde as diretivas do módulo Rewrite, definidas em um bloco server (mas fora de um bloco location), são processadas.

Find-config

Uma fase especial onde um location é selecionado baseado na URI da requisição.

Rewrite

Similar à fase Server-rewrite, mas se aplica às regras rewrite definidas dentro do bloco location selecionado na fase anterior.

Post-rewrite

Uma fase especial onde a requisição é redirecionada para um novo location, como na fase Find-config, se sua URI foi modificada durante a fase Rewrite.

Preaccess

Durante esta fase, módulos padrão do Angie como Limit Req registram seus manipuladores.

Access

A fase onde a autorização do cliente para fazer a requisição é verificada, normalmente invocando módulos padrão do Angie como Auth Basic.

Post-access

Uma fase especial onde a diretiva satisfy any é processada.

Precontent

Diretivas de módulos padrão, como try_files e mirror, registram seus manipuladores durante esta fase.

Content

A fase onde a resposta é normalmente gerada. Múltiplos módulos padrão do Angie registram seus manipuladores neste estágio, incluindo Index. As diretivas proxy_pass, fastcgi_pass, uwsgi_pass, scgi_pass e grpc_pass também são tratadas aqui.

Os manipuladores são chamados sequencialmente até que um deles produza a saída.

Log

A fase final, onde o registro da requisição é realizado. Atualmente, apenas o módulo Log registra seu manipulador neste estágio para registro de acesso.

Processamento de sessões TCP/UDP#

Uma sessão TCP/UDP de um cliente passa por uma série de fases, onde um tipo específico de processamento é realizado em cada fase:

Post-accept

A fase inicial após aceitar uma conexão do cliente. O módulo RealIP é invocado nesta fase.

Pre-access

Uma fase preliminar para verificar o acesso. Os módulos Set são invocados durante esta fase.

Access

A fase para limitar o acesso do cliente antes do processamento real dos dados. O módulo Access é invocado neste estágio.

SSL

A fase onde ocorre a terminação TLS/SSL. O módulo SSL é invocado durante esta fase.

Preread

A fase para ler os bytes iniciais de dados no buffer de preread para permitir que módulos como SSL Preread analisem os dados antes do processamento.

Content

Uma fase obrigatória onde os dados são realmente processados, normalmente envolvendo o módulo Return para enviar uma resposta ao cliente. A diretiva proxy_pass também é tratada aqui.

Log

A fase final onde o resultado do processamento da sessão do cliente é registrado. O módulo Log é invocado nesta fase.

Processamento de requisições#

Seleção de servidor virtual#

Inicialmente, uma conexão é criada dentro do contexto de um servidor padrão. O nome do servidor pode então ser determinado nos seguintes estágios do processamento da requisição, cada um dos quais está envolvido na seleção da configuração do servidor:

  • Durante o handshake SSL, antecipadamente, de acordo com o SNI.

  • Após processar a linha da requisição.

  • Após processar o campo de cabeçalho Host.

Se o nome do servidor não for determinado após processar a linha da requisição ou o campo de cabeçalho Host, o Angie usará um nome vazio como nome do servidor.

Em cada um desses estágios, diferentes configurações de servidor podem ser aplicadas. Portanto, certas diretivas devem ser especificadas com cuidado:

  • No caso da diretiva ssl_protocols, a lista de protocolos é definida pela biblioteca OpenSSL antes que a configuração do servidor seja aplicada de acordo com o nome solicitado através do SNI. Como resultado, os protocolos devem ser especificados apenas para o servidor padrão.

  • As diretivas client_header_buffer_size e merge_slashes são aplicadas antes de ler a linha da requisição. Portanto, essas diretivas usam ou a configuração do servidor padrão ou a configuração do servidor escolhida por SNI.

  • No caso das diretivas ignore_invalid_headers, large_client_header_buffers, e underscores_in_headers, que estão envolvidas no processamento dos campos de cabeçalho da requisição, a configuração do servidor depende adicionalmente de ter sido atualizada de acordo com a linha da requisição ou o campo de cabeçalho Host.

  • Uma resposta de erro é tratada usando a diretiva error_page no servidor que está atualmente processando a requisição.

Servidores virtuais baseados em nome#

O Angie primeiro determina qual servidor deve tratar a requisição. Considere uma configuração simples onde todos os três servidores virtuais escutam na porta 80:

server {

    listen 80;
    server_name example.org www.example.org;
    # ...
}

server {

    listen 80;
    server_name example.net www.example.net;
    #  ...
}

server {

    listen 80;
    server_name example.com www.example.com;
    #  ...
}

Nesta configuração, o Angie determina qual servidor deve tratar a requisição baseado exclusivamente no campo de cabeçalho Host. Se o valor deste cabeçalho não corresponder a nenhum nome de servidor ou se a requisição não contiver este campo de cabeçalho, o Angie roteará a requisição para o servidor padrão desta porta. Na configuração acima, o servidor padrão é o primeiro — que é o comportamento padrão do Angie. Também pode ser explicitamente especificado qual servidor deve ser o padrão usando o parâmetro default_server na diretiva listen:

server {

    listen 80 default_server;
    server_name example.net www.example.net;
    #  ...
}

Nota

Note que o servidor padrão é uma propriedade do socket de escuta, não do nome do servidor.

Nomes internacionalizados#

Nomes de domínio internacionalizados (IDNs) devem ser especificados usando uma representação ASCII (Punycode) na diretiva server_name:

server {

    listen 80;
    server_name xn--e1afmkfd.xn--80akhbyknj4f; # пример.испытание
    #    ...
}

Prevenindo requisições com nomes de servidor indefinidos#

Se requisições sem o campo de cabeçalho Host não devem ser permitidas, um servidor que simplesmente descarta tais requisições pode ser definido:

server {

    listen 80;
    server_name "";
    return 444;
}

Nesta configuração, o nome do servidor é definido como uma string vazia, que corresponde a requisições sem o campo de cabeçalho Host. Um código especial não-padrão 444 é então retornado, que fecha a conexão.

Combinando servidores virtuais baseados em nome e baseados em IP#

Vamos examinar uma configuração mais complexa onde alguns servidores virtuais escutam em endereços diferentes:

server {

    listen 192.168.1.1:80;
    server_name example.org www.example.org;
    #  ...
}

server {

    listen 192.168.1.1:80;
    server_name example.net www.example.net;
    #  ...
}

server {

    listen 192.168.1.2:80;
    server_name example.com www.example.com;
    #  ...
}

Nesta configuração, o Angie primeiro testa o endereço IP e a porta da requisição contra as diretivas listen dos blocos server. Em seguida, testa o campo de cabeçalho Host da requisição contra as entradas server_name dos blocos server que corresponderam ao endereço IP e porta. Se o nome do servidor não for encontrado, a requisição será processada pelo servidor padrão. Por exemplo, uma requisição para www.example.com recebida na porta 192.168.1.1:80 será tratada pelo servidor padrão para essa porta — ou seja, pelo primeiro servidor — já que www.example.com não está definido para esta porta.

Como mencionado anteriormente, um servidor padrão é uma propriedade da porta de escuta, e diferentes servidores padrão podem ser definidos para diferentes portas:

server {

    listen 192.168.1.1:80;
    server_name example.org www.example.org;
    #  ...
}

server {

    listen 192.168.1.1:80 default_server;
    server_name example.net www.example.net;
    #  ...
}

server {

    listen 192.168.1.2:80 default_server;
    server_name example.com www.example.com;
    #  ...
}

Escolhendo localizações#

Considere uma configuração simples de site PHP:

server {

    listen 80;
    server_name example.org www.example.org;
    root /data/www;

    location / {

        index index.html index.php;
    }

    location ~* \.(gif|jpg|png)$ {

        expires 30d;
    }

    location ~ \.php$ {

        fastcgi_pass localhost:9000;
        fastcgi_param SCRIPT_FILENAME
        $document_root$fastcgi_script_name;
        include fastcgi_params;
    }
}

O Angie primeiro busca pela location de prefixo mais específica dada por strings literais, independentemente da ordem listada. Na configuração acima, a única localização de prefixo é location /, que corresponde a qualquer requisição e será usada como último recurso. O Angie então verifica localizações definidas por expressões regulares na ordem em que aparecem no arquivo de configuração. A primeira expressão correspondente para a busca, e o Angie usará essa location. Se nenhuma expressão regular corresponder a uma requisição, o Angie usará a location de prefixo mais específica encontrada anteriormente.

Nota

Localizações de todos os tipos testam apenas a parte URI da linha de requisição, excluindo argumentos. Isso ocorre porque argumentos na string de consulta podem ser especificados de várias maneiras, por exemplo:

  • /index.php?user=john&page=1

  • /index.php?page=1&user=john

Além disso, strings de consulta podem conter qualquer número de parâmetros:

  • /index.php?page=1&something+else&user=john

Agora vamos ver como as requisições seriam processadas na configuração acima:

  • A requisição /logo.gif é primeiro correspondida pelo prefixo location / e depois pela expressão regular .(gif|jpg|png)$. Portanto, é tratada pela última localização. Usando a diretiva root /data/www, a requisição é mapeada para o arquivo /data/www/logo.gif, e o arquivo é enviado para o cliente.

  • A requisição /index.php também é inicialmente correspondida pelo prefixo location / e depois pela expressão regular .(php)$. Consequentemente, é tratada pela última localização, e a requisição é passada para um servidor FastCGI escutando em localhost:9000. A diretiva fastcgi_param define o parâmetro FastCGI SCRIPT_FILENAME como /data/www/index.php, e o servidor FastCGI executa o arquivo. A variável $document_root é definida com o valor da diretiva root, e a variável $fastcgi_script_name é definida com o URI da requisição, ou seja, /index.php.

  • A requisição /about.html é correspondida apenas pelo prefixo location /, então é tratada nesta localização. Usando a diretiva root /data/www, a requisição é mapeada para o arquivo /data/www/about.html, e o arquivo é enviado para o cliente.

Tratar a requisição / é mais complexo. Ela é correspondida apenas pelo prefixo location /, então é tratada por esta localização. A diretiva index então testa a existência de arquivos de índice de acordo com seus parâmetros e a diretiva root /data/www. Se o arquivo /data/www/index.html não existir mas o arquivo /data/www/index.php existir, a diretiva executa um redirecionamento interno para /index.php, e o Angie busca as localizações novamente como se a requisição tivesse sido enviada por um cliente. Como mencionado anteriormente, a requisição redirecionada será eventualmente tratada pelo servidor FastCGI.

Proxy e Balanceamento de Carga#

Um uso comum do Angie é configurá-lo como um servidor proxy. Neste papel, o Angie recebe requisições, as encaminha para os servidores proxy, recupera respostas desses servidores e envia as respostas de volta para os clientes.

Um servidor proxy simples:

server {

    location / {

        proxy_pass http://backend:8080;
    }

A diretiva proxy_pass instrui o Angie a passar requisições do cliente para o backend backend:8080 (o servidor proxy). Existem muitas diretivas adicionais disponíveis para configurar ainda mais uma conexão proxy.

Proxy FastCGI#

O Angie pode ser usado para rotear requisições para servidores FastCGI que executam aplicações construídas com vários frameworks e linguagens de programação, como PHP.

A configuração mais básica do Angie para trabalhar com um servidor FastCGI envolve usar a diretiva fastcgi_pass em vez da diretiva proxy_pass, junto com diretivas fastcgi_param para definir parâmetros passados para o servidor FastCGI. Suponha que o servidor FastCGI seja acessível em localhost:9000. Em PHP, o parâmetro SCRIPT_FILENAME é usado para determinar o nome do script, e o parâmetro QUERY_STRING é usado para passar parâmetros de requisição. A configuração resultante seria:

server {

    location / {

        fastcgi_pass localhost:9000;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_param QUERY_STRING $query_string;
    }

    location ~ \.(gif|jpg|png)$ {

        root /data/images;
    }
}

Esta configuração define um servidor que roteia todas as requisições, exceto aquelas para imagens estáticas, para o servidor proxy operando em localhost:9000 via o protocolo FastCGI.

Proxy WebSocket#

Para atualizar uma conexão de HTTP/1.1 para WebSocket, é usado o mecanismo de troca de protocolo disponível no HTTP/1.1.

No entanto, há uma sutileza: como o cabeçalho Upgrade é um cabeçalho hop-by-hop, ele não é passado do cliente para o servidor proxy. Com proxy direto, os clientes podem usar o método CONNECT para contornar esse problema. Essa abordagem não funciona com proxy reverso, pois os clientes não têm conhecimento de nenhum servidor proxy, e é necessário processamento especial no servidor proxy.

O Angie implementa um modo especial de operação que permite configurar um túnel entre um cliente e um servidor proxy se o servidor proxy retornar uma resposta com código 101 (Switching Protocols), e o cliente solicitar uma troca de protocolo através do cabeçalho Upgrade na requisição.

Como mencionado, cabeçalhos hop-by-hop, incluindo Upgrade e Connection, não são passados do cliente para o servidor proxy. Portanto, para que o servidor proxy tenha conhecimento da intenção do cliente de trocar para o protocolo WebSocket, esses cabeçalhos devem ser passados explicitamente:

location /chat/ {

    proxy_pass http://backend;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";
}

Um exemplo mais sofisticado demonstra como o valor do campo de cabeçalho Connection em uma requisição para o servidor proxy depende da presença do campo Upgrade no cabeçalho da requisição do cliente:

http {

    map $http_upgrade $connection_upgrade {

        default upgrade;
        '' close;
    }

    server {

        ...

        location /chat/ {

            proxy_pass http://backend;
            proxy_http_version 1.1;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection $connection_upgrade;
        }
    }
}

Por padrão, a conexão será fechada se o servidor proxy não transmitir nenhum dado dentro de 60 segundos. Esse timeout pode ser aumentado usando a diretiva proxy_read_timeout. Alternativamente, o servidor proxy pode ser configurado para enviar periodicamente frames de ping WebSocket para redefinir o timeout e verificar se a conexão ainda está ativa.

Balanceamento de Carga#

O balanceamento de carga entre múltiplas instâncias de aplicação é uma técnica amplamente usada para otimizar a utilização de recursos, maximizar o throughput, reduzir a latência e garantir configurações tolerantes a falhas.

O Angie pode ser usado como um balanceador de carga HTTP altamente eficiente para distribuir tráfego para múltiplos servidores de aplicação, melhorando assim o desempenho, escalabilidade e confiabilidade de aplicações web.

A configuração mais simples para balanceamento de carga com Angie pode parecer assim:

http {

    upstream myapp1 {

        server srv1.example.com;
        server srv2.example.com;
        server srv3.example.com;
    }

    server {

        listen 80;

        location / {

            proxy_pass http://myapp1;
        }
    }
}

No exemplo acima, três instâncias da mesma aplicação estão executando em srv1 até srv3. Quando um método de balanceamento de carga não é explicitamente configurado, o padrão é round-robin. Outros mecanismos de balanceamento de carga suportados incluem: weight, least_conn, e ip_hash. A implementação de proxy reverso no Angie também suporta verificações de saúde do servidor in-band (ou passivas). Essas são configuradas usando as diretivas max_fails e fail_timeout dentro do bloco server no contexto upstream.

Logging#

Nota

Além das opções listadas aqui, você também pode habilitar o log de depuração.

Syslog#

As diretivas error_log e access_log suportam logging para syslog. Os seguintes parâmetros são usados para configurar logging para syslog:

server=address

Especifica o endereço de um servidor syslog. O endereço pode ser um nome de domínio ou um endereço IP, com uma porta opcional, ou um caminho de socket de domínio UNIX especificado após o prefixo "unix:". Se a porta não for especificada, a porta UDP 514 é usada. Se um nome de domínio resolver para múltiplos endereços IP, o primeiro endereço resolvido é usado.

facility=string

Define a facility para mensagens syslog, conforme definido na RFC 3164. As facilities possíveis incluem: "kern", "user", "mail", "daemon", "auth", "intern", "lpr", "news", "uucp", "clock", "authpriv", "ftp", "ntp", "audit", "alert", "cron", "local0".."local7". O padrão é "local7".

severity=string

Define o nível de severidade das mensagens syslog para access_log, conforme especificado na RFC 3164. Os valores possíveis são os mesmos do segundo parâmetro (level) da diretiva error_log. O padrão é "info". A severidade das mensagens de erro é determinada pelo Angie, então este parâmetro é ignorado na diretiva error_log.

tag=string

Define a tag para mensagens syslog. A tag padrão é "angie".

nohostname

Desabilita a adição do campo hostname no cabeçalho da mensagem syslog.

Exemplo de configuração syslog:

error_log syslog:server=192.168.1.1 debug;

access_log syslog:server=unix:/var/log/angie.sock,nohostname;
access_log syslog:server=[2001:db8::1]:12345,facility=local7,tag=angie,severity=info combined;

Nota

Entradas do syslog são reportadas no máximo uma vez por segundo para prevenir flooding.