You Might Not Need Plugins: WordPress Login Security with Fail2Ban
Becoming an insufferable self-hosting zealot has its ups and downs. Dealing with all of the bad actors in the world is a complete downer. That is, until you deploy a solution and get that hit of dopamine as you watch your server's CPU usage take a nose dive back to normal levels.
First major issue I deal with was extremely rude AI crawlers. Then
damn near immediately after I migrated my WordPress sites over, it was brute
force attempts to wp-login.php.
If I had to guess, next will be some brand new AI company that can't seem to
properly vibe reading in robots.txt and actually respecting it.
The saga continues...
You know there's a plugin for that, right?
Oh, there are definitely plugins to help solve these security issues. Plugins to move your login files around to help obfuscate things. Plugins to handle limiting login attempts, handle velocity, and the like.
So many plugins, so little time. And you know there's some upgrade path in most of those plugins. These plugins are designed for folks that don't have direct server access, or simply don't know that most problems have already been solved with free software.
Old reliable technology to the rescue
If you don't already have fail2ban installed, I highly recommend that you do.
It's a great piece of software, scanning your log files for sketchy behavior,
and subsequently bans the offending parties. Out of the box, you get added
security for a myriad of services (assuming you have them installed), including
SSH.
To add additional filtering for WordPress troublemakers, you'll need to create a
new file in filter.d and jail.d. The former will contain some RegEx to
identify things, and the latter will define where to look and how to handle
things.
Filter and find 'em
In addition to wp-login.php I also include xmlrpc.php as it's used for those
nasty WordPress pingback DDoS attacks.
/etc/filter.d/wordpress.conf
[Definition]
failregex = ^ .* "(GET|POST) /+wp-login.php
^ .* "(GET|POST) /+xmlrpc.php
And lock 'em out
You'll want to tweak your logpath based on your setup, and can adjust the
values below that to fit your needs.
/etc/jail.d/wordpress.conf
[wordpress]
enabled = true
port = http,https
filter = wordpress
action = iptables-multiport[name=wordpress, port="http,https", protocol=tcp]
logpath = /var/log/nginx/*.access.log
maxretry = 12
findtime = 120
bantime = 120
Restart and check that it's working
Of course, you'll want to restart fail2ban. If you're using systemd, you can
do so as such: systemctl restart fail2ban.
To check that your wordpress.conf file is loaded up, you can run
fail2ban-client status which should list out any active jails you have.
If you happened to be in the middle of an attack, and your CPU was elevated because of it, within a few moments of enabling the new jail, you should see a fairly immediate improvement.