Learn how to protect your App | Website | WordPress blog by installing and configuring Fail2ban. Even though fail2ban covers a large array of services and processes, for general example purposes we will cover the following:
SSH Jail
- General approach; For those looking for overall server protection.
WordPress Jail
- Use Specific approach; For those who are trying to figure out why fail2ban was auto-installed by their server platform.
Manually Banning IPs
- Use fail2ban’s command-line utility to manage security in your application.
Recently I wound up going through a ton of resources while trying to figure out how to configure and use fail2ban on one of my projects.
I discovered a curious little plugin auto-installed on a WordPress application called wp-fail2ban. After a quick online search, it is said to be a security feature. The only problem was that it had very few configuration settings available to me, if not any.
2 hours later….
I figured out that it was installed and configured optimally out of the box by Digitalocean, which was the cloud server platform I was working with at the time.
To their weak defense ( more on that later ), I was actually warned of this early on. I found a support forum topic with the following:
The shipped configuration should be plenty adequate for most droplets.
This was in response to a customer that could not figure out if further configuration was needed.
In the customer’s defense, the next question asked was to please explain what plenty adequate meant, since he/she found no further explanation as to what was done or configured out of the box. And then… the thread went silent.
Check out the footnotes for the complete conversation. [*]
Now, me being a control freak, I jumped into the rabbit hole 🤓. Lessons learned coming up next.
Fail2Ban is NOT a WordPress plugin
But it does have one 😊.
Fail2Ban is an intrusion prevention framework written in python that can be run on POSIX systems.
It works by monitoring logs for specific patterns and running scripts when a match occurs. Ex. A script that bans certain IPs after attempting to log-in several times unsuccessfully.
We can install it on our ubuntu servers and set up our config by visiting our /etc/fail2ban
directory.
While trying to figure out how the Wp-Fail2ban plugin worked, I felt confused by all the documentation I found that had nothing to do with WordPress; Until the fact mentioned above finally clicked for me.
Now if I sound naive for not knowing this, so be it, but judging from the Digitalocean forum, I was not alone in this ship.
![](https://bettersnippets.com/btrsnpt-child-theme/shortcodes/we-recommend/images/down-arrow@1.webp)
Article continues below
![](https://bettersnippets.com/btrsnpt-child-theme/shortcodes/we-recommend/images/kinsta-logo-light@2.webp)
So I know our tutorials are totally awesome 😉. But maybe, going through how-to's is not how you would like to be spending your precious time. Imagine a world where things just work. Kinsta's hosting platform gets our official -"Easy Way of the Day" seal. Advanced features that are incredibly easy to set up.
- Cloudflare integration
- Automatic daily backups
- DDoS protection
- Exclusively for WordPress
Installing Fail2ban on Ubuntu 20.04
Most docs IMHO felt pretty crude, including Fail2ban’s own docs. [*]
In no way Is this me bashing the authors, fail2ban is an open-source package, and we are all welcome to help out in any way we can.
So here is a quick set of instructions I put together as a guide, in case you are using an Ubuntu setup.
But, how do I know if I already have fail2ban installed ?
You might say.
Simple. Before trying to install it, SSH to your server and try the following on your command line:
sudo systemctl status fail2ban
If installed, you should see something like the following:
fail2ban.service - Fail2Ban Service
Loaded: loaded (/lib/systemd/system/fail2ban.service; enabled; ... )
Active: active (running) since Wed 2020-08-19 06:16:29 UTC; 27s ago
Docs: man:fail2ban(1) Main PID: 1251 (f2b/server) Tasks: 5 (limit: 1079)
Memory: 13.8M
CGroup: /system.slice/fail2ban.service
└─1251 /usr/bin/python3 /usr/bin/fail2ban-server -xf start
If not, then a simple:
sudo apt update
sudo apt install fail2ban
Should do the trick for you. Now try running sudo systemctl status fail2ban
again and see how it went.
Configuring Fail2ban
The complete purpose of the framework is to “Jail” services. Fail2ban scans logs in search of specific patterns set in your filter files fail2ban/filters.d
that is in turn controlled by the .conf or .local configuration file.
After installation, fail2ban ships with default .conf files that we should not touch:
/etc/fail2ban/jail.conf
/etc/fail2ban/jail.d/defaults-debian.conf
To create your own rules try copying the jail.conf file into the jail.d directory and renaming it to jail.local:
cd /etc/fail2ban
cp jail.conf jail.d/jail.local
.local files overwrite .conf files.
Open the file using your favorite editor ( vim in my case ).
vim jail.d/jail.local
Each option contains comments as to what it does, as an example, this would be whitelisting an IP:
ignoreip = 127.0.0.1/8 ::1 9.52.94.113 192.168.1.0/24
Uncomment the line and edit as necessary, IPs are separated by a space.
I really encourage you to go through the file and learn about the config options available to you. Since it is not something we will go through in detail in this article.
Fail2Ban Jails
Fail2ban works on the concept of jails. These are service-specific configurations that tell fail2ban how to deal with system log patterns related to the execution of the process in question ( Ex SSH ).
Now that was a mouthful 🤔, let’s go over what this means with examples.
[sshd]
enabled = true
maxretry = 2
findtime = 1d
bantime = 6w
ignoreip = 9.52.94.113 127.0.0.1/8
This snippet would go in our jail.d/jail.local
file. It controls the activation and configuration of a filter file that resides in our fail2ban/filters.d
directory.
A filter file ( In this case filter.d/sshd.conf
) contains the logic that defines the jail. To activate a jail simply set enabled = true
.
In the example above we are setting the sshd filter to go off if:
In a time period of one day | findtime = 1d |
It finds 2 unsuccessful logins | maxretry = 2 |
Then ban for six weeks | bantime = 6w |
While Ignoring the following IPs | ignoreip = 9.52.94.113 |
To me, this was quite a neat discovery. Since I finally figured out how fail2ban interfaces with WordPress. It has a notion of certain services through added filters. And it seems WordPress was one of them.
Fail2ban WordPress Filter
To make things better, I didn’t have to write a filter for WordPress, because it already exists:
wordpress-hard.conf
# Fail2Ban filter for WordPress hard failures
# Auto-generated: 2018-11-04T16:40:53+00:00
#
[INCLUDES]
before = common.conf
[Definition]
_daemon = (?:wordpress|wp)
failregex = ^%(__prefix_line)sBlocked authentication attempt for .* from <HOST>$
^%(__prefix_line)sBlocked user enumeration attempt from <HOST>$
^%(__prefix_line)sSpam comment \d+ from <HOST>$
^%(__prefix_line)sXML-RPC multicall authentication failure from <HOST>$
^%(__prefix_line)sPingback error .* generated from <HOST>$
^%(__prefix_line)sAuthentication attempt for unknown user .* from <HOST>$
^%(__prefix_line)sXML-RPC authentication attempt for unknown user .* from <HOST>$
ignoreregex =
# DEV Notes:
# Requires the 'WP fail2ban' plugin:
# https://github.com/invisnet/wp-fail2ban/
#
# Author: Charles Lecklider
wordpress-soft.conf
# Fail2Ban filter for WordPress soft failures
# Auto-generated: 2018-11-04T16:40:53+00:00
#
[INCLUDES]
before = common.conf
[Definition]
_daemon = (?:wordpress|wp)
failregex = ^%(__prefix_line)sAuthentication failure for .* from <HOST>$
^%(__prefix_line)sXML-RPC authentication failure for .* from <HOST>$
ignoreregex =
# DEV Notes:
# Requires the 'WP fail2ban' plugin:
# https://github.com/invisnet/wp-fail2ban/
#
# Author: Charles Lecklider
Create two files inside your filters folder and copy the two filters respectively inside:
vim filter.d/wordpress-hard.conf
vim filter.d/wordpress-soft.conf
Then manage it by pasting the following on your jail.local ( If you jumped directly here, see info above to create it ):
[wordpress-hard]
enabled = true
filter = wordpress-hard
logpath = /var/log/auth.log
maxretry = 1
port = http,https
[wordpress-soft]
enabled = true
filter = wordpress-soft
logpath = /var/log/auth.log
maxretry = 3
port = http,https
Use this to configure fail2ban for WordPress.
WordPress-hard is designed to handle situations that are considered almost always malicious:
- Blocked users
- Pingback errors
WordPress-soft is designed to handle situations where a hard ban would be too much, like failing to add the correct password at login.
Wp-Fail2ban Plugin
Now finally, for those reading this because they found the Wp-fail2ban WordPress plugin installed by default. The plugin is simply a friendly GUI for WordPress users to extend fail2ban’s functionality and it is a must if you want to use the WordPress filters. It logs WordPress-related events so fail2ban can pick them up.
It includes two options:
- Free ( Non-paid ): You can manage the extra options by adding constant definitions the
/wp-config.php
file. - Premium: Manage it through settings on your wp-admin dashboard.
Now, remember, these options are only added configurations, an interface for fail2ban to work with WordPress, and a GUI showing your latest log entries. Even if nothing is selected, make sure to check if the WordPress fail2ban Jail is set and active on your server.
For those on the freemium model that have access to the wp-config file, here is a quick snippet to turn on some of the extra features:
/** Stop attackers listing existing usernames. */
define('WP_FAIL2BAN_BLOCK_USER_ENUMERATION', true);
/** Allow email addresses only for login. */
define('WP_FAIL2BAN_BLOCK_USERNAME_LOGIN', true);
For a complete list of constant definitions available check out the footnotes for the official docs. [*]
Command line tool
Fail2ban also provides a useful command-line tool to interact with it:
fail2ban-client set wordpress-hard banip 123.123.123.123
The above bans an IP using wordpress-hard Jail.
Need to get the status of configured Jails? Try using the status function. You can also try passing a jail name after the status command:
fail2ban-client status
fail2ban-client status wordpress-hard
To get a complete list of functions the CLI utility has available, be not afraid of passing ye old -h option to it 😉.
fail2ban-client -h
Footnotes