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 |
---|---|
|
A standard method. The supporting module is built automatically on
platforms that do not have more efficient methods. The
|
|
A standard method. The supporting module is built automatically on
platforms that do not have more efficient methods. The
|
|
An efficient method available on FreeBSD 4.1+, OpenBSD 2.9+, NetBSD 2.0, and macOS. |
|
An efficient method available on Linux 2.6+. |
|
An efficient method available on Solaris 7 11/99+, HP/UX 11.22+ (eventport), IRIX 6.5.15+, and Tru64 UNIX 5.1A+. |
|
The |
HTTP session processing#
An HTTP request goes through a series of phases, where a specific type of processing is performed at each phase.
|
The initial phase. The RealIP module is invoked during this phase. |
|
The phase where directives from the Rewrite
module, defined in a |
|
A special phase where a location is selected based on the request URI. |
|
Similar to the |
|
A special phase where the request is redirected to a new location, as in
the |
|
During this phase, standard Angie modules like Limit Req register their handlers. |
|
The phase where the client's authorization to make the request is verified, typically by invoking standard Angie modules such as Auth Basic. |
|
A special phase where the satisfy any directive is processed. |
|
Standard module directives, such as try_files and mirror, register their handlers during this phase. |
|
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. |
|
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:
|
The initial phase after accepting a client connection. The RealIP module is invoked at this phase. |
|
A preliminary phase for checking access. The Set modules are invoked during this phase. |
|
The phase for limiting client access before actual data processing. The Access module is invoked at this stage. |
|
The phase where TLS/SSL termination occurs. The SSL module is invoked during this phase. |
|
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. |
|
A mandatory phase where the data is actually processed, typically involving the Return module to send a response to the client. |
|
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 prefixlocation /
and then by the regular expression.(gif|jpg|png)$
. Therefore, it is handled by the latter location. Using the directiveroot /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 prefixlocation /
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 onlocalhost:9000
. The fastcgi_param directive sets the FastCGI parameterSCRIPT_FILENAME
to/data/www/index.php
, and the FastCGI server executes the file. The variable $document_root is set to the value of theroot
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 prefixlocation /
, so it is handled in this location. Using the directiveroot /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
:
|
Specifies the address of a |
|
Sets the facility for |
|
Defines the severity level of |
|
Sets the tag for |
|
Disables the addition of the :sa,p:hostname field in the |
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.