Ravindra BagaleCourses & study guides Track your progress

Guides

Fail2ban Setup: Protect SSH on Linux from Brute-Force Attacks Step by Step

Fail2ban watches your login logs and blocks IP addresses that fail too many times. Install it (sudo apt install fail2ban on Ubuntu, from EPEL or the distro repo on Amazon Linux/RHEL), create /etc/fail2ban/jail.local with an enabled [sshd] jail (for example 5 failures in 10 minutes = 1-hour ban), add your own IP to ignoreip, and start it. Check bans with sudo fail2ban-client status sshd. It is an extra layer: SSH keys and a restricted port 22 come first.

Quick answer: /etc/fail2ban/jail.local

[DEFAULT]
ignoreip = 127.0.0.1/8 ::1 203.0.113.10
bantime  = 1h
findtime = 10m
maxretry = 5

[sshd]
enabled = true
backend = systemd     ; Amazon Linux 2023 / journal-only systems
sudo systemctl enable --now fail2ban
sudo fail2ban-client status sshd

A live example first

We opened an Ubuntu server's SSH port to the internet for a training lab. Within an hour the log was full:

sudo grep "Failed password" /var/log/auth.log | tail -n 3
Oct 16 21:02:11 lab sshd[2211]: Failed password for root from 198.51.100.23 port 51422 ssh2
Oct 16 21:02:14 lab sshd[2213]: Failed password for invalid user admin from 198.51.100.23 port 51988 ssh2
Oct 16 21:02:17 lab sshd[2215]: Failed password for invalid user oracle from 198.51.100.23 port 52101 ssh2
  1. Install and configure:
sudo apt update && sudo apt install -y fail2ban
sudo nano /etc/fail2ban/jail.local      # paste the quick-answer config (no backend line needed on Ubuntu)
sudo systemctl enable --now fail2ban
  1. Ten minutes later:
sudo fail2ban-client status sshd
Status for the jail: sshd
|- Filter
|  |- Currently failed: 3
|  |- Total failed:     41
`- Actions
   |- Currently banned: 4
   |- Total banned:     4
   `- Banned IP list:   198.51.100.23 192.0.2.77 203.0.113.91 198.51.100.140
  1. Then we did the real fix: switched to key-only login and limited port 22 in the cloud firewall to our office IP. Friends, fail2ban cut the noise, but the keys closed the door.

How does fail2ban work?

fail2ban flow Failed SSH logins appear in the logs, fail2ban counts them per IP, bans the IP in the firewall, and unbans it after the ban time. fail2ban flow AttackerguessesLogfailed loginCount5 in 10 minBanfirewallUnbanafter 1 h you An extra layer. SSH keys and closed port 22 come first

fail2ban counts failed logins per IP and bans repeat guessers in the firewall for a set time.

Each jail joins a filter (a pattern that finds failed logins in a log) with an action (usually a firewall ban through nftables, iptables or firewalld). When one IP matches maxretry times within findtime, it is banned for bantime, then automatically unbanned.

How do I set it up step by step?

  1. Install fail2ban for your distribution (table below).
  2. Create /etc/fail2ban/jail.local. Do not edit jail.conf.
  3. Put your own fixed IPs in ignoreip.
  4. Enable the [sshd] jail; set backend = systemd if there is no auth log file.
  5. sudo systemctl enable --now fail2ban.
  6. Check sudo fail2ban-client status sshd.
  7. Test from another IP with wrong passwords (in a lab), and confirm it gets banned.
  8. Unban with sudo fail2ban-client set sshd unbanip IP.

Install by distribution

Distribution Install Log source
Ubuntu / Debian sudo apt install fail2ban /​var/​log/​auth.​log (or journal on newer Debian, set backend = systemd)
Amazon Linux 2023 sudo dnf install fail2ban if available in your repo, else from source/pip per docs systemd journal (backend = systemd)
Amazon Linux 2 sudo amazon-​linux-​extras install epel then sudo yum install fail2ban /var/log/secure
RHEL / Rocky / Alma sudo dnf install epel-​release && sudo dnf install fail2ban /var/log/secure or journal

On RHEL-family systems the ban action usually uses firewalld (banaction = firewallcmd-rich-rules).

Protect more than SSH

