I use fail2ban to protect my server. I additionally report the IP addresses to AbuseIPDB
But Forum spam is a big problem as anyone with a blog will know
I have Akismet configured, which pretty much stops it all from ever appearing, but that doesn’t stop them from repeatedly posting spam.
I looked at various plugins but couldn’t find one that did what I wanted – and I certainly wasn’t going to pay for one.
So I’ve built my own system. It has two parts
- Report spam from the blog to a file that can be read by fail2ban
- Fail2ban reads the file and firewalls the IP address and then reports it to AbuseIPDB
Report spam from the blog to a file that can be read by fail2ban
Create a file somewhere on your Blog where it can be accessed via a url. lets call it logspam.php. This code has been developed for a networked blog site so we have to do a bit of work to get the right table name. Also note that if this file isn’t in the root of your blog directory you’ll need to change the require_once value
<?php require_once __DIR__ . '/wp-load.php'; $prefix = $wpdb->prefix; $table = $prefix."comments"; $site_title = trim(htmlspecialchars_decode(get_bloginfo( 'name' )));$sql="select max(comment_id) maxid from $table where comment_approved='spam' and comment_karma=0"; $r = $wpdb->get_row($sql, ARRAY_A); $maxid=$r['maxid']; Print date("d/m/Y H:i:s")." Doing $site_title \n"; if (is_null($maxid)) { print date("d/m/Y H:i:s")." No Spam to process \n"; } else { $sql="select distinct comment_author_ip from $table where comment_approved='spam' and comment_karma=0"; $r2 = $wpdb->get_results($sql, ARRAY_A); openlog("Wordpress_spam", LOG_PID | LOG_PERROR | LOG_NDELAY, LOG_LOCAL0); foreach($r2 as $row){ $x=$row['comment_author_ip']; print date("d/m/Y H:i:s"). " reporting spam IP address $x \n"; syslog(LOG_WARNING, "WP_SPAM_IP $x "); } closelog(); $sql= "update $table set comment_karma=-1 where comment_approved='spam' and comment_karma=0 and comment_id <= $maxid"; $r3 = $wpdb->get_results($sql, ARRAY_A); } Print date("d/m/Y H:i:s")." Completed $site_title \n"; print "------------------------\n"; ?>
So this code checks to see if there are spammer IP addresses to report, gets a distinct list of them and reports them into the server syslog file with a line that looks like this
Jul 2 19:04:01 nyman WordPress_spam[2104013]: WP_SPAM_IP 78.46.108.24
Once it’s reported them it uses the old comment_karma field to mark that it’s reported it so it doesn’t get picked up if the code is run again before you’ve deleted the spam from the blog.
Then set up a cron job to call the reporting php file – you can capture the output of the cron call if you like – it produces something like this
------------------------ 02/07/2024 19:04:01 Doing Steve's Blog 02/07/2024 19:04:01 reporting spam IP address 103.76.117.236 02/07/2024 19:04:01 reporting spam IP address 94.103.188.103 02/07/2024 19:04:01 reporting spam IP address 78.46.108.24 02/07/2024 19:04:01 reporting spam IP address 23.81.64.213 02/07/2024 19:04:01 Completed Steve's Blog ------------------------
Fail2ban reads the file and firewalls the IP address and then reports it to AbuseIPDB
Create a new filter file called wordpress_spam.conf in the filter.d folder
[Definition] failregex = ^ .*. WP_SPAM_IP <ADDR>.$
Then create your new entry in jail.local file – this should all look pretty normal apart from the abuseipdb bit. Details on how to integrate AbuseIPDB with fail2ban have been written up by AbuseIPDB
[blog-spam] enabled = true port = http,https filter = wordpress_spam logpath = /var/log/syslog #bantime = 172800 maxretry = 1 action = %(action_mwl)s %(action_abuseipdb)s[abuseipdb_apikey="yourAPI key goes in here", abuseipdb_category="10",matches_comment="Forum Spam"]
then reload fail2ban using the fail2ban-client utility
When the cron runs the wget it writes to the syslog file which then gets picked up by fail2ban and you get emails
and reports in AbuseIPDB