According to financesonline.com, more than 80% of website breaches through hacking involved either brute force, or the use of lost or stolen credentials.

If you’re running a website, it’s an almost certainty that your website is constantly being bombarded with login attempts. Unauthorized access is a matter of when, not if.

To ensure your website is secure, and fully protected from this kind of attempted hack, it’s vital to start using a solution such as Fail2ban.

Fail2ban is a software tool that automatically blocks suspicious IP addresses and prevents them from connecting to your server.

In this article, we will explain exactly how to make sure that your website is fully protected the right way by showing you how to install and configure IP blocking for your WordPress website using Fail2ban.

What Is Fail2ban?

Fail2ban is an open-source software product that monitors log files for suspicious activity. It can be configured to take the action needed to prevent further attacks. This method is widely used to protect web servers, applications, and other network services from brute-force attacks and DDOS attacks.

Fail2ban is configured by default on RunCloud for SSH logins. If you try to log in to your server via SSH with incorrect credentials, your own IP address will be temporarily banned and you will get the following error:

ssh: connect to host example.com port 22: Connection timed out

By configuring a few settings, this protection can also be applied to your WordPress login form.

Configuring Fail2ban for WordPress

Start by logging in to your server via SSH – make sure that you have superuser access.

Locate Log Files

On Nginx servers, RunCloud stores the log files in /home/runcloud/logs/apache2/ and /home/runcloud/logs/nginx/ – along with the name of each web application. Use the following command to see all available log files of Apache2:

ll /home/runcloud/logs/apache2/

In the above example we can see that there are two web applications running on the server, and each of those applications generate both an access log and an error log.

On OpenLiteSpeed servers, these logs are stored at /home/runcloud/logs. Use the following command to view the logs stored on your server:

ls -lah /home/runcloud/logs

Let’s say we want to configure the Fail2ban for the “app-schulist” application.

We will begin by verifying whether the /home/runcloud/logs/apache2/app-schulist_access.log file is the correct log file to watch for failed login attempts. To do this, run the following command in your terminal to get notified about failed login attempts, (don’t forget to replace “app-schulist” with the name of your application):

tail -f /home/runcloud/logs/apache2/app-schulist_access.log | grep "POST /wp-login.php"   

After running the command, go to your WordPress dashboard and try logging in with invalid credentials. You should see a log message in your terminal for each failed login attempt.

terminal screenshot of logs

If you are using OpenLiteSpeed servers, just change the path of the log file in the above command. It should look something like following example:

tail -f /home/runcloud/logs/app-keeling_access.log | grep "POST /wp-login.php"

Once you have verified the log file, press Ctrl + C in your terminal to stop monitoring for new log entries. Make sure to take a note of the location of this log file. 

Configuring Fail2ban Jail

Fail2ban comes with a default configuration file that comes with sensible defaults. It is recommended to leave the default configuration files untouched. If you want to make any changes, you should create another configuration file that overrides the default configuration.

Run the following command with root privileges in your terminal to create a new file and open it in a text editor:

cp /etc/fail2ban/jail.{conf,local}
nano /etc/fail2ban/jail.local

Once you have opened the file, scroll down to the “jails” section using the arrow keys on your keyboard, and then paste the following code to create a new entry. (Once again, make sure to replace the name of the log file with the name that you noted in the last step.)

[wordpress-auths]
enabled = true
port = http,https
filter = wordpress-auth
logpath = /home/runcloud/logs/apache2/app-schulist_access.log

If you have more than one WordPress website on your server, you can append more entries to the logpath variable (as shown above). This will ensure that all of the specified log files will be monitored for the given criteria.

If you don’t want to constantly add or remove the log path in the configuration file, you can replace the name of the application with * as shown below. This will ensure that all the log files in the given folder (and hence all the application on your server) are being monitored.

However, you will need to reload Fail2ban after you deploy a new application on your server. You can do this easily, directly from the RunCloud dashboard, by creating a cron job with the appropriate command and running it manually when required.

If you want to have different settings for each web app, you can create a separate jail for each web application as shown below. Just make sure to specify the correct log files – and give each entry its own unique name (written in green).

Fail2ban Config file

After adding the necessary content, press Ctrl + O to save the file and press “Enter” to confirm it. Then press Ctrl + X to exit the text editor.

Creating a Fail2ban Filter

Once you have created a jail, you’ll need to create the corresponding filter that tells Fail2ban which clients to ban in case of a malicious login attempt. Run the following command to create a new filter named wordpress-auth:

nano /etc/fail2ban/filter.d/wordpress-auth.conf

Then paste the following text snippet to filter the failed login attempts on Nginx servers:

[Definition]
failregex = ^<HOST> .* "POST /wp-login.php HTTP.* 200
fail2ban jail file

