Connections, Sessions, Requests, Logging#

Connection processing mechanisms#

Angie supports various connection processing methods. The availability of a specific method depends on the platform being used. On platforms that support multiple methods, Angie typically selects the most efficient method automatically. However, if necessary, a connection processing method can be explicitly chosen using the use directive.

The following connection processing methods are available:

Method

Description

select

A standard method. The supporting module is built automatically on platforms that do not have more efficient methods. The --with-select_module and --without-select_module build options can be used to forcibly enable or disable the building of this module.

poll

A standard method. The supporting module is built automatically on platforms that do not have more efficient methods. The --with-poll_module and --without-poll_module build options can be used to forcibly enable or disable the building of this module.

kqueue

An efficient method available on FreeBSD 4.1+, OpenBSD 2.9+, NetBSD 2.0, and macOS.

epoll

An efficient method available on Linux 2.6+.

/dev/poll

An efficient method available on Solaris 7 11/99+, HP/UX 11.22+ (eventport), IRIX 6.5.15+, and Tru64 UNIX 5.1A+.

eventport

The event ports method is available on Solaris 10+. (Due to known issues, using the /dev/poll method is recommended instead.)

HTTP session processing#

An HTTP request goes through a series of phases, where a specific type of processing is performed at each phase.

Post-read

The initial phase. The RealIP module is invoked during this phase.

Server-rewrite

The phase where directives from the Rewrite module, defined in a server block (but outside a location block), are processed.

Find-config

A special phase where a location is selected based on the request URI.

Rewrite

Similar to the Server-rewrite phase, but it applies to rewrite rules defined within the location block selected in the previous phase.

Post-rewrite

A special phase where the request is redirected to a new location, as in the Find-config phase, if its URI was modified during the Rewrite phase.

Preaccess

During this phase, standard Angie modules like Limit Req register their handlers.

Access

The phase where the client's authorization to make the request is verified, typically by invoking standard Angie modules such as Auth Basic.

Post-access

A special phase where the satisfy any directive is processed.

Precontent

Standard module directives, such as try_files and mirror, register their handlers during this phase.

Content

The phase where the response is usually generated. Multiple standard Angie modules register their handlers at this stage, including Index. Handlers are called sequentially until one of them produces the output.

Log

The final phase, where request logging is performed. Currently, only the Log module registers its handler at this stage for access logging.

TCP/UDP session processing#

A TCP/UDP session from a client goes through a series of phases, where a specific type of processing is performed at each phase:

Post-accept

The initial phase after accepting a client connection. The RealIP module is invoked at this phase.

Pre-access

A preliminary phase for checking access. The Set modules are invoked during this phase.

Access

The phase for limiting client access before actual data processing. The Access module is invoked at this stage.

SSL

The phase where TLS/SSL termination occurs. The SSL module is invoked during this phase.

Preread

The phase for reading initial bytes of data into the preread buffer to allow modules such as SSL Preread to analyze the data before processing.

Content

A mandatory phase where the data is actually processed, typically involving the Return module to send a response to the client.

Log

The final phase where the outcome of client session processing is recorded. The Log module is invoked at this phase.

Processing requests#

Virtual server selection#

Initially, a connection is created within the context of a default server. The server name can then be determined in the following stages of request processing, each of which is involved in the selection of server configuration:

  • During the SSL handshake, in advance, according to the SNI.

  • After processing the request line.

  • After processing the Host header field.

If the server name is not determined after processing the request line or the Host header field, Angie will use an empty name as the server name.

At each of these stages, different server configurations may be applied. Therefore, certain directives should be specified with caution:

  • In the case of the ssl_protocols directive, the protocol list is set by the OpenSSL library before the server configuration is applied according to the name requested through SNI. As a result, protocols should only be specified for the default server.

  • The client_header_buffer_size and merge_slashes directives are applied before reading the request line. Therefore, these directives use either the default server configuration or the server configuration chosen by SNI.

  • In the case of the ignore_invalid_headers, large_client_header_buffers, and underscores_in_headers directives, which are involved in processing request header fields, the server configuration additionally depends on whether it was updated according to the request line or the Host header field.

  • An error response is handled using the error_page directive in the server that is currently processing the request.

