So your site has a login page? Ever wondered how many “people” are knocking on your door? When I looked at the login attempts on my SSH front door, just shortly after new server deployment, I decided to change doors (ports..). SSH login attempts are in the logs and are fun to look at. But how about failed WordPress logins?

First of all, they are not in the logs. But this can be fixed easily like this:

—> create directory mu-plugins
mkdir /var/www/<your site root>/wp-content/mu-plugins
—> create file wp-fail2ban.php in this directory
function admin_login_failed_403() {
    status_header( 403 );
add_action( 'wp_login_failed', 'admin_login_failed_403' );

A mu-plugin is a “Must Use” plugin and shows up as a separate category in the plugin overview.

WordPress failed logins are now logged as 403 POST errors in your web-server access.log. This might be fun to look at, but does not protect your site. This is where fail2ban comes into play. With the following fail2ban config (for nginx), access is blocked for 1 hour after 3 failed attempts.

—> create WordPress filter file for fail2ban
failregex = <HOST>.*POST.*(wp-login\.php).* 403
ignoreregex =

—> create WordPress jail file for fail2ban:
/etc/fail2ban/jail.d/wordpress.conf :
enabled = true
filter  = wordpress
logpath = /var/log/nginx/access.log
maxretry = 3
port = http,https
bantime = 1h

Of course, you still want to know who was knocking on your door, right? fail2ban uses a sqlite3 database to store ban history and the following query shows unique IP’s that have been banned.

—> list banned IPs from database
sqlite3 /var/lib/fail2ban/fail2ban.sqlite3 "select distinct ip,jail from bans"

Make sure to erase this info regularly to comply with regulations…

Leave a Reply

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

3 + 2 =