mod_antiloris is an Apache HTTP Server module that helps to mitigate Slowloris denial of service (DoS) attacks. It works by preventing new connections from the same IP address after the connection count of the IP exceeds a configurable limit.
- mod_antiloris
There is a shell script that automates the installation of mod_antiloris, courtesy of @filippolauria.
wget -q https://raw.githubusercontent.com/Deltik/mod_antiloris/main/install-antiloris.sh && chmod +x install-antiloris.sh && ./install-antiloris.sh
This script simplifies the installation process by cloning this repository, compiling the module, and configuring the necessary files for seamless integration with the Apache HTTP Server.
The installer can also be run non-interactively:
wget -qO- https://raw.githubusercontent.com/Deltik/mod_antiloris/main/install-antiloris.sh | sh -s - --accept-disclaimer
The installer can uninstall and remove the configuration files for mod_antiloris with the --uninstall
option:
wget -qO- https://raw.githubusercontent.com/Deltik/mod_antiloris/main/install-antiloris.sh | sh -s - --uninstall
The script has been tested on the following platforms:
- Ubuntu 18.04
- Ubuntu 24.04
- Debian 12
- AlmaLinux 8
- AlmaLinux 9
Pre-built modules might exist on the project's releases page. If the module is available in binary format (mod_antiloris.so
), you can install it by:
- Copying
mod_antiloris.so
to your Apache modules folder (/usr/lib64/apache2/modules/
on some Linux systems) and - Adding the following directive to your Apache configuration file (
httpd.conf
or somewhere that isInclude
d like/etc/apache2/conf.modules.d/mod_antiloris.conf
):LoadModule antiloris_module modules/mod_antiloris.so
(>= 0.7
)
mod_antiloris has more dependencies than in previous versions, but building isn't much harder. Just make sure you have cmake
installed in addition to the Apache development tools. You should also have git
so that CMake can download the rest of the dependencies automatically. To be exact:
- Suggested dependency installation for Debian/Ubuntu:
apt install -y apache2-dev cmake git
- Suggested dependency installation for RHEL/CentOS:
- With
dnf
:dnf install -y epel-release && dnf install -y gcc /usr/bin/apxs make cmake3 git
- With
yum
:yum install -y epel-release && yum install -y gcc /usr/bin/apxs make cmake3 git
- With
- Suggested dependency installation for Fedora:
dnf install -y gcc /usr/bin/apxs make cmake git redhat-rpm-config
mod_antiloris is most easily installed by running these commands on your Apache server:
git clone https://github.com/Deltik/mod_antiloris.git
cd mod_antiloris
# Optional: git checkout "v${ANTILORIS_VERSION}"
# Replace ${ANTILORIS_VERSION} with the desired version of this software.
# RHEL/CentOS 6 and 7 compatibility
if type cmake3 > /dev/zero 2>&1; then alias cmake="cmake3"; fi
cmake .
make
apxs -i -a -n antiloris mod_antiloris.so
The output of the apxs
command shows where the module was installed, so you can use that information to uninstall the module, if desired.
(< 0.7
)
mod_antiloris is most easily installed by copying or downloading the source code to your Apache server and running the following command:
apxs -a -i -c mod_antiloris.c
The output of the command shows where the module was installed, so you can use that information to uninstall the module, if desired.
mod_antiloris works best in combination with mod_reqtimeout, because:
- mod_reqtimeout drops connections if they are too slow but is vulnerable when a client opens a lot of connections and prevents legitimate connections during the timeout period.
- mod_antiloris prevents a client from hogging up connection slots but does not drop slow connections.
Using both modules at the same time protects against both kinds of DoS offenders.
LoadModule reqtimeout_module modules/mod_reqtimeout.so
<IfModule mod_reqtimeout>
RequestReadTimeout header=20-40,MinRate=500 body=20-40,MinRate=500
</IfModule>
LoadModule antiloris_module modules/mod_antiloris.so
<IfModule antiloris_module>
IPTotalLimit 16
ExemptIPs 127.0.0.1 ::1
</IfModule>
The above example mitigates Slowloris DoS attacks by:
- Using mod_reqtimeout to drop connections that don't meet the data transfer rate requirement and
- Using mod_antiloris to prevent more than 16 concurrent connections from the same IP.
Directive | Default | Description | Version |
---|---|---|---|
IPTotalLimit |
30 |
Maximum simultaneous connections in any state per IP address. If set to 0 , this limit does not apply. This limit takes precedence over all other limits. |
>= 0.7 |
IPOtherLimit |
10 |
Maximum simultaneous idle connections per IP address. If set to 0 , this limit does not apply. |
>= 0.6 |
IPReadLimit |
10 |
Maximum simultaneous connections in READ state per IP address. If set to 0 , this limit does not apply. |
>= 0.6 |
IPWriteLimit |
10 |
Maximum simultaneous connections in WRITE state per IP address. If set to 0 , this limit does not apply. |
>= 0.6 |
ExemptIPs |
none | Space-delimited list of IPv4 and IPv6 addresses, ranges, or CIDRs which should not be subjected to any limits by this module. | >= 0.8 |
These directives no longer apply to the latest version of this module:
Directive | Default | Description | Version |
---|---|---|---|
IPReadLimit |
10 |
Maximum simultaneous connections in READ state per IP address. If set to 0 , this limit does not apply. |
>= 0.1, < 0.5.2 |
IPReadLimit |
20 |
Maximum simultaneous connections in READ state per IP address. If set to 0 , this limit does not apply. |
= 0.5.2 |
LocalIPs |
none | List of IPs (separated by spaces), the connections of which are always allowed (not subjected to any limits) | ~> 0.6.0 |
WhitelistIPs |
none | Space-delimited list of IPv4 and IPv6 addresses, ranges, or CIDRs which should not be subjected to any limits by this module. | ~> 0.7.0 |
Directive Alias | Is Equivalent To | Applicable Version |
---|---|---|
LocalIPs |
WhitelistIPs |
~> 0.7.0 |
LocalIPs |
ExemptIPs |
>= 0.8 |
WhitelistIPs |
ExemptIPs |
>= 0.8 |
(>= 0.6
) Allows 10 open connections in each state for a total of 30 concurrent connections per IP address,
and ignores limits for IP addresses 127.0.0.1
and ::1
:
LoadModule antiloris_module modules/mod_antiloris.so
<IfModule antiloris_module>
IPOtherLimit 10
IPReadLimit 10
IPWriteLimit 10
LocalIPs 127.0.0.1 ::1
</IfModule>
(>= 0.7
) Per IP address, allows 8 open connections in each state, but no more than 16 connections of any state:
LoadModule antiloris_module modules/mod_antiloris.so
<IfModule antiloris_module>
IPTotalLimit 16
IPOtherLimit 8
IPReadLimit 8
IPWriteLimit 8
</IfModule>
(>= 0.8
) Default mitigation settings, but exclude Cloudflare IP addresses and localhost IP addresses:
LoadModule antiloris_module modules/mod_antiloris.so
<IfModule antiloris_module>
ExemptIPs 127.0.0.1 ::1 173.245.48.0/20 103.21.244.0/22 103.22.200.0/22 103.31.4.0/22 141.101.64.0/18 108.162.192.0/18 190.93.240.0/20 188.114.96.0/20 197.234.240.0/22 198.41.128.0/17 162.158.0.0/15 104.16.0.0/13 104.24.0.0/14 172.64.0.0/13 131.0.72.0/22 2400:cb00::/32 2606:4700::/32 2803:f800::/32 2405:b500::/32 2405:8100::/32 2a06:98c0::/29 2c0f:f248::/32
</IfModule>
For directives that accept IP addresses, this module matches IPv4 and IPv6 addresses in the form of:
- (
>= 0.6
) Individual addresses (e.g.127.0.0.1
matches only127.0.0.1
), - (
>= 0.7
) Hyphenated ranges (e.g.127.0.1.1-127.0.1.3
matches127.0.1.1
,127.0.1.2
, and127.0.1.3
), or - (
>= 0.7
) CIDR notation (e.g.127.0.2.0/30
matches127.0.2.0
,127.0.2.1
,127.0.2.2
, and127.0.2.3
).
Here are more examples:
127.0.0.1
matches the individual IPv4 address127.0.0.1
.192.168.0.100-192.168.0.200
inclusively matches the IPv4 range192.168.0.100
to192.168.0.200
.10.0.0.0/8
inclusively matches the IPv4 range from10.0.0.0
to10.255.255.255
.::1
matches the individual IPv6 address0:0:0:0:0:0:0:0001
.::ffff:ac10:0-::ffff:ac10:8
inclusively matches the IPv6 range0:0:0:0:0:ffff:ac10:0
to0:0:0:0:0:ffff:ac10:8
.FD12:3456:789A:1::/64
inclusively matches the IPv6 rangefd12:3456:789a:0001:0:0:0:0
tofd12:3456:789a:0001:ffff:ffff:ffff:ffff
.
This software uses Semantic Versioning. From a version number MAJOR.MINOR.PATCH
:
MAJOR
increases when behavior changes that breaks how previous versions worked,MINOR
increases when new features are added while being compatible with how previous versions worked, andPATCH
increases when bugs are fixed without breaking how previous versions worked.
In the documentation, version constraints are used to indicate to which versions the piece of documentation applies:
>=
means starting from this version,>
means after this version,<=
means up to and including this version,<
means up to but not including this version,=
means this version only, and~>
means this version and any newer versions after the last point (.
).
>= 1.5
matches version1.5.0
and higher.> 1.4
matches version1.4.1
and higher.<= 1.3.1
matches version1.3.1
,1.3.0
,1.3
, and lower.< 1.4
matches any version lower than1.4
.= 1.0
matches version1.0
and1.0.0
.~> 1.4
is the same as>= 1.4, < 2
.~> 1.3.0
is the same as>= 1.3.0, < 1.4
.~> 2
is the same as>= 2.0.0
.= 1.0, = 1.1, = 1.2, = 1.3
matches only versions1.0
,1.1
,1.2
,1.3
, and their.0
PATCH
versions.
This module is a fork of NewEraCracker's mod_antiloris, which itself is a fork of mind04's mod_antiloris.
mod_antiloris versions < 1
are intended to be backwards-compatible with both upstream projects, but the default directive values may have changed.
mod_antiloris vs. mod_reqtimeout
mod_reqtimeout effectively kicks slow connections, but it does not prevent those connections from being made in the first place. This means that during mod_reqtimeout's timeout grace period, Apache's connection slots can be filled up.
mod_antiloris prevents too many slow connections made from one client. This addresses the drawback of mod_reqtimeout. For the best DoS mitigation, mod_antiloris should be combined with mod_reqtimeout.
mod_antiloris vs. mod_qos
At the time of writing, mod_qos only works on Apache 2.2 with MPM worker. mod_qos is probably better than mod_antiloris on Apache 2.2 and MPM worker, but it seems to be broken on newer Apache major versions and on other MPMs.
mod_antiloris vs. mod_noloris
mod_noloris is based on mod_antiloris = 0.3
, but it runs an IP ban check on a (default) 10-second timer instead of on every request like in mod_antiloris. This leaves a window of time for a Slowloris DoS to make Apache unresponsive.
mod_noloris also has other drawbacks:
- Banned IPs are not unbanned until the server is restarted, which means legitimate requests can be banned indefinitely if the client is sufficiently unlucky.
- Only connections in the
SERVER_BUSY_READ
state are counted, so variant Slowloris attacks using a different state would be immune to mitigations. - A more clever Slowloris attacker can anticipate the timer to make their attack invisible to mod_noloris.
- Banned IPs are scanned sequentially on every request (linear time) instead of looked up in a hash table (constant time). The bigger the banlist, the larger the performance penalty upon every request, even if the request is legitimate.
Although mod_noloris in theory consumes less time and resources on every request (if the banlist is empty) due to the deferred connection scan, the savings are negligible. On a test server with 150 connection slots, mod_antiloris configured with an allowlist of Cloudflare IP addresses had practically no effect on the response time. The test was conducted by requesting a static HTML file 100000 times with 10 concurrent requests to download the entire file. Data summary:
Slowloris mitigation | N | min (s) | q1 (s) | median (s) | q3 (s) | max (s) | mean (s) | stddev (s) |
---|---|---|---|---|---|---|---|---|
none | 100000 | 0.000573 | 0.001035 | 0.001123 | 0.001231 | 0.008474 | 0.001170 | 0.000300 |
mod_antiloris = 0.7.2 |
100000 | 0.000539 | 0.001068 | 0.001166 | 0.001287 | 0.010362 | 0.001212 | 0.000314 |
mod_antiloris = 0.8.0 |
100000 | 0.000510 | 0.001054 | 0.001146 | 0.001260 | 0.011931 | 0.001197 | 0.000312 |
mod_antiloris vs. ModSecurity
ModSecurity depends on other sources to decide whether to block a connection. At the time of writing, the OWASP ModSecurity Core Rule Set V3.0 has a rule to block too many requests to dynamic resources, but there is nothing by default to block Slowloris specifically.
It is possible to use the HTTP 408 returned by mod_reqtimeout to increment a denial-of-service counter in ModSecurity, but this suffers from the same drawbacks as mod_reqtimeout.
mod_antiloris vs. mod_evasive
mod_evasive does nothing to mitigate Slowloris. It is designed to return HTTP 403 to the client if the client makes too many requests, but it assumes that the client is willing to receive the response. Slowloris, of course, doesn't, so the connection slots remain occupied.
mod_antiloris vs. mod_limitipconn
mod_limitipconn is conceptually similar to mod_antiloris, but mod_limitipconn hooks too late and can't mitigate Slowloris. It is designed to return HTTP 503 to the client if the client makes too many connections, but it assumes that the client is willing to receive the response. Slowloris, of course, doesn't, so the connection slots remain occupied.
(>= 0.7
)
After generating the build files from cmake
, tests can simply be run with this command:
make test