Name-based virtual servers#

Angie first determines which server should handle the request. Consider a simple configuration where all three virtual servers listen on port 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;
    #  ...
}

In this configuration, Angie determines which server should handle the request based solely on the Host header field. If the value of this header does not match any server name or if the request does not contain this header field, Angie will route the request to the default server for this port. In the configuration above, the default server is the first one — which is Angie's standard default behavior. It can also be explicitly specified which server should be the default using the default_server parameter in the listen directive:

server {

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

Note

Note that the default server is a property of the listen socket, not of the server name.

Internationalized names#

Internationalized domain names (IDNs) should be specified using an ASCII (Punycode) representation in the server_name directive:

server {

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

Preventing requests with undefined server names#

If requests without the Host header field should not be allowed, a server that simply drops such requests can be defined:

server {

    listen 80;
    server_name "";
    return 444;
}

In this configuration, the server name is set to an empty string, which matches requests without the Host header field. A special non-standard code 444 is then returned, which closes the connection.

Combining name-based and IP-based virtual servers#

Let's examine a more complex configuration where some virtual servers listen on different addresses:

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

In this configuration, Angie first tests the IP address and port of the request against the listen directives of the server blocks. It then tests the Host header field of the request against the server_name entries of the server blocks that matched the IP address and port. If the server name is not found, the request will be processed by the default server. For example, a request for www.example.com received on port 192.168.1.1:80 will be handled by the default server for that port — i.e., by the first server — since www.example.com is not defined for this port.

As previously mentioned, a default server is a property of the listen port, and different default servers may be defined for different ports:

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

Choosing locations#

Consider a simple PHP website configuration:

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

Angie first searches for the most specific prefix location given by literal strings, regardless of their listed order. In the configuration above, the only prefix location is location /, which matches any request and will be used as a last resort. Angie then checks locations defined by regular expressions in the order they appear in the configuration file. The first matching expression stops the search, and Angie will use that location. If no regular expression matches a request, Angie will use the most specific prefix location found earlier.

Note

Locations of all types test only the URI part of the request line, excluding arguments. This is because arguments in the query string can be specified in various ways, for example:

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

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

Additionally, query strings may contain any number of parameters:

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

Now let's look at how requests would be processed in the configuration above:

  • The request /logo.gif is first matched by the prefix location / and then by the regular expression .(gif|jpg|png)$. Therefore, it is handled by the latter location. Using the directive root /data/www, the request is mapped to the file /data/www/logo.gif, and the file is sent to the client.

  • The request /index.php is also initially matched by the prefix location / and then by the regular expression .(php)$. Consequently, it is handled by the latter location, and the request is passed to a FastCGI server listening on localhost:9000. The fastcgi_param directive sets the FastCGI parameter SCRIPT_FILENAME to /data/www/index.php, and the FastCGI server executes the file. The variable $document_root is set to the value of the root directive, and the variable $fastcgi_script_name is set to the request URI, i.e., /index.php.

  • The request /about.html is matched only by the prefix location /, so it is handled in this location. Using the directive root /data/www, the request is mapped to the file /data/www/about.html, and the file is sent to the client.

Handling the request / is more complex. It is matched only by the prefix location /, so it is handled by this location. The index directive then tests for the existence of index files according to its parameters and the root /data/www directive. If the file /data/www/index.html does not exist but the file /data/www/index.php does, the directive performs an internal redirect to /index.php, and Angie searches the locations again as if the request had been sent by a client. As previously mentioned, the redirected request will eventually be handled by the FastCGI server.

Proxying and Load Balancing#

One common use of Angie is to set it up as a proxy server. In this role, Angie receives requests, forwards them to the proxied servers, retrieves responses from those servers, and sends the responses back to the clients.

A simple proxy server:

server {

    location / {

        proxy_pass http://backend:8080;
    }

The proxy_pass directive instructs Angie to pass client requests to the backend backend:8080 (the proxied server). There are many additional directives available for further configuring a proxy connection.

FastCGI Proxying#

Angie can be used to route requests to FastCGI servers that run applications built with various frameworks and programming languages, such as PHP.

The most basic Angie configuration for working with a FastCGI server involves using the fastcgi_pass directive instead of the proxy_pass directive, along with fastcgi_param directives to set parameters passed to the FastCGI server. Suppose the FastCGI server is accessible on localhost:9000. In PHP, the SCRIPT_FILENAME parameter is used to determine the script name, and the QUERY_STRING parameter is used to pass request parameters. The resulting configuration would be:

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

This configuration sets up a server that routes all requests, except those for static images, to the proxied server operating on localhost:9000 via the FastCGI protocol.

WebSocket Proxying#

To upgrade a connection from HTTP/1.1 to WebSocket, the protocol switch mechanism available in HTTP/1.1 is used.

However, there is a subtlety: since the Upgrade header is a hop-by-hop header, it is not passed from the client to the proxied server. With forward proxying, clients may use the CONNECT method to circumvent this issue. This approach does not work with reverse proxying, as clients are unaware of any proxy servers, and special processing on the proxy server is required.

Angie implements a special mode of operation that allows setting up a tunnel between a client and a proxied server if the proxied server returns a response with code 101 (Switching Protocols), and the client requests a protocol switch via the Upgrade header in the request.

As mentioned, hop-by-hop headers, including Upgrade and Connection, are not passed from the client to the proxied server. Therefore, for the proxied server to be aware of the client's intention to switch to the WebSocket protocol, these headers must be explicitly passed:

location /chat/ {

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

A more sophisticated example demonstrates how the value of the Connection header field in a request to the proxied server depends on the presence of the Upgrade field in the client request header:

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

By default, the connection will be closed if the proxied server does not transmit any data within 60 seconds. This timeout can be increased using the proxy_read_timeout directive. Alternatively, the proxied server can be configured to periodically send WebSocket ping frames to reset the timeout and check if the connection is still active.

Load Balancing#

Load balancing across multiple application instances is a widely used technique to optimize resource utilization, maximize throughput, reduce latency, and ensure fault-tolerant configurations.

Angie can be used as a highly efficient HTTP load balancer to distribute traffic to multiple application servers, thereby enhancing the performance, scalability, and reliability of web applications.

The simplest configuration for load balancing with Angie might look like this:

http {

    upstream myapp1 {

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

    server {

        listen 80;

        location / {

            proxy_pass http://myapp1;
        }
    }
}

In the example above, three instances of the same application are running on srv1 through srv3. When a load balancing method is not explicitly configured, it defaults to round-robin. Other supported load balancing mechanisms include: weight, least_conn, and ip_hash. The reverse proxy implementation in Angie also supports in-band (or passive) server health checks. These are configured using the max_fails and fail_timeout directives within the server block in the upstream context.

Logging#

Note

In addition to the options listed here, you can also enable the debugging log.

Syslog#

The error_log and access_log directives support logging to syslog. The following parameters are used to configure logging to syslog:

server=address

Specifies the address of a syslog server. The address can be a domain name or an IP address, with an optional port, or a UNIX domain socket path specified after the "unix:" prefix. If the port is not specified, UDP port 514 is used. If a domain name resolves to multiple IP addresses, the first resolved address is used.

facility=string

Sets the facility for syslog messages, as defined in RFC 3164. Possible facilities include: "kern", "user", "mail", "daemon", "auth", "intern", "lpr", "news", "uucp", "clock", "authpriv", "ftp", "ntp", "audit", "alert", "cron", "local0".."local7". The default is "local7".

severity=string

Defines the severity level of syslog messages for access_log, as specified in RFC 3164. Possible values are the same as those for the second parameter (level) of the error_log directive. The default is "info". The severity of error messages is determined by Angie, so this parameter is ignored in the error_log directive.

tag=string

Sets the tag for syslog messages. The default tag is "angie".

nohostname

Disables the addition of the :sa,p:hostname field in the syslog message header.

Example syslog configuration:

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;

Note

Syslog entries are reported no more than once per second to prevent flooding.