2026年11月12日
2026年11月12日
ModSecurity vs fail2ban: Differences and How to Use Both on WordPress
This article is a localized edition of the Japanese original. Read the Japanese original
ModSecurity and fail2ban are both tools for "stopping unauthorized access," but the way they stop it is fundamentally different. ModSecurity is a WAF (web application firewall) that inspects the contents of each request inside the web server and blocks it, while fail2ban reads logs after the fact and locks out IP addresses that have failed repeatedly, for a set time, using the firewall. So the question is not "which is better"; it is realistic to divide roles according to the attacks you want to stop, and in many cases to use both together. This article explains how the two differ, how to use each on a WordPress server, and how to think about the configuration when using them together.
How they differ
ModSecurity: looks at the contents of requests and stops them one by one
ModSecurity is a WAF engine that runs built into the web server. There is the version 2 line, widely used as an Apache module, and the version 3 line, which consists of a library independent of the web server (libmodsecurity) and a connector for nginx.
ModSecurity itself is the inspection mechanism, and what counts as an attack is decided by rules. Generally you use OWASP's Core Rule Set (CRS). The CRS detects patterns such as SQL injection, cross-site scripting, and directory traversal, and uses an "anomaly score" method that adds up the points of each rule and blocks requests that exceed a threshold. You adjust the strictness of detection with the "paranoia level."
Note that ModSecurity was developed under the lead of Trustwave for a long time, but it was moved to an OWASP project in 2024. There are also compatible alternative implementations such as OWASP Coraza. If you adopt it, check your distribution's packages and the project's current availability (as of October 2026).
fail2ban: reads logs and locks out repeat offenders
fail2ban watches log files and blocks, with the firewall for a set time (bantime), IP addresses for which lines matching a regular expression (a filter) exceed a set number of times (maxretry) within a set period (findtime). A combination of a monitored target and conditions is called a "jail," and it can cover a wide range of services that write logs, such as SSH, mail servers, and web servers.
Blocking is done by a firewall such as iptables, nftables, or firewalld, so traffic from a locked-out IP address is stopped before it reaches the web server.
Comparison
| Aspect | ModSecurity | fail2ban |
|---|---|---|
| Basis for judgment | Contents of the request (URL, headers, body) | Results left in logs |
| When it stops | Before that request is processed | After a set number of times is exceeded |
| What it stops | One request | An IP address (for a set time) |
| Attacks it handles well | Attack patterns such as SQL injection and XSS | Brute force, repeated scanning |
| Main burden | Tuning false positives, processing load | Writing filters, getting the correct source IP |
What each one prevents
Where ModSecurity fits
fail2ban cannot prevent an attack that succeeds in a single request. By the time it is in the log, that request has already been processed. SQL injection aimed at a plugin vulnerability, or path manipulation aimed at reading files, requires a mechanism like ModSecurity that looks at the contents before processing.
However, a WAF does not fix the vulnerability itself. Prioritize updates to WordPress core, plugins, and themes, and think of the WAF as a layer that reduces damage in the meantime.
Where fail2ban fits
Password brute-forcing against wp-login.php and floods of requests to xmlrpc.php look normal one request at a time, so they are attacks that are hard to stop with WAF rules. fail2ban, which judges by behavior such as "the same party is failing many times in a short period," is better suited. The same goes for brute-forcing against SSH.
Notes on using fail2ban with WordPress
Note that WordPress login failures are often returned with a normal 200 as the HTTP status, so it is hard to tell failures from the web server's access log alone. There are the following approaches.
- Use a plugin that writes login failures to a log: There are plugins such as "WP fail2ban" that record login failures and the like in syslog. fail2ban then watches that log. The details of the features change by version, so check the plugin's description.
- Count POSTs to
wp-login.phpin the access log: You cannot tell whether they failed, so set the threshold somewhat loose so that you do not lock out legitimate users.
You can also write logs yourself using the wp_login_failed action, but in that case, take care not to record usernames or passwords as they are.
Another pitfall is the source IP address. On a server behind a CDN or reverse proxy, the source recorded in the log becomes the CDN's address, and as is, you would block the whole CDN. On the web server side, configure it to extract the real source (nginx's real_ip module or Apache's mod_remoteip) and limit the addresses of the proxies you trust. Furthermore, blocking traffic that passes through a CDN with the server's firewall has no effect, so also consider a setup that uses an action that blocks through the CDN's API.
Configuration flow when using both
When you combine the two, you get a division of labor in which ModSecurity blocks attack requests and fail2ban reads its records and locks out repeat offenders. Do the work in a staging environment before production, and back up the configuration files before you proceed.
- Run ModSecurity in detection-only mode: Set
SecRuleEngine DetectionOnlyand just collect logs for a while. Check that no false positives appear in your normal operations, such as the WordPress admin screen, saving in the block editor, and use of the REST API. - Tune false positives with exclusion rules: Rather than disabling the rule that was triggered, exclude it only for the specific URL or parameter. The CRS has a mechanism to enable exclusion settings for WordPress, so check the documentation for the CRS version you use.
- Switch to blocking mode: Change to
SecRuleEngine Onand start blocking at the anomaly score threshold. - Prepare the fail2ban jails: Create a jail for login failures and a jail that reads ModSecurity's block records. fail2ban sometimes ships with a filter for ModSecurity logs.
Here is an example fail2ban jail (change the file names and log paths to suit your environment).
# /etc/fail2ban/jail.d/wordpress.local
[wordpress-login]
enabled = true
port = http,https
filter = wordpress-login
logpath = /var/log/nginx/access.log
# Block for 1 hour if more than 10 times in 10 minutes
findtime = 10m
maxretry = 10
bantime = 1h
# Addresses that are never blocked, such as the administrator's fixed IP
ignoreip = 127.0.0.1/8 ::1 203.0.113.10
# /etc/fail2ban/filter.d/wordpress-login.conf
[Definition]
failregex = ^<HOST> .* "POST /wp-login\.php
ignoreregex =
After configuring, check that the filter matches the log before you enable it.
sudo fail2ban-regex /var/log/nginx/access.log /etc/fail2ban/filter.d/wordpress-login.conf
sudo systemctl reload fail2ban
sudo fail2ban-client status wordpress-login
Putting your own IP address in ignoreip prevents the accident of locking yourself out during testing. If you do get locked out, you can lift the ban with sudo fail2ban-client set wordpress-login unbanip <IP address>.
On rental servers
On shared rental servers, you almost never can install ModSecurity or fail2ban yourself. Many providers offer WAF features on the server side, so check whether you can enable it in the control panel. Limiting login attempts is realistically done with a WordPress security plugin.
Summary
- ModSecurity is a WAF that inspects the contents of requests before processing; fail2ban is a tool that reads logs after the fact and blocks IP addresses for a set time
- ModSecurity suits attacks that succeed in one request (such as SQL injection), and fail2ban suits repeated attacks (such as login brute force)
- Tune false positives in ModSecurity's detection-only mode before switching to blocking
- fail2ban requires logs that can distinguish WordPress login failures, and the correct source IP behind a CDN
- Neither replaces fixing vulnerabilities, so prioritize updating core and plugins
- How to set up a WAF with Apache's mod_security
- How to stop brute force attacks on WordPress with Fail2Ban
Questions about WordPress? The publisher of this site is based in Japan and replies in Japanese. Contact (Japanese)