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.

Article continues below

Our Sponsored Pick
| TrustScore 4.6

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.

Pros:
  • Cloudflare integration
  • Automatic daily backups
  • DDoS protection
Cons:
  • Exclusively for WordPress
Explore Platform Read Reviews
We earn a commission if you click this link and make a purchase at no additional cost to you.
09/08/2024 1:09 am UTC

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:

/etc/fail2ban/jail.local

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.

/etc/fail2ban/jail.d/jail.local

[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 dayfindtime = 1d
It finds 2 unsuccessful loginsmaxretry = 2
Then ban for six weeksbantime = 6w
While Ignoring the following IPsignoreip = 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:

/path/to/wordpress/root/wp-config.php

/** 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