Service Jail Catches
nginx basic auth [nginx-​http-​auth] Failed password prompts
nginx bad bots [nginx-​botsearch] Scans for /wp-login.php, /phpmyadmin on non-WordPress sites
WordPress plugin log + custom filter Login guessing
Postfix / Dovecot [postfix], [dovecot] Mail login guessing
Repeat offenders [recidive] IPs banned many times; long ban
[nginx-http-auth]
enabled = true
port    = http,https
logpath = /var/log/nginx/error.log

The right order of SSH defences

Defence Effect
1. Key-only login (PasswordAuthentication no) Password guessing becomes useless
2. Firewall / security group: port 22 from your IP only Attackers cannot even connect
3. AWS Systems Manager Session Manager No open port 22 at all
4. PermitRootLogin no Removes the most guessed username
5. fail2ban Bans what still gets through, cuts log noise

Real example

In 2016, the Mirai botnet infected hundreds of thousands of cameras and routers simply by trying a short list of default usernames and passwords over Telnet, then used them for record-breaking DDoS attacks, including the October 2016 attack on Dyn that slowed major websites. Automated password guessing against any open login port is constant, which is why you see attempts within minutes of opening SSH.

Useful fail2ban-client commands

Command What it does
sudo fail2ban-​client status List all active jails
sudo fail2ban-​client status sshd Show failures and banned IPs for SSH
sudo fail2ban-​client set sshd banip 198.​51.​100.​23 Ban an IP by hand
sudo fail2ban-​client set sshd unbanip 198.​51.​100.​23 Remove a ban
sudo fail2ban-​client reload Load changes to jail.local
sudo fail2ban-​regex /​var/​log/​auth.​log /​etc/​fail2ban/​filter.​d/​sshd.​conf Test whether the filter matches your log

Troubleshooting

  1. Jail shows 0 failures while attacks happen: the log path or backend is wrong. On journal-only systems set backend = systemd.
  2. fail2ban will not start: run sudo fail2ban-client -d to print the config and find the error line.
  3. Bans do not block traffic: check that the ban action matches your firewall (nftables, iptables or firewalld) with sudo nft list ruleset or sudo firewall-cmd --list-all.
  4. Behind a load balancer: SSH is not usually behind one, but for nginx jails the log shows the load balancer IP, so log the real client IP first.

Mistakes to avoid

  1. Banning yourself. Always set ignoreip before testing.
  2. Editing jail.conf. Updates overwrite it.
  3. Relying only on fail2ban with password login still on. Use keys.

Summary table

Task Command / setting
Install apt install fail2ban / dnf install fail2ban
Config file /​etc/​fail2ban/​jail.​local
SSH jail [sshd] enabled = true
Journal systems backend = systemd
Status fail2ban-​client status sshd
Unban fail2ban-​client set sshd unbanip IP

Quick quiz: check what you learned

  1. What does fail2ban read to find attackers?

    1. Log files of failed logins
    2. The bash history of users
    3. Your nginx config file
    4. The list of installed apps
    Show answer

    A. It watches logs like auth.log or the journal.

  2. Which file should hold your fail2ban settings?

    1. jail.local
    2. jail.conf
    3. sshd_config
    4. fstab file
    Show answer

    A. jail.local survives package updates.

  3. What is the best first defence for SSH?

    1. SSH keys, no passwords
    2. A longer welcome banner
    3. Changing the hostname
    4. Installing a GUI desktop
    Show answer

    A. Key-only login stops password guessing.

  4. How do you list IPs banned by the sshd jail?

    1. fail2ban-client status sshd
    2. systemctl list-units all
    3. ss -tulpn on the host
    4. journalctl --disk-usage
    Show answer

    A. status shows counts and banned IPs.

Frequently asked questions

What does fail2ban do?

It reads log files, finds IP addresses with too many failed logins, and adds firewall rules to block them for a set time.

Is fail2ban enough to secure SSH?

No. Use SSH keys, disable password login, and limit port 22 in the firewall or security group. Fail2ban is an extra layer.

Why should I not edit jail.conf?

Package updates can overwrite it. Put your settings in jail.local or files in jail.d/.

How do I see banned IPs?

Run sudo fail2ban-client status sshd.

How do I unban an IP?

Run sudo fail2ban-client set sshd unbanip 203.0.113.5.

Does it work on Amazon Linux 2023?

Yes, but logs go to the systemd journal, so set backend = systemd in the jail.