The Fail2ban website describes Fail2ban as:

Fail2ban scans log files (e.g. /var/log/apache/error_log) and bans IPs that show the malicious signs — too many password failures, seeking for exploits, etc. Generally Fail2Ban is then used to update firewall rules to reject the IP addresses for a specified amount of time, although any arbitrary other action (e.g. sending an email) could also be configured. Out of the box Fail2Ban comes with filters for various services (apache, courier, ssh, etc). Fail2Ban is able to reduce the rate of incorrect authentications attempts however it cannot eliminate the risk that weak authentication presents. Configure services to use only two factor or public/private authentication mechanisms if you really want to protect services.

For VPS and Dedicated Server users who want to use Fail2ban to work with CSF/LFD, the following can be done to install and configure Fail2ban to work along side CSF/LFD.

Installation

Fail2ban can be installed via YUM from either the epel-release or RPMForge repositories, depending on the version of CentOS.  For this guide, and since CentOS 6 is End-of-Life, we’ll focus on CentOS 7.

For CentOS 7, Fail2ban is in the epel-release repository. Try to run this first to see if this repo is already installed and setup:

yum -y install fail2ban

If not, then you’ll need to install that repository, run:

yum -y install epel-release

Now, you can perform the installation of Fail2ban.

yum -y install fail2ban

If you installed the epel-release repository, you’ll want to disable the it to put it back the way it was and to make sure that it’s not used for normal update processes. Skip this if you did not install the epel-release repository and running the ‘yum install’ command worked the first time. You’ll want to leave the server the way it was.

sed -i 's/enabled=1/enabled=0/' /etc/yum.repos.d/epel.repo

Updating Fail2ban

Since Fail2ban was installed using the RPMForge or epel-release repositories, and since those same repositories are now disabled (except in those cases for CentOS 7 systems), in order to update Fail2ban you’ll need to enable the repository to update Fail2ban specifically. Otherwise, Fail2ban will remain the version that was originally installed on the server.  Keep this in mind moving forward.

yum -y --enablerepo=epel-release update fail2ban

Configuration

By default, Fail2ban enables SSH protection (sshd). It’s one of the “jails” as shown in the original jail.conf file found below. However, this is not desirable, as CSF/LFD is already protecting SSH. It should be disabled or even removed. Fail2ban should only be used for services that CSF/LFD are not watching, such as WordPress or Exim.

That’s the key to using both Fail2ban and CSF/LFD together — don’t let them overlap.

Main jail.conf File

Rename the original Fail2ban configuration file, then make a new one with the changes.

mv /etc/fail2ban/jail.conf /etc/fail2ban/jail.conf.backup
vim /etc/fail2ban/jail.conf

Here’s a good default page.

# Fail2Ban jail specifications file

[DEFAULT]
ignoreip = 127.0.0.1/8
bantime = 21600
findtime = 600
maxretry = 10 

# pyinotify: requires pyinotify (a file alteration monitor) to be installed.
# If pyinotify is not installed, Fail2ban will use auto.
# gamin: requires Gamin (a file alteration monitor) to be installed.
# If Gamin is not installed, Fail2ban will use auto.
# polling: uses a polling algorithm which does not require external libraries.
# auto: will try to use the following backends, in order:
# pyinotify, gamin, polling.
backend = auto 

# "usedns" specifies if jails should trust hostnames in logs,
# warn when reverse DNS lookups are performed, or ignore all hostnames in logs
# yes: if a hostname is encountered, a reverse DNS lookup will be performed.
# warn: if a hostname is encountered, a reverse DNS lookup will be performed,
# but it will be logged as a warning.
# no: if a hostname is encountered, will not be used for banning,
# but it will be logged as info.
usedns = warn

destemail = [email protected]
banaction = iptables-multiport
mta = sendmail
protocol = tcp
chain = INPUT

# The simplest action to take: ban only
action_ = %(banaction)s[name=%(__name__)s, port="%(port)s", protocol="%(protocol)s", chain="%(chain)s"]
# ban & send an e-mail with whois report to the destemail.
action_mw = %(banaction)s[name=%(__name__)s, port="%(port)s", protocol="%(protocol)s", chain="%(chain)s"]
%(mta)s-whois[name=%(__name__)s, dest="%(destemail)s", protocol="%(protocol)s", chain="%(chain)s"]
# ban & send an e-mail with whois report and relevant log lines to the destemail.
action_mwl = %(banaction)s[name=%(__name__)s, port="%(port)s", protocol="%(protocol)s", chain="%(chain)s"]
%(mta)s-whois-lines[name=%(__name__)s, dest="%(destemail)s", logpath=%(logpath)s, chain="%(chain)s"] 

action = %(action_)s

[wordpress]
enabled = true
filter = wordpress
logpath = /var/log/messages
action = csf-ip-deny[name=wordpress]
         sendmail-whois[name=apache-auth]
