Reporting to with Fail2ban

This is a guide to integrating Fail2ban and so that each time your system blocks an attacker, it also reports the incident to AbuseIPDB. This document is a work in progress. In lieu of registering on this wiki, please send comments and corrections to

Table of Contents

Background - Fail2ban and AbuseIPDB

Fail2ban is a utility that parses various system and software log files looking for signs of network abuse, and then firewalls out the offending IP addresses. It's becoming more common to crowdsource these incidents to centralized databases, so administrators can watch for patterns of abuse or pre-emptively block known malicious IPs. One of these efforts is AbuseIPDB, where attack information is compiled into reports like this one.

In this guide you'll learn how to configure Fail2ban so that it automatically reports attacks to the AbuseIPDB database. It's assumed that your system is already running Fail2ban.

Step 1: Register for AbuseIPDB

First, you'll need an API key from to make any reports there. Go to their website, register for an account, and obtain an API key. If you have a large footprint (multiple servers, well-known servers, etc.) and see >1000 Fail2ban incidents per day, you probably want to register for a webmaster account, as the daily API usage limit is higher. It's free to register either way.

Step 2: Create AbuseIPDB action configuration

Create a new file in your Fail2ban action.d directory, for example /etc/fail2ban/action.d/, and name it abuseipdb.conf. You MUST set your API key at the end of this configuration file.

# Fail2ban configuration file
# Action to report IP address to
# You must sign up to obtain an API key from
# Reporting an IP of abuse is a serious complaint. Make sure that it is
# serious. Fail2ban developers and network owners recommend you only use this
# action for:
#   * The recidive where the IP has been banned multiple times
#   * Where maxretry has been set quite high, beyond the normal user typing
#     password incorrectly.
#   * For filters that have a low likelihood of receiving human errors


# Option:  actionstart
# Notes.:  command executed once at the start of Fail2Ban.
# Values:  CMD
actionstart =

# Option:  actionstop
# Notes.:  command executed once at the end of Fail2Ban
# Values:  CMD
actionstop =

# Option:  actioncheck
# Notes.:  command executed once before each actionban command
# Values:  CMD
actioncheck =

# Option:  actionban
# Notes.:  command executed when banning an IP. Take care that the
#          command is executed with Fail2Ban user rights.
#          ** IMPORTANT! **
#          By default, this posts directly to AbuseIPDB's API, unfortunately
#          this results in a lot of backslashes/escapes appearing in the
#          reports. If you have your own web server with PHP available, you can
#          use my helper PHP script by commenting out the first #actionban
#          line below, uncommenting the second one, and pointing the URL at
#          wherever you install the helper script. For the PHP helper script, see
#          <>
#          --ciphers ecdhe_ecdsa_aes_256_sha is used to workaround a
#          "NSS error -12286" from curl as it attempts to connect using
#          SSLv3. See
# Tags:    See jail.conf(5) man page
# Values:  CMD
actionban = curl --fail --ciphers ecdhe_ecdsa_aes_256_sha --data 'key=<abuseipdb_apikey>' --data-urlencode 'comment=<matches>' --data 'ip=<ip>' --data 'category=<abuseipdb_category>' ""
#actionban = curl --fail --data 'key=<abuseipdb_apikey>' --data 'comment=<matches>' --data 'ip=<ip>' --data 'category=<abuseipdb_category>' ""

# Option:  actionunban
# Notes.:  command executed when unbanning an IP. Take care that the
#          command is executed with Fail2Ban user rights.
# Tags:    See jail.conf(5) man page
# Values:  CMD
actionunban =


# Option:  abuseipdb_apikey
# Notes    Your API key from
# Values:  STRING  Default: None


Step 3: Edit jail.local

Edit your fail2ban/jail.local file to define several new actions as below. These should go below the default action definitions (action_mw, etc.) that are already defined in the file.

# Actions to report to via API.
# See action.d/abuseipdb.conf
action_abuseipdb_fraud     = abuseipdb[abuseipdb_category="3"]
action_abuseipdb_ddos      = abuseipdb[abuseipdb_category="4"]
action_abuseipdb_proxy     = abuseipdb[abuseipdb_category="9"]
action_abuseipdb_forumspam = abuseipdb[abuseipdb_category="10"]
action_abuseipdb_emailspam = abuseipdb[abuseipdb_category="11"]
action_abuseipdb_blogspam  = abuseipdb[abuseipdb_category="12"]
action_abuseipdb_portscan  = abuseipdb[abuseipdb_category="14"]
action_abuseipdb_hack      = abuseipdb[abuseipdb_category="15"]
action_abuseipdb_sqlinject = abuseipdb[abuseipdb_category="16"]
action_abuseipdb_spoofing  = abuseipdb[abuseipdb_category="17"]
action_abuseipdb_sshbrute  = abuseipdb[abuseipdb_category="18"]

Now add these new actions to each jail wherever appropriate; a jail can have multiple actions, so just add the new ones to complement any existing actions. For example, to report SSH brute force attempts to AbuseIPDB, add action_abuseipd_sshbrute as an action for sshd:

enabled = true
port    = ssh
logpath = %(sshd_log)s
action  = %(action_mwl)s                   # <--- This was already set as an action
		  %(action_abuseipdb_sshbrute)s    # <--- Here is the new additional action

Restart Fail2ban (service fail2ban restart or perhaps fail2ban-client reload). It will take a few minutes to re-parse all the bans; check its log files to see whether or not it's working properly. Login to your account and see if any reports are being submitted.

Step 4: Optionally, install the PHP Helper Script

Reports posted directly from Fail2ban to will, as of this writing, contain a lot of backslash/escape characters. That's because, for security purposes, Fail2ban escapes the contents of the "matches" variable before passing it on to any action mechanism. In order to clean up my reports, as well as gain some control over filtering their contents, I created a helper script in PHP. Fail2ban posts to the PHP script instead of to AbuseIPDB. The helper script does some cleaning and then posts to the AbuseIPDB API.

If you have a web server (Apache, nginx, ...) capable of running PHP, you can place this helper script somewhere on your server, and then point Fail2ban's action.d/abuseipdb.conf (from Step 2) to it. I recommend restricting it via .htaccess or some other method so that only your server(s) can post to it. You should also edit in your server's own IP address, domain, your username, or anything else you don't want showing up in your reports.


/* Bail if nothing was posted to us */
if (!isset($_POST['ip'])) {

/* Remove backslashes and sensitive information from the report */
$_POST['comment'] = str_replace('\\', '', $_POST['comment']);
$_POST['comment'] = str_replace('', '[munged]', $_POST['comment']);
$_POST['comment'] = preg_replace('||mi', '[munged]', $_POST['comment']);

// If we're reporting spam, further munge any email addresses in the report
if ($_POST['category'] == 11) {
  $_POST['comment'] = str_replace('@', '[at]', $_POST['comment']);

/* Post report data to */
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, '');
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 30);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($_POST));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
// Required for connecting to a Cloudflare-hosted system...
curl_setopt($ch, CURLOPT_SSL_CIPHER_LIST, 'ecdhe_ecdsa_aes_128_sha');

$reply = curl_exec($ch);
$err = curl_error($ch);

/* Send a notification email */
mail ('', 
  '[abuseipdb] ' . $_POST['ip'], 
  "Err: {$err}\n\nServer reply: {$reply}\n\nIncoming _POST:\n\n" . var_export($_POST, true) . "\n\nOutgoing post data: " . http_build_query($_POST)

There are no comments on this page.
Valid XHTML :: Valid CSS: :: Powered by WikkaWiki