Any service that is exposed to the network is a potential target in this way. If you pay attention to application logs for these services, you will often see repeated, systematic login attempts that represent brute force attacks by users and bots alike.
A service called fail2ban can mitigate this problem by creating rules that can automatically alter your firewall configuration based on a predefined number of unsuccessful login attempts. This will allow your server to respond to illegitimate access attempts without intervention from you.
In this article, we'll cover how to install and use fail2ban on an Ubuntu 14.04 server.
Install Fail2Ban on Ubuntu 14.04The installation process for this tool is simple because the Ubuntu packaging team maintains a package in the default repositories.
First, we need to update our local package index and then we can use
aptto download and install the package:
sudo apt-get update sudo apt-get install fail2ban
As you can see, the installation is trivial. We can now begin configuring the utility for our own use.
Configure Fail2Ban with your Service SettingsThe fail2ban service keeps its configuration files in the
/etc/fail2bandirectory. There is a file with defaults called
Since this file can be modified by package upgrades, we should not edit this file in-place, but rather copy it so that we can make our changes safely.
We need to copy this to a file called
jail.localfor fail2ban to find it:
sudo cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local
Once the file is copied, we can open it for editing to see how everything works:
sudo nano /etc/fail2ban/jail.local
In this file, there are a few settings you may wish to adjust. The settings located under the
[DEFAULT]section will be applied to all services enabled for fail2ban that are not overridden in the service's own section.
ignoreip = 127.0.0.1/8
You can adjust the source addresses that fail2ban ignores by adding a value to the
ignoreipparameter. Currently, it is configured not ban any traffic coming from the local machine. You can add additional addresses to ignore by appending them to the end of the parameter, separated by a space.
bantime = 600
bantimeparameter sets length of time that a client will be banned when they have failed to authenticate correctly. This is measured in seconds. By default, this is set to 600 seconds, or 10 minutes.
findtime = 600 maxretry = 3
The next two parameters that you want to pay attention to are
maxretry. These work together to establish the conditions under which a client is found to be an illegitimate user that should be banned.
maxretryvariable sets the number of tries a client has to authenticate within a window of time defined by
findtime, before being banned. With the default settings, the fail2ban service will ban a client that unsuccessfully attempts to log in 3 times within a 10 minute window.
destemail = root@localhost sendername = Fail2Ban mta = sendmail
Some other settings you may wish to are the
mtasettings if you wish to configure email alerts. The
destemailparameter sets the email address that should receive ban messages. The
sendernamesets the value of the "From" field in the email. The
mtaparameter configures what mail service will be used to send mail.
action = $(action_)s
This parameter configures the action that fail2ban takes when it wants to institute a ban. The value
action_is defined in the file shortly before this parameter. The default action is to simply configure the firewall to reject traffic from the offending host until the ban time elapses.
If you would like to configure email alerts, you can change the value from
action_mw. If you want the email to include the relevant log lines, you can change it to
action_mwl. Make sure you have the appropriate mail settings configured if you choose to use mail alerts.
Individual Jail SettingsFinally, we get to the portion of the configuration file that deals with individual services. These are specified by the section headers, like
Each of these sections can be enabled by modifying or adding the
enabledline to be "true":
enabled = true
By default, the SSH service is enabled and all others are disabled.
These sections work by using the default values we defined above. If you want to override any values, you can do so under the service's section. If you want to use the defaults, you aren't required to add anything.
Some other settings that are set here are the
filterthat will be used to decide whether a line in a log indicates a failed authentication and the
logpathwhich tells fail2ban where the logs for that particular service are located.
filtervalue is actually a reference to a file located in the
/etc/fail2ban/filter.ddirectory, with its
.confextension removed. This file contains the regular expressions that determine whether a line in the log is bad. We won't be covering this file in-depth in this guide, because it is fairly complex and the predefined settings match appropriate lines well.
However, you can see what kind of filters are available by looking into that directory:
If you see a file that looks to be related to a service you are using, you should open it with a text editor. Most of the files are fairly well commented and you should be able to at least tell what type of condition the script was designed to guard against. Most of these filters have appropriate (disabled) sections in the
jail.localfile that we can enable if desired.
For instance, pretend that we are serving a website using nginx and realize that a password-protected portion of our site is getting slammed with login attempts. We can tell fail2ban to use the
nginx-http-auth.conffile to check for this condition within the
This is actually already set up in a section called
/etc/fail2ban/jail.localfile. We just need to flip the
enabledparameter to protect our service:
[nginx-http-auth] enabled = true filter = nginx-http-auth port = http,https logpath = /var/log/nginx/error.log
If you enable this, you'll want to restart your fail2ban service to make sure your rules are constructed correctly.
Putting It All TogetherNow that you understand the basic idea behind fail2ban, let's run through a basic setup.
We're going to configure a auto-banning policy for SSH and Nginx, just as we described above. We want fail2ban to email us when an IP is banned.
First, let's install all of the relevant software.
If you don't already have it, you'll need nginx, since we're going to be monitoring its logs, and you'll need sendmail to mail us notifications. We'll also grab
iptables-persistentto allow the server to automatically set up our firewall rules at boot. These can be acquired from Ubuntu's default repositories:
sudo apt-get update sudo apt-get install nginx sendmail iptables-persistent
Establish a Base FirewallWhen that is finished, we should implement a default firewall. You can learn how to configure an iptables firewall on Ubuntu 14.04 here. We are going to just create a basic firewall for this guide.
We're going to tell it to allow established connections, traffic generated by the server itself, traffic destined for our SSH and web server ports. We will drop all other traffic. We can set this basic firewall up by typing:
sudo iptables -A INPUT -i lo -j ACCEPT sudo iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT sudo iptables -A INPUT -p tcp --dport 22 -j ACCEPT sudo iptables -A INPUT -p tcp --dport 80 -j ACCEPT sudo iptables -A INPUT -j DROP
These commands will implement the above policy. We can see our current firewall rules by typing:
sudo iptables -S
-P INPUT ACCEPT -P FORWARD ACCEPT -P OUTPUT ACCEPT -N fail2ban-ssh -A INPUT -p tcp -m multiport --dports 22 -j fail2ban-ssh -A INPUT -i lo -j ACCEPT -A INPUT -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT -A INPUT -p tcp -m tcp --dport 22 -j ACCEPT -A INPUT -p tcp -m tcp --dport 80 -j ACCEPT -A INPUT -j DROP -A fail2ban-ssh -j RETURN
We have our default policy for each of our chains, and then the five rules that we just established. In red, we also have the default structure set up by fail2ban since it already implements SSH banning policies by default.
Adjusting the Fail2ban ConfigurationNow, we need to configure fail2ban using the settings we'd like. Open the
sudo nano /etc/fail2ban/jail.local
We can set a more severe ban time here. Under the default heading, change the
bantimesetting so that our service bans clients for half an hour:
bantime = 1800
We also need to configure our alert email information. First, find the
destemailparameter and put in the email address that you want to use to collect these messages:
destemail = firstname.lastname@example.org
You can set the
sendernameto something else if you'd like. It's useful to have a value that can be easily filtered using your mail service though, or else your regular inbox may get flooded with alerts if there are a lot of break in attempts from various places.
Moving down, we need to adjust the
actionparameter to one of the actions that sends us email. The choices are between
action_mwwhich institutes the ban and then emails us a "whois" report on the offending host, or
action_mwlwhich does the above, but also emails the relevant log lines.
We're going to chose
action_mwlbecause the log lines will help us troubleshoot and gather more information if there are issues:
action = %(action_mwl)s
Moving on to our SSH section, if we want to adjust the amount of unsuccessful attempts that should be allowed before a ban is established, you can edit the
maxretryentry. If you are using a port other than "22", you'll want to adjust the
portparameter appropriately. As we said before, this service is already enabled, so we don't need to modify that.
Next, search for the
nginx-http-authsection. Change the
enabledparameter to read "true":
[nginx-http-auth] enabled = true . . .
This should be all you have to do this section unless your web server is operating on non-standard ports or if you moved the default error log path.
Restarting the Fail2ban ServiceWhen you are finished, save and close the file.
Now, start or restart your fail2ban service. Sometimes, it's better to completely shut down the service and then start it again:
Now we can restart it by typing:
sudo service fail2ban stop
sudo service fail2ban start
It may take a few moments for all of your firewall rules to be populated. However, after a time, you can check the new rules by typing:
sudo iptables -S
-P INPUT ACCEPT -P FORWARD ACCEPT -P OUTPUT ACCEPT -N fail2ban-nginx-http-auth -N fail2ban-ssh -A INPUT -p tcp -m multiport --dports 80,443 -j fail2ban-nginx-http-auth -A INPUT -p tcp -m multiport --dports 22 -j fail2ban-ssh -A INPUT -i lo -j ACCEPT -A INPUT -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT -A INPUT -p tcp -m tcp --dport 22 -j ACCEPT -A INPUT -p tcp -m tcp --dport 80 -j ACCEPT -A INPUT -j DROP -A fail2ban-nginx-http-auth -j RETURN -A fail2ban-ssh -j RETURN
The lines in red are the ones that our fail2ban policies have created. Right now, they are just directing traffic to new, almost empty chains and then letting the traffic flow right back into the INPUT chain.
However, these new chains are where the banning rules will be added.
Testing the Banning PoliciesFrom another server, one that won't need to log into your fail2ban server with, we can test the rules by getting our second server banned.
After logging into your second server, try to SSH into the fail2ban server. You can try to connect using a non-existent name for instance:
Enter random characters into the password prompt. Repeat this a few times. At some point, the fail2ban server will stop responding with the
Permission deniedmessage. This signals that your second server has been banned from the fail2ban server.
On your fail2ban server, you can see the new rule by checking our iptables again:
sudo iptables -S
-P INPUT ACCEPT -P FORWARD ACCEPT -P OUTPUT ACCEPT -N fail2ban-nginx-http-auth -N fail2ban-ssh -A INPUT -p tcp -m multiport --dports 80,443 -j fail2ban-nginx-http-auth -A INPUT -p tcp -m multiport --dports 22 -j fail2ban-ssh -A INPUT -i lo -j ACCEPT -A INPUT -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT -A INPUT -p tcp -m tcp --dport 22 -j ACCEPT -A INPUT -p tcp -m tcp --dport 80 -j ACCEPT -A INPUT -j DROP -A fail2ban-nginx-http-auth -j RETURN -A fail2ban-ssh -s 126.96.36.199/32 -j REJECT --reject-with icmp-port-unreachable -A fail2ban-ssh -j RETURN
As you can see in the highlighted line, we have a new rule in our configuration which rejects traffic to the SSH port coming from our second server's IP address. You should have also gotten an email about the ban in the account you configured.