# NGINX: Restrict access by IP address

*Keep in mind that this is a static configuration, which is not very effective against [adversarial attacks](https://blackfedora.dev/adversarial-cycle) 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](https://docs.nginx.com/nginx/admin-guide/security-controls/denylisting-ip-addresses/) 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 instance
- `server` - to assert control on the virtual host level
- `location` - to assert control on the specific path
- `limit_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.

```bash
# 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.
