Tutorial

How To Protect SSH With Fail2Ban on CentOS 7

How To Protect SSH With Fail2Ban on CentOS 7
Not using CentOS 7?Choose a different version or distribution.
CentOS 7

Introduction

While connecting to your server through SSH can be very secure, the SSH daemon itself is a service that must be exposed to the Internet to function properly. This comes with some inherent risk and offers a vector of attack for would-be assailants.

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 automatically alter your iptables 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 guide, we’ll cover how to install and use Fail2ban on a CentOS 7 server.

Install Fail2ban on CentOS 7

While Fail2ban is not available in the official CentOS package repository, it is packaged for the EPEL project. EPEL, standing for Extra Packages for Enterprise Linux, can be installed with a release package that is available from CentOS:

  1. sudo yum install epel-release

You will be prompted to continue—press y, followed by Enter:

yum prompt
Transaction Summary ============================================================================ Install 1 Package Total download size: 14 k Installed size: 24 k Is this ok [y/d/N]: y

Now we should be able to install the fail2ban package:

  1. sudo yum install fail2ban

Again, press y and Enter when prompted to continue.

Once the installation has finished, use systemctl to enable the fail2ban service:

  1. sudo systemctl enable fail2ban

Configure Local Settings

The Fail2ban service keeps its configuration files in the /etc/fail2ban directory. There, you can find a file with default values called jail.conf. Since this file may be overwritten by package upgrades, we shouldn’t edit it in-place. Instead, we’ll write a new file called jail.local. Any values defined in jail.local will override those in jail.conf.

