Fail2ban is one of the first pieces of software I install and configure on all of my servers and it does a great job of blocking malicious login attempts. With the built-in AbuseIPDB plugin for Fail2ban, you can automate reports to their database which helps users around the world keep track of what malicious IPs are doing! Note: This post will focus purely on ssh login attempts, though with a bit of modification, you can apply this to other Fail2ban jails with the same AbuseIPDB action. All you’d need to do is modify the report categories!
To start with, you’re going to need to install the software that will do the heavy lifting, Fail2ban. We’ll also install iptables/firewalld just in case it didn’t come by default.
Debian / Ubuntu
sudo apt update; sudo apt install fail2ban iptables
CentOS / RedHat
sudo yum update; sudo yum install epel-release;sudo yum install fail2ban firewalld fail2ban-firewalld
Rocky Linux / AlmaLinux / Fedora
sudo dnf update; sudo dnf install epel-release; sudo dnf install fail2ban firewalld fail2ban-firewalld
Creating an AbuseIPDB account
To be able to report your attempted intruders you will need an AbuseIPDB account. You can sign up on their website and the free/personal account is enough to get started.
Once registered, go to the report page where you’ll find a notice that you need to apply for reporting privileges before being able to submit reports against IPs. This process usually takes around a week (though I believe I waited for 2-3!) and once approved, you’ll receive an email notifying you that you’re able to contribute.
When your account is approved, the next step is to obtain an API key. Head to the Account > API page and locate the Create button on the right-hand side.
At this stage, you’re ready to move on to the next step and configure Fail2ban to use the AbuseIPDB module.
All of Fail2ban’s configuration files will be found in
/etc/fail2ban/ and whilst you’ll see the global configuration files by default, we’re going to use a new file at
/etc/fail2ban/jail.local as global configurations can be overwritten in updates and this will be a little cleaner.
Go ahead and create and open
/etc/fail2ban/jail.local with your chosen text editor and paste the following into it:
[sshd] enabled = true port = ssh maxretry = 3 findtime = 60d bantime = 7d ignoreip = 127.0.0.1 logpath = /var/log/auth.log action = %(action_)s %(action_abuseipdb)s[abuseipdb_apikey="YOUR-API-KEY", abuseipdb_category="18,22"]
You can (and will need to in some cases) configure some of these settings as required.
|maxretry||The number of attempts a malicious IP can make before being blocked.|
|findtime||The time Fail2ban will go back to look for the number of attempts specified in |
|bantime||The length of time an IP is blocked/banned.|
|ignoreip||Enter any IP addresses you wish to ignore here (such as localhost or your own IP)|
|logpath||The path to your SSHd log. By default on Debian, it is |
|action||This section specifies what actions Fail2ban will take if an IP meets the criteria above to be blocked. You will need to update |
Once you’ve set up the above, you’ll need to restart Fail2ban:
sudo systemctl restart fail2ban
Checking everything’s working
To check if everything is working, you can watch a live output of your logfile:
sudo tail -f /var/log/fail2ban.log
With the above, you should see Fail2ban working its magic, telling you when it detects a failed login and when it hits the threshold, it will tell you it has been banned. If you see
[sshd] Ban XX.XX.XX.XX in your log output, an IP has been banned and you can go back to your AbuseIPDB reports page to see if it was successfully submitted to their database.
One thing to bear in mind is that if you have a firewall that’s limited access to your ssh port already, this will be of little use as those connections won’t make it through. If you do have an open firewall for the port, the amount of malicious attempts you get will greatly depend on your service provider and what you’re running on the server. Certain providers’ IP ranges get targeted more frequently and if you’re running something that gets a lot of attention, it’s more likely to push your server up the list of targets. In the end though, these spammers will scan the entirety of the internet so they’ll reach you at some point!
Increasing your daily reporting limit
Depending on the number of requests you’re likely to be making, the default personal plan may not contain enough permitted daily requests through their API (1,000 per day by default). Luckily, they offer a number of ways to increase this with relative ease.
Verifying your website as a webmaster
If you want to raise your daily limit from 1,000 requests to 3,000, you can quickly and easily verify your website by uploading a verification file to the root directory of your website. This can be achieved via the Account > Webmasters section.
Showing a contributor badge on your website
If you want to take it one step further and increase your daily limit to 5,000 requests then you can show off your “Contributor badge” (configurable here) on your website. Mine can be seen below (I started reporting on the 10th July 2022!) and all of my public facing machines are currently connected using the above steps.
If you’ve reached this point and completed all of the above steps, congratulations! You’re now helping to report malicious users across the internet. These reports alone won’t fix the issue entirely though. As you’re only reporting these to AbuseIPDB, they’ll only be stored in their database and be used towards anyone making lookups. The positive is that many providers utilise the AbuseIPDB monitoring for their own IP ranges so any time an IP is reported, they’ll receive as notification and hopefully begin an investigation into what’s going on.
Being a WordPress user myself, I’m now looking into automating the reports of malicious login attempts. Do you already have something set up? Let me know in the comments or on Twitter and I’ll take a look. It would be even better to also automate the sending of abuse reports to the IP’s relevant owners but that’s a project for another day.