# Apache: 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.*

This guide does not cover managing `.htaccess` file.

### Locating config files

Before applying the changes we need to find the location of the config files. The location can vary depending on the way Apache was been installed. To look for the configuration we can run the following command:

```bash
apachectl -S
# or
apache2ctl -S
```

and look for `ServerRoot`

```bash
# apachectl -S                
VirtualHost configuration:
ServerRoot: "/usr/local/apache2"
...
```

Alternatively we can run the following command and look for the location of the `bin` directory.

```bash
which httpd ; which apache ; which apache2
```

The usual places where the configuration is stored is

```bash
/etc/apache2/
/etc/httpd/
/etc/httpd/conf
/usr/local/apache2
/opt/apache2 # usually if installed from source
C:\Program Files\Apache Software Foundation\Apache2.4\  # Windows
/usr/local/etc/httpd/  # Mac OS
```

The virtual host configuration can be found in the `conf` folder under `extra/httpd-vhosts.conf` or `/etc/apache2/sites-available/000-default.conf` or `/etc/apache2/sites-available/example.conf`.

### Restricting a single IP

The module that supports the following directives is `mod_authz_host`.

These are the examples of configuration on the directory level:

```apacheconf
<Directory "/opt/www/dir">
    ...
    <RequireAll>
        Require all granted
        Require not ip 8.8.8.8
    </RequireAll>
</Directory>
```

On the virtual host level:

```apacheconf
<VirtualHost *:80>
    ...
    <Location "/">
        <RequireAll>
            Require all granted
            Require not ip 8.8.8.8
        </RequireAll>
    </Location>
</VirtualHost>
```

On the endpoint level:

```apacheconf
<VirtualHost *:80>
    ...
    <Location "/login">  # notice endpoint here
        <RequireAll>
            Require all granted
            Require not ip 8.8.8.8
        </RequireAll>
    </Location>
</VirtualHost>
```

### Managing a denylist

To store denylist in a file we can use `Include` directory:

```apacheconf
<RequireAll>
    Require all granted
    Include /etc/apache2/denylist.conf
</RequireAll>
```

The `denylist.conf` can contain each directive divided by a newline.

```apacheconf
# cat denylist.conf
Require not ip 8.8.8.8
Require not ip 9.9.9.9
```

### Restrict multiple IPs

The directive supports providing multiple IPs along with CIDR ranges and partial IPs.

```apacheconf
# single IP
Require not ip 8.8.8.8

# multiple IPs
Require not ip 8.8.8.1 8.8.8.2 8.8.8.3

# partial IP
Require not ip 192.168

# CIDR range
Require not ip 9.9.9.0/24
```

### Error message

The default error message is a `403 Forbidden`.

```html
# curl localhost:8080
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html><head>
<title>403 Forbidden</title>
</head><body>
<h1>Forbidden</h1>
<p>You don't have permission to access this resource.</p>
</body></html>
```

### Applying configuration

There are many different ways to apply and reload the configuration depending on the way Apache was installed. The following example should restart the server **gracefully**.

```bash
apachectl configtest
# or
httpd -M
# or
apache2 -M
```
to test the configuration.

```bash
apachectl -k graceful
# or
/etc/init.d/httpd graceful
# or
/sbin/service httpd graceful
# or
/etc/init.d/apache2 reload
# or
sudo service apache2 reload
# or for Windows
httpd.exe -k restart
# or
apache.exe -k restart 
```
to reload.
