Ok, so probably the reason you’re here..is because you’re being swamped with failed login attempts against wp-login, or perhaps xmlrpc.
Not only are these really annoying, but also consume resources. I was recently working on a webserver with upwards of 40 different WordPress installations on it, to find that a massive amount of traffic each day was basically spurious or unwanted.
Fail2Ban works well as a log file analyser, which can then carry out actions based on parsing a given logfile. In this context, we want it to detect failed logins (and other nastiness), then firewall the culprit entirely. This way, the traffic doesn’t end up at the webserver, and doesn’t consume any more resources other than the kernel rejecting the TCP traffic. Nice!
This “How To” is specifically for CentOS 7, as the configuration procedure was somewhat awkward. So this not only (hopefully) server as a help for you…but also gives me something I can come back to later, when I’ve forgotten how to do it! 😉
What We’re Dealing With:
- CentOS 7 – with firewalld removed, as I don’t enjoy dozens of needless rules in my firewall. YMMV
- wp-fail2ban – for logging auth attempts to /var/log/messages (really important, its not in /var/log/auth.log)
- wp-cli – (optional really, but makes life easy if you already have ssh access)
Getting It Done..
Ok, first things first. Get logged into the server over ssh or whatever (sit at the machine if you wish), and install the required software. Fail2ban is in the epel repository, so we need that first (if not already installed)
sudo yum install epel-release
next up, grab fail2ban
sudo yum install fail2ban
next up, this article assumes you’re going to use wp-cli. If you’re not, then login to your wordpress install, head to plugins and install “wp-fail2ban”, then skip the next step. I’ve actually put together some wp-cli rpms but haven’t updated them for a bit. Check there first though, incase I got around to it 😉
curl -O https://raw.githubusercontent.com/wp-cli/builds/gh-pages/phar/wp-cli.phar chmod +x wp-cli.phar sudo mv wp-cli.phar /usr/local/bin/wp
Thats wp-cli installed. Next to use it to install the wp-fail2ban plugin. cd into your website’s root directory (usually cd /var/www/html/yourwebsite)
/usr/local/bin/wp plugin install wp-fail2ban /usr/local/bin/wp plugin activate wp-fail2ban
With a couple of green confirmation messages, you should now have wp-fail2ban installed, and fail2ban on the actual machine.
I don’t much like firewalld. I’m completely comfortable hand-writing iptables scripts, and as such don’t really enjoy the whole “wrapper” experience. Ultimately it aims to simplify the manipulation of firewall rules, personally I find it does the opposite (YMMV). If, like me..you don’t want to use firewalld, you will find that during the process of installing fail2ban, you got a cheeky package fail2ban-firewalld which drops a firewalld specific config file in /etc/fail2ban/jail.d. To get rid of this:
rpm -e --nodeps fail2ban-firewalld
for some reason, whoever packages fail2ban things that firewalld *is* a dependency thats needed. I disagree, but as such if you try and remove it with yum, it’ll try to remove fail2ban at the same time.
Time to test that wp-fail2ban is actually doing it’s thing. If you tail /var/log/messages, then try to login with false credentials, you should see something like:
# tail -f /var/log/messages Jul 10 17:35:10 localhost wordpress(yourwebsite.com): Authentication failure for admin from x.x.x.x
That being the case, wp-fail2ban is doing it’s job. Next up, configure fail2ban itself.
Firstly, you want to grab wordpress-soft.conf and wordpress-hard.conf from your plugin directory (webroot/wp-content/plugins/wp-fail2ban) and drop those into /etc/fail2ban/filter.d. To make things easier, you can use these (July 2016, these WILL change over time, best to grab the ones from the plugin)
# Fail2Ban configuration file [INCLUDES] before = common.conf [Definition] _daemon = (?:wordpress|wp) failregex = ^%(__prefix_line)sAuthentication failure for .* from <HOST>$ ^%(__prefix_line)sXML-RPC authentication failure from <HOST>$ ignoreregex =
# Fail2Ban configuration file [INCLUDES] before = common.conf [Definition] _daemon = (?:wordpress|wp) failregex = ^%(__prefix_line)sAuthentication attempt for unknown user .* from <HOST>( via XML-RPC)?$ ^%(__prefix_line)sBlocked authentication attempt for .* from <HOST>( via XML-RPC)?$ ^%(__prefix_line)sBlocked user enumeration attempt from <HOST>$ ^%(__prefix_line)sPingback error .* generated from <HOST>$ ignoreregex =
These files setup the filters so that when fail2ban is scanning /var/log/messages, it knows how to handle failed logins, pingback errors, etc.
Next up, configure the jail file. Try not to edit /etc/fail2ban/jail.conf, as this will change with updates. Instead, I chose to drop this in /etc/fail2ban/jail.d/00-dcr.conf
[DEFAULT] # Ban hosts for one hour: bantime = 3600 # Override /etc/fail2ban/jail.d/00-firewalld.conf: banaction = iptables-multiport [wordpress-hard] enabled = true filter = wordpress-hard logpath = /var/log/messages maxretry = 1 port = http,https [wordpress-soft] enabled = true filter = wordpress-soft logpath = /var/log/messages maxretry = 3 port = http,https
This enables the two filters, and sets them to the default ban action. Time to start fail2ban:
systemctl start fail2ban.service systemctl enable fail2ban.service
Now fail2ban should be running, you can confirm this with:
# fail2ban-client status Status |- Number of jail: 2 `- Jail list: wordpress-hard, wordpress-soft
this is showing us that not only is fail2ban running, but so are our two jails..win!
At this point, you should be set and running. Any failed login attempts will be logged in /var/log/messages, and any ban actions by fail2ban will be logged in /var/log/fail2ban.log
I’ve tried to make this as complete as possible, and easy to follow…I’d really appreciate the feedback (in the comments below) if you have any trouble, or want the howto adjusting for some reason (for example, if you REALLY want to use firewalld, or if you want a howto for CentOS 6 maybe)
Thanks for reading!