For OpenLiteSpeed servers, the regex pattern is slightly different due to a difference in the log format.

[Definition]
failregex = .+ <HOST> .+POST \/wp-login\.php .*200

Once again, press Ctrl + O to save the file and press “Enter” to confirm it. Then press Ctrl + X to exit the text editor.

Testing The Fail2ban Filter (Optional)

If you are making changes to the production environment, it’s advisable to test out the settings before applying the new ones. You can use the following command to check if a filter is working correctly:

fail2ban-regex <path to log file> <path to filter>

For example, the full command would look something like this:

fail2ban-regex /home/runcloud/logs/apache2/app-schulist_access.log /etc/Fail2ban/filter.d/wordpress-auth.conf

In the above message, “Failregex: 8 total” shows that 8 entries in our log file matched with the filter that we provided. This means that our Regex filter is working correctly. If you want to see which log entries are being matched, you can include --print-all-matched flag before the path of the log file. For example:

fail2ban-regex --print-all-matched ./app-keeling_access.log /etc/fail2ban/filter.d/wordpress-auth.conf

In the above example, we can see that our regex pattern matched 22 entries in the given log file, and then listed out each entry which would have triggered a violation.

Apply the Changes to Fail2ban

To apply the new changes, you’ll need to restart the Fail2ban service. You can restart the service and check its status by running the following commands:

systemctl restart fail2ban
systemctl status fail2ban

In the above example, we didn’t encounter any errors, and Fail2ban was able to restart successfully. If you do face any errors, run the following command to troubleshoot the issue:

fail2ban-client -x start

Check Running Jails

Once you have restarted the service, you can check if your changes were applied correctly. Run the following command to see all of the jails currently configured on your server:

fail2ban-client status

Check Banned IPs

To check where the malicious IP addresses are being banned, try repeatedly logging in to your WordPress dashboard with incorrect credentials.

By default, if you make five unsuccessful login attempts within ten minutes, your IP address will be blocked for ten minutes. This setting can be configured in the /etc/Fail2ban/jail.local file.

To get detailed information about a particular jail, use the following command, (make sure to replace “wordpress-auths” with the name of your jail):

fail2ban-client status wordpress-auths

If you have multiple websites running on your server, the malicious actor will not be able to access any of them due to being listed as a banned IP address. This includes even those sites that are not being monitored by Fail2ban.

However, if you are using the Cloudflare proxy, this won’t work. Let’s see why.

Using Fail2ban With Cloudflare 

When you are using Cloudflare proxy to serve your web requests, the IP address used to connect to your server belongs to Cloudflare. Therefore, when you block the IP address after repeated failed login attempts, it blocks Cloudflare’s own IP address – which results in the following error:

Blocking Cloudflare’s IP address makes it think that the website has crashed – and all visitors from the blocked region will get a 520 error.

This is obviously unacceptable as blocking one IP address can make your website inaccessible to all users in a country. To fix this we will need to block the malicious traffic before it reaches Cloudflare.

Using Cloudflare Actions

To do this we will create a list of bad users who have too many failed login attempts, and then give this list to Cloudflare so that it can block the traffic. 

Go to your Cloudflare Dashboard and generate your API token.

Once you have opened the API token menu, scroll down to the “Global API Key” menu and view the token. Run the following command in your terminal to open the configuration file:

nano /etc/Fail2ban/action.d/cloudflare.conf

Scroll down to the bottom of the file using your keyboard arrows, and paste your API key as shown above.

Next, enter the email address you used to register your Cloudflare account, and then save and exit the file.

Having done that, you’ll need to edit the /etc/Fail2ban/jail.local file to make sure that it uses our newly created action. Scroll down to the jail corresponding to the website that uses the Cloudflare proxy to serve traffic, and add the following line to it:

action = cloudflare
    iptables-allports

Save and exit the file. After saving, restart the Fail2ban client to apply the changes. You can run the following command to restart the service, ban a dummy IP address, and check its status. Just make sure to replace “wordpress-auths” with the name of your jail:

systemctl restart fail2ban
fail2ban-client -v set wordpress-auths banip 22.22.22.22
fail2ban-client status wordpress-auths

Conclusion

Using Fail2ban with WordPress can greatly enhance the security of your website by protecting it against brute force attacks and other malicious activity. By following the steps outlined in this article, you can easily set up Fail2ban on your WordPress site and start enjoying the benefits of increased security.

If you’re tired of managing your own servers – you might want to check out RunCloud (yep, that’s us!). RunCloud is built for developers that want to focus on shipping great work, not on managing their infrastructure.

Discover what a painless server configuration feels like, allowing you to avoid having to spend hours figuring it out. Get started with RunCloud today, and get up and running in minutes.