Nginx Rate Limiting and Access Control Configuration Guide
Rate Limiting
Nginx provides two distinct types of rate limiting mechanisms:
- Connection frequency control via
limit_conn_module - Request frequency control via
limit_req_module
HTTP Connection vs Request Behavior
HTTP operates over TCP, requiring a three-way handshake before data transfer begins. Once a TCP connection is established, requests and responses can flow freely.
Key distinction: A single TCP connection can generate multiple HTTP requests, but each HTTP request originates from one TCP connection.
Connection Limiting Module
The ngx_http_limit_conn_module constrains the number of simultaneous connections per defined key, typically limiting connections from a specific IP address.
Only connections that have been fully processed and whose request headers have been completely read are counted.
Configuration Directives:
Syntax: limit_conn_zone key zone=name:size;
Default: —
Context: http
Syntax: limit_conn zone number;
Default: —
Context: http, server, location
The first directive allocates shared memory for tracking connections keyed by an Nginx varible (commonly binary_remote_addr). The name parameter identifies the zone, while size defines the memory allocation.
The second directive applies the limit, where zone references the previously defined zone and number specifies the maximum concurrent connections allowed.
Request Limiting Module
The ngx_http_limit_req_module controls the procesing rate of requests per defined key using a "leaky bucket" algorithm.
Configuration Directives:
Syntax: limit_req_zone key zone=name:size rate=rate;
Default: —
Context: http
Syntax: limit_req zone=name [burst=number] [nodelay];
Default: —
Context: http, server, location
The rate parameter accepts values in requests per second (e.g., 1r/s). The optional burst parameter queues excess requests, while nodelay allows immediate processing of queued requests.
Practical Configuration Example
limit_conn_zone $binary_remote_addr zone=connection_pool:1m;
limit_req_zone $binary_remote_addr zone=request_pool:1m rate=1r/s;
server {
listen 80;
server_name example.com;
location / {
root /var/www/html;
index index.html index.htm;
# Connection limit: 1 concurrent connection per IP
# limit_conn connection_pool 1;
# Request limit with burst queuing
# limit_req zone=request_pool burst=3 nodelay;
# Request limit without burst
# limit_req zone=request_pool;
}
}
Note: binary_remote_addr stores client IP addresses in a compact binary format, consuming approximately 10 bytes less memory compared to remote_addr.
Load Testing:
ab -n 40 -c 20 http://example.com/
Without rate limiting, all 40 requests succeed. With limit_req zone=request_pool active (1 request per second per client), only the first request completes successfully within the test window.
Access Control
Nginx implements two primary access control strategies:
- IP-based restrictions using
http_access_module - User authentication using
http_auth_basic_module
IP-Based Access Control
The ngx_http_limit_conn_module restricts access to specific client addresses based on IP, CIDR notation, or UNIX domain sockets.
Configuration Directives:
Syntax: allow address | CIDR | unix: | all;
Default: —
Context: http, server, location, limit_except
Syntax: deny address | CIDR | unix: | all;
Default: —
Context: http, server, location, limit_except
Blocking Specific IP Addresses:
location ~ ^/admin.html {
root /var/www/html;
deny 192.168.1.6;
allow all;
index index.html index.htm;
}
Allowing Only Specific Subnet:
location ~ ^/admin.html {
root /var/www/html;
allow 192.168.1.0/24;
deny all;
index index.html index.htm;
}
Apply changes with:
nginx -tc /etc/nginx/nginx.conf
systemctl reload nginx
Module Limitations:
The IP-based access control identifies clients by their direct connection IP (remote_addr). When requests pass through proxy servers or load balancers, this approach becomes ineffective since Nginx only sees the proxy's IP.
Solutions for Proxied Environments:
- Utilize the
X-Forwarded-Forheader for client identification - Implement the
geomodule for IP-based logic - Pass client information through custom HTTP variables
The X-Forwarded-For header propagates original client information:
X-Forwarded-For = Client IP, Proxy-1 IP, Proxy-2 IP, ...
Basic Auhtentication Module
The http_auth_basic_module enforces username/password authentication before granting access.
Configuration Directives:
Syntax: auth_basic string | off;
Default: auth_basic off;
Context: http, server, location, limit_except
Syntax: auth_basic_user_file file;
Default: —
Context: http, server, location, limit_except
Password File Format:
# comment
user1:password1
user2:password2:comment
user3:password3
Generate passwords using Apache's htpasswd utility or OpenSSL:
yum -y install httpd-tools
htpasswd -c /etc/nginx/auth_conf admin
Protected Location Configuration:
location ~ ^/admin.html {
root /var/www/html;
auth_basic "Restricted Area";
auth_basic_user_file /etc/nginx/auth_conf;
index index.html index.htm;
}
Validate and reload:
nginx -tc /etc/nginx/nginx.conf
systemctl reload nginx
Authentication Limitations:
- User credentials stored in static files lack scalability
- Manual management becomes cumbersome at scale
Alternative Approaches:
- Integrate with Lua scripts for dynamic validation
- Configure LDAP authentication via
nginx-auth-ldapmodule