Stop Brute Force WordPress Login Attempts with Fail2Ban

WordPress LogoWordPress is the most popular content management system for websites and as a result it attracts a lot of automated attempts at brute force login. Blocking such bots before they get very far is the topic of this post.

WordPress has a few plugins that prevent brute force login attempts. But if you have root access to the server you can employ a more efficient solution with the help of a simple plugin and the Fail2Ban utility.

If you have just one site you can install the plugin like any other, but for a multi site installation you want to install it as an mu plugin. A “Must Use” or mu plugin is installed in the [wordpress root]/wp-content/mu-plugins folder. It is always loaded and does not have to be enabled for each and every site.

The code for the plugin is given below. It is based on the WP Fail2Ban plugin.

class wp_fail2ban_special{
	const SYSLOG_FACILITY = LOG_LOCAL1;
 
	function __construct() {
		add_action( 'wp_login_failed', array( $this, 'log_failed_attempt' ) ); 
	}
 
	function log_failed_attempt( $username ) {
		openlog( 'wordpress(' . site_url() . ')', LOG_NDELAY|LOG_PID, self::SYSLOG_FACILITY );
		syslog( LOG_NOTICE, "Authentication failure for $username from {$_SERVER['REMOTE_ADDR']}" );
	}
}
 
new wp_fail2ban_special();

The plugin hooks into the wp_login_failed hook. It writes to the syslog using the syslog facility defined in the constant SYSLOG_FACILITY. Using a special syslog facility allows you to specify a separate log file for WordPress login failures.

Syslog redirect

To redirect to a dedicated log file you can create a simple configuration file with the following contents:

local1.* /var/log/wordpress_fail2ban.log

Where you place this file depends on your syslog daemon and Linux distribution. On Debian we have rsyslog so the file goes in /etc/rsyslog.d.

Be sure to restart syslog once you are done:

service rsyslog restart

Now that we have the logging sorted out let’s look at how to make use of it to stop brute force attempts.

vultr

Fail2Ban

Fail2Ban is a python application that specializes in parsing log files and performing actions based on what it finds. You can use it to ban IPs that are repeatedly trying to log into WordPress.

To install Fail2Ban on Debian you just do a:

apt-get install fail2ban

Fail2Ban has three types of configuration files:

  1. Filters: These are regular expressions that specify what parts of a log file fail2ban should pay attention to.
  2. Actions: These are things that fail2ban should do when it finds offending entries.
  3. Jails: These combine filters and actions.

The filter for parsing the WP log file is:

[Definition]
failregex = Authentication failure for .* <HOST>$ 
ignoreregex =

The <HOST> tag is what is used to match the IP address of the offending bot.

Put the above in a file named ‘apache-wp-login.conf’ in /etc/fail2ban/filter.d/.

We don’t need to create a separate action since the default action of banning via IPtables is fine for our purposes. So let’s look at customizing the jail file.

Fail2Ban’s default jail file is jail.conf and should not be edited. Instead create a separate jail file jail.local in /etc/fail2ban/:

[apache-wp-login]
enabled = true
port    = http,https
filter  = apache-wp-login
logpath = /var/log/wordpress_fail2ban.log

As you can see it is quite simple. We have specified the filter we configured earlier and the path to the log file.

By default Fail2Ban will ban IPs that make 3 or more failed attempts to login in 10 minutes for 10 minutes. You can customize this with the maxretry, findtime and bantime options:

maxretry = 5
findtime = 1200
bantime = 86400

All times are in seconds so in the above example fail2ban will ban IPs that have 5 or more login attempts in 20 minutes for 24 hours. If you want to ban the IPs forever you just need to enter a negative number for bantime.

Be sure to reload fail2ban once you are done configuring it:

service fail2ban reload

Wrapping it up

Leave this setup running for a day or so and then do:

iptables -nL

You should see the list of blocked IPs in the fail2ban-apache-wp-login chain:

Chain fail2ban-apache-wp-login (1 references)
target     prot opt source               destination         
DROP       all  --  85.223.208.26        0.0.0.0/0           
DROP       all  --  80.59.85.94          0.0.0.0/0     
...

Fail2Ban will automatically ban and unban IPs depending on how you configured it.

One other thing that you should do is setup logrotate for the wordpress_fail2ban.log file. This is left as an exercise for the reader. You might want to read my article on log rotation for help.

3 thoughts on “Stop Brute Force WordPress Login Attempts with Fail2Ban

  1. Just what I’ve been looking for. Nice solution especially when you’re running multiple websites on the same host. Just log the attempts of each site and add to the firewall 😉

Leave a Reply

Your email address will not be published. Required fields are marked *