skip to content

System: Using a Fail2Ban Jail to Whitelist a User

 Tweet Share0 Tweets

Let's suppose we have a directory /login/ which our users need to connect to using Basic Auth or similar authentication. Most CMS's have an address of this type, and they tend to attract a lot of attention from botnets and other automated scripts.

Leaving aside for now other security options (using a different port, certificate based authentication, port knocking, etc.) let's look at how we can aggressively ban failed login attempts while limiting the chances of also blocking a valid user for mis-typing their login because CAPS was on.

The following has been tested in Fail2Ban 0.9.3. The same approach will also work in 0.8.13, but trying to reload the whitelist jail will hang the process, requiring a messy KILL and restart, so it's not advised. See below for upgrade instructions.

Blocking with Fail2Ban

First the simple part. You should be familiar by now with the basic Fail2Ban configuration for setting up a jail/filter. If not, there are plenty of examples included with a default installation.

First we define the jail apache-loginfail as follows:


[apache-loginfail] enabled = true port = http,https logpath = %(apache_access_log)s maxretry = 5 bantime = 172800

Using Debian, apache_access_log maps to /var/log/apache2/*access.log. Other platforms may use a different path, and earlier versions of Fail2Ban need an explicit path here.

The regular expressions for detecting a failed login go into the filters directory:


[INCLUDES] before = apache-common.conf [Definition] failregex = ^<HOST> .* "(GET|POST) /login/.*" (401|403|404) ignoreregex =

So we're going to catch any requests for the /login/ directory that result in a 40* error, and ban them after five (5) attempts and for a period of 48 hours.

At this point you should run some tests to verify that the jail is set up correctly before you activate it - most easily by just restarting the Fail2Ban daemon:

# systemctl restart fail2ban.service

or more properly using the built-in commands:

# fail2ban-client add apache-loginfail auto # fail2ban-client start apache-loginfail

Make sure that the address you want to protect does not appear on any public pages as a clickable link. If it does, use rel="nofollow" on the link and add /login/ to your robots.txt file. Otherwise you will just end up blocking harmless spiders.

Setting up a whitelist action

Everything to this point is vanilla Fail2Ban. What we want to do next is a bit more complicated.

We know we can 'whitelist' ip addresses using the Fail2Ban configuration files:

ignoreip = 192.168.0

Or dynamically using the command-line tool:

# fail2ban-client set apache-loginfail addignoreip

But what we want to do is to automatically add users to the whitelist immediately after they perform a successful login. That will protect them from being banned until/unless the whitelisting as expired.

This requires three (3) separate files:

1. Jail definition: /etc/fail2ban/jail.d/apache-whitelist.conf

[apache-whitelist] enabled = true port = http,https logpath = %(apache_access_log)s action = ignoreip[name=apache-loginfail] maxretry = 1 bantime = -1

2. Filter definition: /etc/fail2ban/filter.d/apache-whitelist.conf

[Definition] failregex = ^<HOST> .* "GET /login/.*" 200 ignoreregex =

3. Action definition: /etc/fail2ban/action.d/ignoreip.conf

[Definition] actionstart = actionstop = actioncheck = iptables -n -L <chain> | grep -q 'f2b-<name>[ \t]' actionban = fail2ban-client set <name> addignoreip <ip> actionunban = fail2ban-client set <name> delignoreip <ip> [Init] name = default chain = INPUT

What's new in the above jail is the action setting. Instead of using one of the built-in actions to manipulate iptables rules we've created a new action ignoreip which instead runs Fail2Ban client commands. Actions can be used to run just about anything from sending emails to restarting services.

You can think of the ignoreip action as a function, taking the name of a jail as the parameter. When the filter is triggered by a successful login (any request to the secure directory returning 200 OK) the ignoreip action is called with the 'name' variable set to 'apache-loginfail'.

What happens next should be obvious. Instead of being added to an iptables chain, the captured ip address will instead be added to the 'ignoreip' list for the 'apache-loginfail' jail. And because we set 'bantime' to '-1' it will stay there indefinitely so the user can no longer run afoul of the failed login jail.

If you want to be notified when anyone is whitelisted, check out the sendmail-whois action. Otherwise you can follow the logs in /var/log/fail2ban.log, or use the command line:

# fail2ban-client get apache-loginfail ignoreip

Our actual settings are as usual a bit more complex, and we don't monitor the access log/s directly, but via an rsyslog filter. More on that later.

If you get this working on your own server, or have questions, get in touch using our Feedback Form.

Installing Fail2Ban 0.9 from 'stretch'

If you're running Debian stable and want to install a newer version of Fail2Ban from testing, you first need to include the 'testing' archived in you apt-sources:


deb stretch main deb-src stretch main

Then pin the Fail2Ban package so it prefers the 'testing' version:


Package: * Pin: release o=Debian,a=testing Pin-Priority: -1 Package: fail2ban Pin: release o=Debian,a=testing Pin-Priority: 900

And finally run the installer:

# apt-get -u install fail2ban

Be aware that, if you're not doing a clean install, upgrading to Fail2Ban 0.9 involves changes to existing jail definitions as well as to the Fail2Ban file structure.

< System

Send a message to The Art of Web:

used only for us to reply, and to display your gravatar.

<- copy the digits from the image into this box

press <Esc> or click outside this box to close

User Comments

Post your comment or question

30 June, 2016

Your whitelist solutions saved me a ton of time.
The only thing I do not understand is the "actioncheck"
Why are you checking against iptables?

From what I understand the 'actioncheck' command is run by Fail2Ban before executing 'actionban' or 'actionnban'. In this case it confirms that the chain we're targetting exists in iptables.

If you're using a back-end other than iptables this will need changing.

19 October, 2015

Upon restarting fail2ban 9.1 on CentOS 6.4:

ERROR fail2ban-client set jail delignoreip XX.XXX.XX.XX -- stderr: 'ERROR Failed to access socket path: /var/run/fail2ban/fail2ban.sock. Is fail2ban running?\n'

This may have been fixed in 0.9.3. (Release notes)

Can anyone confirm?