Dynamic Blacklisting of IP Addresses
This section describes how to create a blacklist or whitelist of specific client IP addresses, which denies or allows them access to your site, and how to dynamically maintain the list of addresses.
Overview
In NGINX Plus Release 13 (R13) and later, you can blacklist some IP addresses as well as create and maintain a database of blacklisted IP addresses. You can also explicitly whitelist other IP addresses. The IP addresses database is managed with the NGINX Plus API and keyval modules.
Prerequisites
NGINX Plus Release 13 or later
Setup
First, enable the database for storing the list of blacklisted and whitelisted IP addresses.
In NGINX Plus configuration file, include the
keyval_zone
directive in thehttp
context to create a memory zone for storing keys and values. This sample directive creates a 1‑MB zone called one.http { # ... keyval_zone zone=one:1m; }
You can optionally include the
state
parameter to create a file where the key‑value database is stored and so persists across NGINX Plus reloads and restarts; in this example, one.keyval:keyval_zone zone=one:1m state=one.keyval;
Enable the NGINX Plus API in read‑write mode with the
api
directive:# ... server { listen 80; server_name www.example.com; location /api { api write=on; } }
We strongly recommend restricting access to this location, for example by allowing access only from localhost (127.0.0.1), and by restricting access to
PATCH
,POST
, andDELETE
methods to some users with HTTP basic authentication:# ... server { listen 80; server_name www.example.com; location /api { limit_except GET { auth_basic "NGINX Plus API"; auth_basic_user_file /path/to/passwd/file; } api write=on; allow 127.0.0.1; deny all; } }
Populate the key‑value database with the API’s
POST
method, supplying the data in JSON format. You can use thecurl
command as in the following example. If the zone is empty, you can enter several key‑value pairs at once; otherwise, pairs must be added one at a time.$ curl -X POST -d '{ "10.0.0.1": "1", "10.0.0.2": "1", "10.0.0.3": "0", "10.0.0.4": "0" }' -s http://www.example.com/api/3/http/keyvals/one
Define how client IP addresses are evaluated against the key‑value database, by including the
keyval
directive in thehttp
context.The directive takes advantage of the standard NGINX and NGINX Plus variable
$remote_addr
, which is set to the client IP address automatically for every request.As it processes each request, NGINX Plus:
- Looks up the first parameter (here,
$remote_addr
, preset to the client’s IP address) in the key‑value database specified by thezone=
parameter (here, one). - If a key in the database exactly matches
$remote_addr
, sets the second parameter (here,$target
) to the value corresponding to the key. In our example, the value is1
for blacklisted addresses or0
for whitelisted addresses.
http { # ... keyval_zone zone=one:1m state=one.keyval; keyval $remote_addr $target zone=one; # Client address is the key, # $target is the value; }
- Looks up the first parameter (here,
Create a rule with the
if
directive that either allows or denies access depending on the client IP address. With this rule, access is allowed when$target
is0
and denied when it is1
:if ($target) { return 403; }
Managing the Key-Value Database
You can use API methods to update a key‑value database on‑the‑fly, without requiring a reload of NGINX Plus.
All of the following examples operate on the one zone, which is accessible at http://www.example.com/api/3/http/keyvals/one.
To get the list of all database entries for a zone:
$ curl -X GET 'http://www.example.com/api/3/http/keyvals/one'
To update the value for an existing entry (in this example to change the access status for IP address 10.0.0.4 from whitelisted to blacklisted):
$ curl -X PATCH -d '{"10.0.0.4": "1"}' -s 'http://www.example.com/api/3/http/keyvals/one'
To add an entry to a populated zone:
$ curl -X POST -d '{"10.0.0.5": "1"}' -s 'http://www.example.com/api/3/http/keyvals/one'
To delete an entry:
$ curl -X PATCH -d '{"10.0.0.4":null}' -s 'http://www.example.com/api/3/http/keyvals/one'
Full Example
The full NGINX Plus configuration:
http {
# ...
keyval_zone zone=one:1m state=one.keyval;
keyval $remote_addr $target zone=one;
server {
listen 80;
server_name www.example.com;
location /api {
limit_except GET {
auth_basic "NGINX Plus API";
auth_basic_user_file /path/to/passwd/file;
}
api write=on;
allow 127.0.0.1;
deny all;
}
if ($target) {
return 403;
}
}
}
This configuration:
- Creates a keyval zone one that is 1 MB in size and also creates the file one.keyval to make the database of key‑value pairs persists across reloads and restarts of NGINX Plus.
- Enables the NGINX Plus API in write mode so that the zone can populated with IP addresses
- Enables lookup of the IP address
$remote_addr
in the key-value database as the key, and puts the value of the found key into the$target
variable. - Enables a simple rule to check for the resulting value: if the value of
$target
is1
(address is blacklisted), return403 (Forbidden)
to the client.
The following curl
command populates the empty keyval zone one with IP addresses that are blacklisted (value is 1
) or whitelisted (value is 0
):
$ curl -X POST -d '{
"10.0.0.1": "1",
"10.0.0.2": "1",
"10.0.0.3": "0",
"10.0.0.4": "0"
}' -s 'http://www.example.com/api/3/http/keyvals/one'