port = http,https
maxretry = 10

[apache-tcpwrapper]
enabled = true
filter = apache-auth
action = csf-ip-deny[name=apache-auth]
         sendmail-whois[name=apache-auth]
logpath = /var/log/apache*/error_log
maxretry = 6

[apache-badbots]
enabled = true
filter = apache-badbots
action = csf-ip-deny[name=apache-badbots]
         sendmail-whois[name=apache-badbots]
sendmail-buffered[name=BadBots, lines=5, [email protected]]
logpath = /home/*/access-logs/*
bantime = 172800
maxretry = 1

# Ban attackers that try to use PHP's URL-fopen() functionality
# through GET/POST variables. - Experimental, with more than a year
# of usage in production environments.
[php-url-fopen]
enabled = true
port = http,https
filter = php-url-fopen
action = csf-ip-deny[name=php-url-fopen]
         sendmail-whois[name=php-url-fopen]
logpath = /home/*/access-logs/*
maxretry = 1

The default ban setting for Fail2ban is too short. It’s easy for malicious users to bypass Fail2ban by attempting logins at longer intervals. By default, Fail2ban monitors for only 10 minutes, and bans for only 10 minutes. Quite a few script kiddies set the retries for 11 minutes because of it.

The two settings that matter are bantime and findtime.

  • bantime: How long a ban lasts.
  • findtime: The is the window of time that Fail2ban tracks failed login attempts. If it’s only set to 600 (10 minutes), then all a malicious user has to do is wait 11 minutes.

A fairly aggressive setting of 24 hours (86400) — combine with 10 login attempts allowed — seems fine. Ban time should be just as aggressive — a minimum of 6 hours (21600).

It’s not likely that the customer will forget the password to their own sites 10 times. But even if they do, the ignoreip can be set to their home, office, or VPS/dedicated server IPs.

WordPress Conf File

Now, you need to create the wordpress.conf filter file, so:

vim /etc/fail2ban/filter.d/wordpress.conf

Add the following:

[INCLUDES]
# Read common prefixes. If any customizations available -- read them from common.local
before = common.conf

[Definition]
_daemon = wordpress

# Option:  failregex
# Notes.:  regex to match the password failures messages in the logfile. The
#          host must be matched by a group named "host". The tag "<HOST>" can
#          be used for standard IP/hostname matching and is only an alias for
#          (?:::f{4,6}:)?(?P<host>[\w\-.^_]+)
# Values:  TEXT
failregex = ^%(__prefix_line)sAuthentication failure for .* from <HOST>$

# Option:  ignoreregex
# Notes.:  regex to ignore. If this regex matches, the line is ignored.
# Values:  TEXT
ignoreregex =

Save and close that file.

CSF IP Deny Conf File

Now, you need to create an action file for Fail2ban to work with CSF:

vim /etc/fail2ban/action.d/csf-ip-deny.conf

Add the following:

[Definition]
actionstart =
actionstop =
actioncheck =
actionban = csf -d <ip> Added by Fail2Ban for <name>
actionunban = csf -dr <ip>
[Init]
name = default

Save and close this file.

Hosts Deny Conf File

[Optional]

Now you can to create the hostsdeny.conf file. This file can be used as a replacement of CSF IP Deny, but it’s preferred to work to with CSF, rather than against it. Oddly, this file is not provided by default and it’s unclear why.

wget -O /etc/fail2ban/action.d/hostsdeny.conf https://raw.githubusercontent.com/mikechau/fail2ban-configs/master/action.d/hostsdeny.conf

Disable the FirewallD Conf

Sometimes, Fail2ban might default or be set to use firewalld instead of iptables. Therefore, we need to disable the firewalld.conf file to ensure that it doesn’t conflict:

cd /etc/fail2ban/jail.d/; mv 00-firewalld.conf 00-firewalld.conf.disabled

You now have Fail2ban setup and configured to work with the default rule set.

Starting Fail2ban

After everything is set, it’s time to restart Fail2ban, as well as make it run at startup.

chkconfig fail2ban on

or

chkconfig -a fail2ban

Then to start the Fail2ban-client run:

service fail2ban-client start

That’s it. CSF/FLD and Fail2ban are installed, side-by-side, and should not conflict with each other.

Commands

For more information on the Fail2ban Server and Client, see the Fail2ban Usage site.

Start, stop, restart, status

fail2ban-client {start,stop,restart,status}

Reload configuration

fail2ban-client reload

Notes

In addition to editing the jail.conf file, the /etc/fail2ban/filter.d folder contains the configuration files (.conf files) needed for each filter. The jail.conf file only controls Fail2ban itself. These filters are outside the scope of this installation guide, but need to be mentioned. By default, the folder contains a number of files for Apache, Courier, Webmin, etc. Others are not included, and will need to be added.