Fail2ban + UFW not blocking IPs on ubuntu 15.04

Posted December 2, 2015 25.3k views

Hi, I’ve got a few Ubuntu 15.04 droplets running Fail2ban + UFW (+ IPtables fwiw). I’ve set the servers up according to the various 14.04 tutorials on DO:
initial server setup steps
setting up ufw
setting up fail2ban
I even followed the directions to setup repeat offender from wireflare as well as recidive (a bit of paranoia admittedly).

I should probably note that these droplets were originally 14.10 that was upgraded to 15.04 in Aug but all of them are running the same kernel 3.19.0-30-generic per DO dashboard. I made sure that each of them were running the right kernel version since iptables wasn’t working on some because of kernel mismatching.

My droplets running 14.04 my setup works great AFAIK…

I’ve set up my UFW rules to REJECT certain annoying IP addresses (e.g. and sudo iptables -S and -L both reflect these particular addresses as being blocked/rejected. I also have UFW reject all incoming requests except to certain ports (http, etc). And I’ve got PermitRootLogin off as well. The only way to log into our servers are via key access (on port 22, but that isn’t the issue).

However, I’ve noticed that f2b continually sends out emails saying those particular IP addresses are still attempting to SSH in. My jail.local has the default SSH jail settings, but that points to port=ssh (which is 22). The brute force attempts from these IPs hit various other ports, like port 23825.

Here’s my current setup. Snippet of UFW

Logging: on (low)
Default: deny (incoming), allow (outgoing), disabled (routed)
New profiles: skip

To                         Action      From
--                         ------      ----
Anywhere                   REJECT IN
Anywhere                   REJECT IN
Anywhere                   REJECT IN
Anywhere                   REJECT IN

Snippet of corresponding IPtables

-A f2b-recidive -s -j REJECT --reject-with icmp-port-unreachable
-A f2b-recidive -s -j REJECT --reject-with icmp-port-unreachable
-A ufw-user-input -s -j REJECT --reject-with icmp-port-unreachable
-A ufw-user-input -s -j REJECT --reject-with icmp-port-unreachable

And my jail.local


enabled  = true
port     = ssh
filter   = sshd
logpath  = /var/log/auth.log
maxretry = 3

(Tho I tried to change the SSH jail to this, unsure if it’s properly configured or working or whatnot – I assume it’s not because I still get the emails re: these particular IPs)


enabled  = true
filter   = sshd
action   = iptables-allports[name=ssh,protocol=tcp]
           sendmail-whois-lines[name=SSH, logpath=/var/log/fail2ban.log]
logpath  = /var/log/auth.log
maxretry = 3

I’ve a few questions regarding all of this.
1 – Why isn’t UFW / IPTables blocking these IP addresses? (Seriously, this is the biggest Q)
2 – How do I set up fail2ban’s SSH jail to also dismiss all SSH attempts thru other ports?
3 – I’m no sysadmin but isn’t UFW/iptables supposed to be blocking those IP addresses even prior to f2b reporting and banning? After all, the packets need to hit the server, go thru the firewall, then get an entry logged into the system for f2b to read and action against.

Any help would be greatly appreciated.

  • Hi,

    Why isn’t UFW / IPTables blocking these IP addresses? (Seriously, this is the biggest Q)
    not sure, but i think you need to change the port on jail.local to something like:

    enabled  = true
    port     = 1234
    filter   = sshd
    logpath  = /var/log/auth.log
    maxretry = 3

    and at the beginning of jail.local set:

    banaction = iptables-allports 

    let me know,
    hope this help.

  • hi @theMiddle

    I have banaction = iptables-allports already set, thanks!

    The problem with setting port = 1234 in the SSH jail is that the jail would only block entries to port 1234. It’s why I tried to go the route of removing the port statement and switching it to an action statement to block all the ports from any sort of SSH'ing.

    Otherwise is there an option to do port = 1-xxxxx ? I can’t seem to find any indication of that in the docs (and they admittedly seem a bit outdated) – only port = ssh, http, https: y'know, comma separated values.

  • Hi @risarisa

    i don’t know if is possible to do it with fail2ban :( sorry. For this kind of issue i’ve write a bash script that do the same work by parsing the auth.log (or any other log file) and dinamically add iptables rules. Parsing sshd logs (or auth and authpriv syslog facility) should solve your problem with multiple ssh port. You can find it here:

    An example:

    Download the script

    cd /usr/local/bin
    git clone

    Run log2iptables

    cd /usr/local/bin/log2iptables
    ./ -f /var/log/auth.log -x 1 -r 'sshd.*Failed.password.*from.([0-9\.]+)' -p 1 -l 5

    this will insert a iptables rule that drop all IPs that fail password more than 5 times. You can test it, without insert any rules, removing the -x 1 parameter. You can insert it in crontab and check your auth.log every n time, and receive a notify each time it add a new iptables rule.

    hope this help

  • Holy moly @theMiddle ! This is amazing! I’m going to try this on one of my servers. Hopefully my IPtables/ufw actually does its job and blocks stuff.

    Thanks again for the help!

These answers are provided by our Community. If you find them useful, show some love by clicking the heart. If you run into issues leave a comment, or add your own answer to help others.

Submit an Answer
2 answers


The issue is that Fail2Ban uses iptables, not ufw (even if ufw is a wrapper for iptables). The order by which the rules are implemented is key as that’s the order they’ll be executed in. Any allow rule set by iptables that get’s executed before your ufw rules means that your ufw deny won’t do anything as the allow is already allowing the connection. If a block follows on down the list, that doesn’t matter either; the allow is still there before the deny or block.

To get around this, you can setup customized definitions for Fail2Ban. This is a more restrictive setup. It will ban any IP that is tagged with UFW BLOCK in the ufw log.

You can do this by creating a file:


and to it add:

actionstart =
actionstop =
actioncheck =
actionban = ufw insert 1 deny in from <ip>
actionunban = ufw delete deny in from <ip>

What the insert 1 does is ensure that this rule is added to the top.

Now we need to create a filter file to tell fail2ban when to ban a user. We can create a file named:


and to it add:

failregex = UFW BLOCK.* SRC=<HOST>
ignoreregex =

If you look at /var/log/ufw.log, you’ll see where this regex comes in to play. If you do not have a log file, try running ufw logging low or ufw logging medium. It seems in many cases, logging is either turned off by default or it’s on and the log file is never created. Running either of those commands will create that file.

Finally, we need to modify the jail.conf file and add:

enabled  = true
filter   = ufwscanban
logpath  = /var/log/ufw.log
action   = ufw
maxretry = 5

This limits the maxrety attempts to 5. If this limit is exceeded, the actionban action is taken. You’ll notice that the filter is simply set to the name of the filter file we created, without the .conf extension and that we’re using /var/log/ufw.log as the logpath, which in this case, is the file we’ll be scanning (which is why it’s important to run the commands mentioned above to ensure that this file is created).

Of course, this is just an example. And as above, it’s not port specific. This will block any IP on any port that exceeds the maximums.

As a side note, if you’re having complications with ufw + fail2ban beyond the above, you may want to look at Config Server Firewall (CSF) which has it’s own Login Failure Detection (LFD). It’s commonly used on cPanel/WHM servers, though it can be used effectively as a standalone (with options available from the CLI).

…of course, you’d want to make sure that Fail2Ban & UFW are disabled fully before enabling this. I can say, from experience, that it works and in most cases, it works without any issues (and it bans!). Just make sure you whitelist your IP(’s).

  • Cool, wow thanks @jtittle ! So if the IPTables are read from top to bottom, then f2b bans being at the top occur prior to ufw – this makes sense. If this is the case, is it almost unnecessary to have both running at the same time? ....Does this equate to a longer wait on SSH'ing in? I have my IP whitelisted in both ufw and f2b, but it takes a good 10-20s before I can properly SSH in, like my IP is going thru every single iptable rule there is.

    And if f2b rules are read before ufw, then the entries in ufw.log would be the ones f2b didn’t catch… would it then make sense to keep the action file and switch the filter file to a general one (like /var/log/auth.log)? Thinking out loud but, as I’m understanding it, it’d then stick those UFW denied IPs pulled from auth.log at the top of iptables. Is this thinking correct?

    Thanks for your very incredibly detailed breakdown of the steps.

The answer by @jtittle1 above is great! Here are the last details you should know:

  • UFW might even still register the blocked attempts in /var/log/ufw.log after all of this setup. The trick is to take a look at your rules with iptables -L -n and see where the ufw and fail2ban chains exist (also the DOCKER chains if you are using swarm). If you want to block absolutely everything you need to add rules to your first CHAIN. Here is an example stopping attacks from hitting the UFW logs after they have been banned. Notice the match-set badbots src rule… which is explained below.
Chain INPUT (policy DROP)
target     prot opt source               destination
DROP       all  --              match-set badbots src
ufw-before-logging-input  all  --  
ufw-before-input  all  --  
ufw-after-input  all  --  
ufw-after-logging-input  all  --  
ufw-reject-input  all  --  
ufw-track-input  all  --  
  • IPTABLES will start to slow down after many thousands of rules are added to the chains, and it will fall off a cliff (in terms of performance) at some point after that. There is a simple solution called IPSET that is a plugin to IPTABLES. Instead of pushing thousands of IP addresses into the IPTABLES chain, you can just add them to an IPSET ip hash, which uses a bintree lookup mechanism with average O(log n) search/insert/delete time complexity (Excellent!) , vs the IPTABLES O(n) time complexity (Fair). Take a look at the Big-O Complexity Chart to understand the performance difference. Here’s a quick-start guide to add IPSET to the setup that @jtittle1 gave above while being 100% certain the IPs are blocked from your entire server:
  1. apt-get install ipset
  2. ipset -exist create badbots iphash
  3. iptables -I INPUT 1 -m set --match-set badbots src -j DROP

Then change /etc/fail2ban/action.d/ufw.conf to this:


actionstart =
actionstop =
actioncheck =
actionban = ipset -exist add badbots <ip>
actionunban = ipset -exist del badbots <ip>

NOTICE: one IPSET hash can hold up to 65536 IPv4 addresses. You can check how many IPs have been added to your hash with ipset list badbots | wc -l. If you start to approach 65k at some point just create a second IPSET hash and begin using it:

  1. ipset -exist create badbots2 iphash
  2. iptables -I INPUT 1 -m set --match-set badbots2 src -j DROP

Then edit ufw.conf

actionban = ipset -exist add badbots2 <ip>
actionunban = ipset -exist del badbots2 <ip>