Securing SSH server with fail2ban
19 06 2009When you are running your SSH server on the standard port 22, you likely see brute force login attempts multiple times a day. The SSH server does not limit unsuccessfull login attempts by itself. So there are multiple ways to deal with this problem.
One option is to move the SSH daemon to a non-standard port. But this means that you might get problems connecting yourself to the server if you are working from a restricted network. So another solution would be to use certificates for login. But then you need to make sure that you carry the certificates with you when you want to login to your server.
Now a good solution is to limit access to the SSH server. One way would be to use the so called port-knocking approach. Here the access to the SSH port is blocked until you use some kind of secret knock-sequence. Then the port will be unblocked for your IP for a certain time. This is very effective but has the downside that you always need to use this knock mechanism before connecting to your server.
What I prefer is a mechanism which works the other way around. The access to the SSH port is open until there are a number of failed login attempts detected. If this is the case, the IP address these login attempts came from will be blocked for a couple of hours. This approach is less secure then the port knocking approach but is a lot more convenient for me. As long is I don’t mess up multiple times with the login, I do not even notice any security restrictions. Brute force attacks on the other hand are blocked right away.
The most common tool for this task is the excellent fail2ban. On a Debian system it can be installed via aptitude:
aptitude install fail2ban
The default configuration is already useful. It will secure the SSH daemon with a blocking time of 10 minutes after 6 failed login attempts. The configuration files can be found in the directory /etc/fail2ban.
You can change the blocking time in the file /etc/fail2ban/jail.conf:
[DEFAULT] bantime = 7200 maxretry = 4
This will change the default settings which apply if not specified otherwise in the application settings. The setting bantime is specified in seconds and defines how long the blocked IP will not be able to connect to the blocked service. maxretry is the number of failed login attempts.
Lets take a look at the ssh setting:
[ssh] enabled = true port = ssh filter = sshd logpath = /var/log/auth.log maxretry = 3
You can enable or disable the monitoring of specific services (ports). The ssh monitoring uses the auth.log file to detect failed login attempts.
To activate changed configuration settings, just reload the service:
/etc/init.d/fail2ban force-reload
So what happens when an IP is blocked? Once the login attempt limit has been reached, the IP address will be blocked via iptables. Here is the output of iptables on my system:
Chain INPUT (policy ACCEPT) target prot opt source destination fail2ban-ssh tcp -- 0.0.0.0/0 0.0.0.0/0 multiport dports 22 Chain FORWARD (policy ACCEPT) target prot opt source destination Chain OUTPUT (policy ACCEPT) target prot opt source destination Chain fail2ban-ssh (1 references) target prot opt source destination DROP all -- 123.456.789.012 0.0.0.0/0 RETURN all -- 0.0.0.0/0 0.0.0.0/0
I have replaced the blocked IP address with some default numbers, but you can see that all traffic from this IP address to the port 22 will be blocked. This iptables rule will be automatically removed after the specified blockout time.
fail2ban is an effective tool to lock out brute force login attempts. It is really easy to setup and can be used to monitor multiple services besides SSH.






Thanks for the hint!
Just installed this solution on our Ubuntu cluster. This is way more convenient than using the denyhosts package!
Thanks Michael for the comment. Looking forward to seeing you online sometimes.
Me too!
Maybe just a sidenote to the program. On Ubuntu 9.04 the fail2ban logfiles got a little spammed with messages like:
2009-07-20 14:16:59,535 fail2ban.server : ERROR Unexpected communication error
I found out that this seems to be a problem with python 2.6. So I installed python 2.5 and adjusted the files fail2ban-client, fail2ban-regex and fail2ban-server (I guess, the first ones aren’t necessary, but anyway) in a way, that they read:
#!/usr/bin/python2.5
That gets rid of the error messages, but I think there were no other problems besides that.
Good point! I am running python 2.5 on my server, so I did not have any problems with fail2ban.