NGINX: Restrict access by IP address
Crude way to stop an attack in case of an emergency.
Keep in mind that this is a static configuration, which is not very effective against adversarial attacks when an attacker constantly changes their tactics.
Denylisting (that's what NGINX calls it) is done through ngx_http_access_module
, which provides static denylisting. For dynamic denylisting we would have to use NGINX Plus.
There are 2 control directives in play here: allow
and deny
. The configuration can be added either to the main file /etc/nginx/nginx.conf
or to any of the virtual hosts /etc/nginx/sites-enabled/website.conf
.
NGINX supports adding the directive in the following blocks
http
- to protect all hosts that are served from a given NGINX instanceserver
- to assert control on the virtual host levellocation
- to assert control on the specific pathlimit_except
- exclude provided HTTP verbs
http {
deny 8.8.8.8;
}
server {
deny 8.8.8.8;
}
location /login {
deny 8.8.8.8;
}
location / {
limit_except GET {
deny 8.8.8.8;
}
}
Restricting access to multiple IPs
We can also use a CIDR notation to protect from botnets deployed in a single subnet. Adding multiple directives means that all of them are going to be applied.
location /login {
deny 8.8.8.0/24;
deny 2001:0db8::/32;
}
Additional blanket value all
can be used to allow the access to a specific subnet while disabling the access to the rest.
location /login {
allow 8.8.8.0/24;
deny all;
}
Managing denylist
We can also manage it through a separate file on a filesystem.
# cat denylist.conf
deny 8.8.8.8
deny 32.32.32.32
For that we need to use include
in the NGINX configuration file.
location /login {
include denylist.conf;
}
Customizing error message
By default NGINX will return 403 Forbidden
, but we can customize it.
location /login {
deny 8.8.8.8;
error_page 403 /deny_403.html;
location = /deny_403.html {
root /usr/share/nginx/html;
allow all; # this is needed to render the page itself
}
}
Applying configuration
/usr/local/nginx/sbin/nginx -t
to test the config.
/usr/local/nginx/sbin/nginx -s reload
# or
service nginx reload
to reload.