limit_req for the stream subsystem: rate limiting of incoming TCP and UDP
connections, with the directives, the parameters and the leaky bucket of the
http module of the same name. sync, which belongs to nginx Plus, is not
part of it.
nginx ships limit_conn for stream, which caps how many connections are
open at once, and limit_req only for http. Nothing in the open source
server limits the rate at which connections arrive at a stream listener, so
a mail, database or VPN front end can be fed new connections as fast as the
network allows while staying inside the connection limit.
stream {
limit_req_zone $binary_remote_addr zone=perip:10m rate=5r/s;
server {
listen 25;
limit_req zone=perip burst=10 delay=5;
proxy_pass backend_smtp;
}
server {
listen 53 udp;
limit_req zone=perip burst=20 nodelay;
proxy_pass backend_dns;
}
}syntax: limit_req_zone <key> zone=<name>:<size> rate=<rate>
context: stream
Defines the shared memory zone holding the state. The key is any stream
variable or a combination of them, usually $binary_remote_addr. The rate
is given in r/s or r/m. A zone smaller than eight pages is rejected.
syntax: limit_req zone=<name> [burst=<number>] [nodelay | delay=<number>]
context: stream, server
Applies a zone. Connections above the rate are refused unless burst
allows them to queue, which is 0 by default; nodelay passes the whole
burst at once, delay=N passes the first N of it and holds the rest until
the rate allows them. Several zones may be applied to one server and are
then all consulted.
The key is read in the preaccess phase, before the connection has sent
anything, so a variable that is only known later is empty there and the zone
then applies to nothing. $ssl_preread_server_name is the obvious one:
limiting by SNI is not possible with this module.
syntax: limit_req_log_level info | notice | warn | error
default: error
context: stream, server
Level a refusal is logged at. A delayed connection is logged one level below that.
syntax: limit_req_dry_run on | off
default: off
context: stream, server
Counts and logs as usual but passes everything, so a rate can be measured against production traffic before it is enforced.
What the module did with this connection: PASSED, DELAYED, REJECTED,
DELAYED_DRY_RUN or REJECTED_DRY_RUN. Not found on a connection that
reached no limit_req. A dry run is only visible through this variable and
the error log, so an access_log carrying it is what a measurement before
enforcement is read from.
The handler runs in the preaccess phase, before the content phase: nothing is proxied, and a refused TCP connection is closed without a byte of payload having been read. A UDP session exists because a datagram arrived, so there the first datagram is read and then dropped; what is counted is the session, one per datagram unless the client keeps sending from the same port.
A refusal is logged as
limiting connections by zone "perip", excess: 1.000
a connection held back by burst as
delaying connection, excess: 0.600, by zone "perip"
and a dry run writes dry run in front of either.
The rate arithmetic is the one ngx_http_limit_req_module uses, so a rate
configured here means what it means in an http block.
The module requires a stream enabled nginx:
./configure --with-stream --add-module=/path/to/nginx-stream-limit-req-moduleor as a loadable module
./configure --with-stream \
--add-dynamic-module=/path/to/nginx-stream-limit-req-modulewith load_module modules/ngx_stream_limit_req_module.so; in the main
context. A build without --with-stream is rejected at configure time
rather than failing at the link step.
ci/build.sh 1.30.5 /tmp/nginx-test
TEST_NGINX_BINARY=/tmp/nginx-test/sbin/nginx prove -r t/
ci/rate.sh /tmp/nginx-test/sbin/nginx
ci/reload.sh /tmp/nginx-test/sbin/nginxt/ covers the configuration parser, ci/rate.sh opens sockets and counts
what the limit passes, ci/reload.sh checks that the zone survives a
reload.
BSD 2-Clause, see LICENSE. The rate arithmetic follows
ngx_http_limit_req_module, Copyright (C) Igor Sysoev, Copyright (C)
Nginx, Inc., under the same licence.