{"id":401,"date":"2020-10-14T15:00:45","date_gmt":"2020-10-14T15:00:45","guid":{"rendered":"https:\/\/dft.wiki\/?p=401"},"modified":"2026-06-09T14:34:33","modified_gmt":"2026-06-09T18:34:33","slug":"increase-security-with-fail2ban-on-ubuntu-20-4","status":"publish","type":"post","link":"https:\/\/dft.wiki\/?p=401","title":{"rendered":"Increasing Security with Fail2Ban on Ubuntu"},"content":{"rendered":"<p><strong>Fail2Ban<\/strong> is a service that watches the log files of your services, such as SSH, HTTP, and FTP, looking for consecutive authentication failures that may indicate an unauthorized login attempt.<\/p>\n<p>When it detects a possible intruder that fails to log in X times within Y period of time, it bans the origin IP address for Z time by creating a firewall rule, which is automatically removed after the ban expires.<\/p>\n<pre>sudo apt update\r\nsudo apt install fail2ban\r\nsudo systemctl status fail2ban<\/pre>\n<p>You should see the service as active (running).<\/p>\n<pre>sudo cp \/etc\/fail2ban\/jail.{conf,local}\r\nsudo nano \/etc\/fail2ban\/jail.local<\/pre>\n<p>Set up your whitelist by uncommenting the line below and filling it with trusted IP addresses. Typically, this includes the loopback interfaces (127.0.0.1\/8 and ::1), and if you access your network remotely via VPN, also include the VPN subnet (e.g., 10.8.0.0\/24).<\/p>\n<pre>ignoreip = 127.0.0.1\/8 ::1 10.8.0.0\/24<\/pre>\n<p>Before saving the file, define X, Y, and Z:<\/p>\n<pre>bantime = <strong>1d<\/strong>\r\nfindtime = <strong>60m<\/strong>\r\nmaxretry = <strong>5<\/strong>\r\nbackend = <strong>systemd<\/strong><\/pre>\n<p>In this example, if someone fails 5 times within 60 minutes, they will be banned for 1 day. Also change the backend to &#8220;systemd&#8221;, since the default value &#8220;auto&#8221; may not catch any events.<\/p>\n<p>To configure e-mail alert notifications when someone is banned (requires an SMTP server):<\/p>\n<pre>destemail = admin@yourdomain.com\r\nsender = root@yourdomain.com\r\naction = %(action_mw)s<\/pre>\n<p>Scroll down to find the services you want to protect. Only enable the ones you actually need.<\/p>\n<pre>[sshd]\r\n<strong>enabled = true<\/strong>\r\n#mode = normal\r\nport = ssh\r\nlogpath = %(sshd_log)s\r\nbackend = %(sshd_backend)s<\/pre>\n<p>Add <strong>enabled = true<\/strong> to each jail you want to activate.<\/p>\n<p>In the example above, I enabled it for SSH. I would do the same for HTTP, FTP, and any other service exposed to the internet that requires authentication.<\/p>\n<p>Note the commented line in the example above. You can uncomment <strong>mode = normal<\/strong> and switch to a more aggressive approach, such as <strong>DDoS<\/strong>, <strong>extra<\/strong>, or <strong>aggressive<\/strong>. See &#8220;filter.d\/sshd.conf&#8221; for usage examples and details.<\/p>\n<p>Save the configuration file, restart the service, and verify it is running without errors:<\/p>\n<pre>sudo systemctl restart fail2ban\r\nsudo systemctl status fail2ban<\/pre>\n<p>Fail2Ban includes a CLI tool called <strong>fail2ban-client<\/strong> for interacting with the service. Usage examples:<\/p>\n<pre>sudo fail2ban-client status sshd\r\nsudo fail2ban-client set sshd unbanip 1.1.1.1\r\nsudo fail2ban-client set sshd banip 1.1.1.1\r\nsudo fail2ban-client -h<\/pre>\n<p>Right after setting up the service, I received 46 e-mails about banned IPs trying to log in to my SSHD as root (last digits omitted):<\/p>\n<pre>Total failed: <strong>1106<\/strong>\r\nTotal banned: <strong>38<\/strong>\r\nBanned <strong>IP list<\/strong>: 93.39.184.1X 95.78.251.11X 208.109.11.3X 167.71.237.7X 162.243.130.8X 82.65.23.6X 100.26.163.9X (...)<\/pre>\n<p>Looking up the origin of those IP addresses, they come from all over: USA, CH, IND, SG, RU, IT, FR, UK, GER, VN, NL, HK, etc. Most of them belong to OVH SAS and DigitalOcean.<\/p>\n<p>Due to the high volume of bans, I ended up disabling e-mail notifications (more than 10 per hour).<\/p>\n<p>A week after setting up Fail2Ban, the number of daily bans on my SSH dropped from 200 to 4. My guess is that once attackers get banned, many stop trying. For the same reason, I also plan to disable ping responses to avoid advertising that the server is live.<\/p>\n<p>To get the status of all jails at once (this is a single long command):<\/p>\n<pre>fail2ban-client status | sed -n 's\/,\/\/g;s\/.*Jail list:\/\/p' | xargs -n1 fail2ban-client status<\/pre>\n<hr \/>\n<p><strong>BONUS<\/strong><\/p>\n<p>Did you know you can use Fail2Ban to protect your <strong>WordPress<\/strong> website as well? See more in WordPress Configuration Tips and Tricks [<a href=\"https:\/\/dft.wiki\/?p=405\">Link<\/a>].<\/p>\n<p>As an alternative, the open source <strong>SSHGuard<\/strong> aims to accomplish the same goal [<a href=\"https:\/\/bitbucket.org\/sshguard\/sshguard\/\">Link<\/a>].<\/p>\n<pre>sudo apt update &amp;&amp; sudo apt install sshguard -y\r\necho '192.168.1.0\/24' &gt;&gt; \/etc\/sshguard\/whitelist\r\nsudo nano \/etc\/sshguard\/sshguard.conf<\/pre>\n<p>Configure accordingly.<\/p>\n<pre># For IPTABLES\r\nBACKEND=\"\/usr\/lib\/sshguard\/sshg-fw-iptables\"\r\n# For NFTABLES\r\n#BACKEND=\"\/usr\/lib\/sshguard\/sshg-fw-nft-sets\"\r\nWHITELIST_FILE=\"\/etc\/sshguard\/whitelist\"\r\nBLOCK_TIME=1200\r\nDETECTION_TIME=1800\r\nTHRESHOLD=30<\/pre>\n<p>Start the service and monitor the logs.<\/p>\n<pre>sudo systemctl enable sshguard --now\r\nsudo journalctl -u sshguard -f<\/pre>\n<p>List banned IPs and unban by line number.<\/p>\n<pre>sudo iptables --list sshguard --line-numbers --numeric\r\nsudo iptables --delete sshguard &lt;line-number&gt;<\/pre>\n","protected":false},"excerpt":{"rendered":"<p>Fail2Ban is a service that watches the log files of your services, such as SSH, [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[4,6],"tags":[],"class_list":["post-401","post","type-post","status-publish","format-standard","hentry","category-linux","category-raspberry-pi"],"_links":{"self":[{"href":"https:\/\/dft.wiki\/index.php?rest_route=\/wp\/v2\/posts\/401","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/dft.wiki\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/dft.wiki\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/dft.wiki\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/dft.wiki\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=401"}],"version-history":[{"count":18,"href":"https:\/\/dft.wiki\/index.php?rest_route=\/wp\/v2\/posts\/401\/revisions"}],"predecessor-version":[{"id":5827,"href":"https:\/\/dft.wiki\/index.php?rest_route=\/wp\/v2\/posts\/401\/revisions\/5827"}],"wp:attachment":[{"href":"https:\/\/dft.wiki\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=401"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/dft.wiki\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=401"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/dft.wiki\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=401"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}