jail.conf contains a [DEFAULT] section, followed by sections for individual services. jail.local may override any of these values. Additionally, files in /etc/fail2ban/jail.d/ can be used to override settings in both of these files. Files are applied in the following order:

  1. /etc/fail2ban/jail.conf
  2. /etc/fail2ban/jail.d/*.conf, alphabetically
  3. /etc/fail2ban/jail.local
  4. /etc/fail2ban/jail.d/*.local, alphabetically

Any file may contain a [DEFAULT] section, executed first, and may also contain sections for individual jails. The last vavalue set for a given parameter takes precedence.

Let’s begin by writing a very simple version of jail.local. Open a new file using nano (or your editor of choice):

  1. sudo nano /etc/fail2ban/jail.local

Paste the following:

/etc/fail2ban/jail.local
[DEFAULT]
# Ban hosts for one hour:
bantime = 3600

# Override /etc/fail2ban/jail.d/00-firewalld.conf:
banaction = iptables-multiport

[sshd]
enabled = true

This overrides three settings: It sets a new default bantime for all services, makes sure we’re using iptables for firewall configuration, and enables the sshd jail.

Exit and save the new file (in nano, press Ctrl-X to exit, y to save, and Enter to confirm the filename). Now we can restart the fail2ban service using systemctl:

  1. sudo systemctl restart fail2ban

The systemctl command should finish without any output. In order to check that the service is running, we can use fail2ban-client:

  1. sudo fail2ban-client status
Output
Status |- Number of jail: 1 `- Jail list: sshd

You can also get more detailed information about a specific jail:

  1. sudo fail2ban-client status sshd

Explore Available Settings

The version of jail.local we defined above is a good start, but you may want to adjust a number of other settings. Open jail.conf, and we’ll examine some of the defaults. If you decide to change any of these values, remember that they should be copied to the appropriate section of jail.local and adjusted there, rather than modified in-place.

  1. sudo nano /etc/fail2ban/jail.conf

Default Settings for All Jails

First, scroll through the [DEFAULT] section.

ignoreip = 127.0.0.1/8

You can adjust the source addresses that Fail2ban ignores by adding a value to the ignoreip parameter. Currently, it is configured not to ban any traffic coming from the local machine. You can include additional addresses to ignore by appending them to the end of the parameter, separated by a space.

bantime = 600

The bantime parameter sets the 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 findtime and maxretry. These work together to establish the conditions under which a client should be banned.

The maxretry variable 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, Fail2ban will ban a client that unsuccessfully attempts to log in 3 times within a 10 minute window.

destemail = root@localhost
sendername = Fail2Ban
mta = sendmail

If you wish to configure email alerts, you may need to override the destemail, sendername, and mta settings. The destemail parameter sets the email address that should receive ban messages. The sendername sets the value of the “From” field in the email. The mta parameter 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 override this value from action_ to action_mw. If you want the email to include the relevant log lines, you can change it to action_mwl. You’ll want to make sure you have the appropriate mail settings configured if you choose to use mail alerts.

Settings for Individual Jails

After [DEFAULT], we’ll encounter sections configuring individual jails for different services. These will typically include a port to be banned and a logpath to monitor for malicious access attempts. For example, the SSH jail we already enabled in jail.local has the following settings:

/etc/fail2ban/jail.local
[sshd]

port    = ssh
logpath = %(sshd_log)s

In this case, ssh is a pre-defined variable for the standard SSH port, and %(sshd_log)s uses a value defined elsewhere in Fail2ban’s standard configuration (this helps keep jail.conf portable between different operating systems).

Another setting you may encounter is the filter that will be used to decide whether a line in a log indicates a failed authentication.

The filter value is actually a reference to a file located in the /etc/fail2ban/filter.d directory, with its .conf extension 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:

  1. ls /etc/fail2ban/filter.d

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 tell what type of condition the script was designed to guard against. Most of these filters have appropriate (disabled) sections in jail.conf that we can enable in jail.local 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.conf file to check for this condition within the /var/log/nginx/error.log file.

This is actually already set up in a section called [nginx-http-auth] in our /etc/fail2ban/jail.conf file. We would just need to add an enabled parameter for the nginx-http-auth jail to jail.local:

/etc/fail2ban/jail.local
[DEFAULT]
# Ban hosts for one hour:
bantime = 3600

# Override /etc/fail2ban/jail.d/00-firewalld.conf:
banaction = iptables-multiport

[sshd]
enabled = true

[nginx-http-auth]
enabled = true

And restart the fail2ban service:

  1. sudo systemctl restart fail2ban

Monitor Fail2ban Logs and Firewall Configuration

It’s important to know that a service like Fail2ban is working as-intended. Start by using systemctl to check the status of the service:

  1. sudo systemctl status fail2ban

If something seems amiss here, you can troubleshoot by checking logs for the fail2ban unit since the last boot:

  1. sudo journalctl -b -u fail2ban

Next, use fail2ban-client to query the overall status of fail2ban-server, or any individual jail:

  1. sudo fail2ban-client status
  2. sudo fail2ban-client status jail_name

Follow Fail2ban’s log for a record of recent actions (press Ctrl-C to exit):

  1. sudo tail -F /var/log/fail2ban.log

List the current rules configured for iptables:

  1. sudo iptables -L

Show iptables rules in a format that reflects the commands necessary to enable each rule:

  1. sudo iptables -S

Conclusion

You should now be able to configure some basic banning policies for your services. Fail2ban is very easy to set up, and is a great way to protect any kind of service that uses authentication.

If you want to learn more about how Fail2ban works, you can check out our tutorial on how fail2ban rules and files work.

Thanks for learning with the DigitalOcean Community. Check out our offerings for compute, storage, networking, and managed databases.

Learn more about our products

About the author(s)

Brennen Bearnes
Brennen Bearnes
See author profile
Category:
Tutorial

Still looking for an answer?

Ask a questionSearch for more help

Was this helpful?
 
10 Comments
Leave a comment...

This textbox defaults to using Markdown to format your answer.

You can type !ref in this text area to quickly search our full set of tutorials, documentation & marketplace offerings and insert the link!

Fail2ban is a nice one, but what is the difference of this and Denyhosts?

Brennen Bearnes
DigitalOcean Employee
DigitalOcean Employee badge
January 28, 2016

I haven’t personally used DenyHosts. It looks like it takes a similar approach, although from documentation I’d guess that the implementation is less generalized (i.e., Fail2ban works with many different services in addition to SSH, and can trigger a wide range of actions). It also seems like DenyHosts has a built-in data-sharing mechanism, so that you can block hosts already blocked by other users. That might be worth investigating, but I’d hesitate to make any recommendations without actually trying out the software.

Thank you.

Thanks. I’m currently using iptables with hitcount and connlimit, but it’s nice to know alternatives. Maybe someday I will switch to firewalld.

This comment has been deleted

    This comment has been deleted

      Sorry for the noobish question, but does banaction = iptables-multiport tell it to use iptables instead of firewalld? If it does, how can i use firewalld instead? Thanks ahead!

      Brennen Bearnes
      DigitalOcean Employee
      DigitalOcean Employee badge
      February 4, 2016

      It does, yeah. In fact, I’m afraid I don’t have a great answer for this one at the moment. In theory, all you’d have to do is remove that line. By default, /etc/fail2ban/jail.d/00-firewalld.conf looks like this:

      /etc/fail2ban/jail.d/00-firewalld.conf
      # This file is part of the fail2ban-firewalld package to configure the use of
      # the firewalld actions as the default actions.  You can remove this package
      # (along with the empty fail2ban meta-package) if you do not use firewalld
      [DEFAULT]
      banaction = firewallcmd-ipset
      

      …and that gets executed before jail.local.

      Unfortunately, I wasn’t able to get firewalld working (with Fail2ban) at all.

      Do I need to install iptables for this to work properly, and stop firewalld? I have seen a package called iptables already installed with centos7, that is the reason Im asking… and thanks for the help!

      From my experience, firewalld is the default application in CentOS 7 and so you need to stop it and install iptables. In my notes I have:

      systemctl status firewalld # current status of firewalld
      systemctl mask firewalld  # prevent it from starting. mask is more powerful than disable
      systemctl stop firewalld
      yum install iptables-services
      systemctl enable iptables # start on boot
      systemctl start iptables
      systemctl status iptables
      iptables -F  # flush all chains
      iptables-save > /etc/sysconfig/iptables  # update the on-boot rules
      

      https://krash.be/node/28

      I used the above instructions to get firewalld working with fail2ban on Centos7. Firewalld is much easier to use I find than iptables. Hope this helps.

      Well according to nta345abc7ce57987e01e50052 on this page, “banaction = iptables-multiport” still uses firewalld in the default DigitalOcean-CentOS7.

      I’m still not clear about the distinction between iptables and firewalld in CentOS7.

      Another thing you may want to do is set your server up so that any ssh login from outside of your country automatically means that IP is blocked. If you are in the US then more than likely you won’t have anyone from Ireland for example that should be logging into your host.

      I stumbled upon this while looking into it about a day or two ago, I haven’t implemented it for SSH but I did use that database for redirecting non-US login attempts for my WordPress to fbi.gov. So far its been less than a month and around 1500 attempts have been blocked/redirected lol.

      https://www.axllent.org/docs/view/ssh-geoip/

      Interesting. I didn’t even know that option existed. Thanks.

      Any other security ideas? I’m trying to learn best practices.

      Well I personally modified the script in that post to also add iptable rules that will drop any packets to or from any IP from another country that attempts to ssh to my droplet. The reasoning is simple, if you are trying to get onto the ssh from China then chances are I don’t want you even viewing my site.

      Already blocked 83 attempts in about a day.

      logger "$RESPONSE sshd connection from $1 ($COUNTRY)"
        /sbin/iptables -I INPUT -s $1 -j DROP
        /sbin/iptables -I OUTPUT -d $1 -j DROP
        exit 1
      

      There’s a typo in the article.

      action = $(action_)s
      

      Replace the dollar sign with a percent sign and it should work. If you use the dollar sign, fail2ban will fail2start.

      Please be aware that if you are running an ipv6 enabled server the default fail2ban installed from the repository will not ban any malicious users connecting with ipv6.

      (fail2ban version 0.10.0 have ipv6 support and can be installed from source.)

      Is iptables different from firewalld?

      In a default DigitalOcean CENTOS image with fail2ban installed according to this tutorial, I gather that it uses iptables rather than firewalld?

      I see new lines in sudo iptables -L , immediately after starting fail2ban. So it does seem that fail2ban uses iptables.

      Should firewalld be running at all?

      I ask because after a rare reboot, I found my website unreachable until firewalld was stopped, and when I looked inside /etc/firewalld/zones/ it only contained public.xml which only contained:

      <?xml version=“1.0” encoding=“utf-8”?> <zone> <short>Public</short> <description>For use in public areas. You do not trust the other computers on networks to not harm your computer. Only selected incoming connections are accepted.</description> <service name=“ssh”/> <service name=“dhcpv6-client”/> </zone>

      Does this explain why webbrowsers could not view my website? Thank you!

      IPtables is the older way of doing a firewall on CentOS. The newer way is firewalld. You should absolutely use Firewalld. I’d recommend reading the initial server setup series, including the second article in the series that covers the basic setup for Firewalld. Having a basic firewall set up is absolutely essential for having a secure VPS. If you go through those initial setup articles, including the firewall set up, it will show you how to open up the firewall to service: ssh, http, https, etc. You can also open ports if, for example, you changed your ssh port.

      Fail2ban is a different security measure that prevents brute force hacking via ssh. It’s essential as well. There are people trying to hack your droplet the moment you make it live. You have to secure it. I’d review the initial set up series for CentOS 7, doing all the suggested security measures.

      I hope this helps.

      Hi, Your URLs were removed. Do you mean:

      “Initial Server Setup with CentOS 7” https://www.digitalocean.com/community/tutorials/initial-server-setup-with-centos-7

      and

      “Additional Recommended Steps for New CentOS 7 Servers” https://www.digitalocean.com/community/tutorials/additional-recommended-steps-for-new-centos-7-servers (I now realize that I had not done these steps)

      And I have not found a tutorial for fail2ban for firewalld for CentOS7.

      I’m not sure why my URL’s were removed. Yes, I meant the initial setup articles cover firewalld and recommend fail2ban. You don’t need to change your firewall for fail2ban. The two things are not connected and there’s no service to “let through.”

      So you should be able to setup fail2ban without making any changes at all to the firewalld configuration.

      But if we set up fail2ban according to this tutorial, it instructs us to

      Paste the following in /etc/fail2ban/jail.local

      [DEFAULT]

      Ban hosts for one hour:

      bantime = 3600

      Override /etc/fail2ban/jail.d/00-firewalld.conf:

      banaction = iptables-multiport [sshd] enabled = true

      Does the “banaction = iptables-multiport” mean that fail2ban relies on iptables functioning?

      This comment has been deleted

        I believe this tutorial is outdated and does not work with DO’s 2018 CentOS7 images, which don’t have iptables installed, but DO have firewalld installed by default.

        Think of firewalld as a frontend to iptables. I’ve set up fail2ban many times recently and it does not require anything special.

        What exactly is going wrong when you try to do it?

        Is it normal that:

        “sudo systemctl status iptables” gives “Unit iptables.service could not be found.”

        and

        “sudo systemctl status firewalld” gives green “active (running)” …

        And is it normal to use “banaction = iptables-multiport” inside “/etc/fail2ban/jail.local” ?

        “What exactly is going wrong when you try to do it?”

        The problem I had wasn’t directly with fail2ban, it had to do with firewalld kicking in unexpectedly after a reboot, and now I am trying to understand how firewalld relates to iptables and fail2ban.

        In mid-Feb-2018, I was new to DigitalOcean, and when I first followed the instructions here, and I did not do anything about firewalld. (I had not read “Additional Recommended Steps for New CentOS 7 Servers” at all ), then I set up my Wordpress website, and it ran for more than a month. I never had a problem with SSH access, and I never tested whether repeated wrong-password attempts were being banned.

        Then, yesterday, I rebooted for the first time. When the server became ready again, I could SSH in as normal, but the website was unreachable from the internet. After much checking, stopping firewalld solved the problem. And I found within /etc/firewalld/zones/public.xml , only two services were stated, “ssh” and “dhcpv6-client”. I have since added “http” and “https”, and have started firewalld again.

        Make your goal a very simple set up of jail.local to prevent people from brute forcing your droplet with ssh.

        Join the Tech Talk
        Success! Thank you! Please check your email for further details.

        Please complete your information!

        Become a contributor for community

        Get paid to write technical tutorials and select a tech-focused charity to receive a matching donation.

        DigitalOcean Documentation

        Full documentation for every DigitalOcean product.

        Resources for startups and SMBs

        The Wave has everything you need to know about building a business, from raising funding to marketing your product.

        Get our newsletter

        Stay up to date by signing up for DigitalOcean’s Infrastructure as a Newsletter.

        New accounts only. By submitting your email you agree to our Privacy Policy

        The developer cloud

        Scale up as you grow — whether you're running one virtual machine or ten thousand.

        Get started for free

        Sign up and get $200 in credit for your first 60 days with DigitalOcean.*

        *This promotional offer applies to new accounts only.