๐ก๏ธ Complete Guide to Fail2Ban - Protect Your SSH Server from Brute Force Attacks
Protect your Linux servers from SSH brute-force attacks with Fail2Ban. This guide covers easy-to-follow configuration steps, security best practices, and testing methods to harden your SSH access.
๐ Introduction
Securing your SSH access is a fundamental step in hardening any Linux server. While using SSH Key-Based Authentication and enabling Two-Factor Authentication (2FA) significantly strengthen login security, these methods alone donโt prevent brute force attacks.
๐ Table of Contents
- Introduction
- Why Brute Force Attacks Are Still a Threat
- What is Fail2Ban?
- Testing Fail2Ban Protection
Conclusion and Next Steps
Brute force attempts can lead to:
- ๐ก๏ธ Security Risks
- ๐ Performance and Resource Impacts
- ๐ก Network Disruptions
- ๐ Compliance and Audit Violations
Even with firewalls and IP restrictions using AllowUsers, compromised devices within your network can still launch brute force attacks. This is where Fail2Ban comes in.
๐จ Why Brute Force Attacks Are Still a Threat
You might think, โI have SSH keys and 2FA enabled; isnโt that enough?โ Unfortunately, the answer is no. While these measures prevent unauthorized access, they donโt stop repeated failed login attempts that can:
- Consume system resources
- Fill up logs, affecting audit clarity
- Trigger compliance violations
- Potentially exploit zero-day vulnerabilities
Fail2Ban actively prevents these attacks by blocking malicious IP addresses before they can become a bigger problem.
๐ What is Fail2Ban?
Fail2Ban is a powerful intrusion prevention system that monitors log files and reacts to suspicious activity, such as repeated failed authentication attempts. While weโre focusing on SSH in this guide, Fail2Ban also supports services like Apache, NGINX, and Sendmail.
โ Common Fail2Ban Actions:
- Apply temporary or permanent bans
- Block IP addresses using firewall rules
- Modify IP sets for advanced firewall management
- Add routes to blackhole malicious traffic
- Send email notifications to administrators
- Execute custom scripts
- Log and alert without banning (monitoring mode)
Fail2Banโs actions are highly customizable, allowing you to tailor protections based on your specific security requirements.
๐ ๏ธ How to Set Up Fail2Ban for SSH
Fail2Ban configuration primarily revolves around its jail files. The jail.conf
file contains default settings, but itโs best practice to use jail.local
and service-specific .local
files for custom configurations.
๐ฆ File 1: Global Defaults โ /etc/fail2ban/jail.local
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
[DEFAULT]
# ========================
# Fail2Ban Global Settings
# ========================
# IP addresses or networks to ignore (never ban).
# Add your trusted subnets and management IPs here.
ignoreip = 127.0.0.1/8 ::1 192.168.178.0/24
# Duration for which an IP is banned after exceeding maxretry attempts.
# Format examples: s (seconds), m (minutes), h (hours), d (days)
bantime = 1h
# Time window within which maxretry failures must occur to trigger a ban.
findtime = 10m
# Number of failed attempts before an IP gets banned.
maxretry = 3
# Backend used to read logs.
# 'systemd' is recommended for modern systems using journalctl.
backend = systemd
# Control DNS usage in logs and actions.
# Options: yes | warn | no
# 'warn' tries to resolve but continues if it fails.
usedns = warn
# ===========================
# Ban Action Configuration
# ===========================
# Action to take when a rule is triggered.
# %(action_mwl)s:
# - Ban the IP
# - Send an email with whois info and relevant logs
action = %(action_mwl)s
๐ฆ File 2: SSH-Specific Settings โ /etc/fail2ban/jail.d/sshd.local
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
[sshd]
# ==========================
# SSH Jail Configuration
# ==========================
# Enable the SSH jail to monitor and protect against brute-force attacks.
enabled = true
# Port Fail2Ban should monitor for SSH connections.
# If you run SSH on a custom port, replace 'ssh' with the actual port number (e.g., 2222).
port = ssh
# Filter definition to use.
# 'sshd' refers to the default filter that matches common SSH authentication failures.
filter = sshd
# Log file location.
# '%(sshd_log)s' uses the default value set by the system, typically /var/log/auth.log or journalctl.
logpath = %(sshd_log)s
# Backend for reading logs.
# 'systemd' is recommended if your system uses journalctl for logging.
backend = systemd
# ==========================
# SSH-Specific Overrides
# ==========================
# Time window to evaluate failed login attempts.
# If 'maxretry' failures occur within this time, the IP will be banned.
findtime = 5m
# Number of failed attempts allowed before triggering a ban.
maxretry = 4
๐ก Tip: You can apply the same structure for other services like nginx.local
or apache.local
under /etc/fail2ban/jail.d/
to keep configurations clean and organized.
Fail2Ban processes configuration files in the following order:
/etc/fail2ban/jail.conf
(Defaults โ Do Not Modify)/etc/fail2ban/jail.local
(Global Overrides)- All
.local
files in/etc/fail2ban/jail.d/
(Service-Specific Settings)
๐งฉ Testing Fail2Ban Protection
After setting up Fail2Ban, itโs crucial to validate that it correctly detects and mitigates brute force attempts.
Hereโs a simple script to simulate failed SSH logins:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
#!/bin/bash
# ===============================
# Fail2Ban SSH Ban Trigger Script
# ===============================
# This script intentionally generates failed SSH login attempts
# to test if Fail2Ban properly detects and blocks brute-force attacks.
# -------------------------------
# Target Configuration
# -------------------------------
TARGET_HOST="192.168.178.13" # IP address or hostname of the target server to test
FAKE_USER="invaliduser" # Non-existent username to force authentication failure
ATTEMPTS=5 # Number of failed attempts (match or exceed Fail2Ban 'maxretry' setting)
echo "Triggering Fail2Ban by attempting to SSH as user '$FAKE_USER' to $TARGET_HOST"
# -------------------------------
# Brute-Force Simulation Loop
# -------------------------------
for i in $(seq 1 $ATTEMPTS); do
echo "Attempt $i..."
ssh \
-o PreferredAuthentications=password \ # Force password authentication (skip public key)
-o PubkeyAuthentication=no \ # Disable public key authentication entirely
-o StrictHostKeyChecking=no \ # Avoid host key verification prompts
-o ConnectTimeout=5 \ # Limit each connection attempt to 5 seconds
"$FAKE_USER@$TARGET_HOST" exit # Attempt to connect and immediately exit if successful (won't be)
done
# -------------------------------
# Final Status Message
# -------------------------------
echo "Done. Check Fail2Ban status on the target server using:"
echo " sudo fail2ban-client status sshd"
Check the Fail2Ban status:
1
sudo fail2ban-client status sshd
Example output:
1
2
3
4
5
6
7
8
9
Status for the jail: sshd
|- Filter
| |- Currently failed: 1
| |- Total failed: 5
| `- Journal matches: _SYSTEMD_UNIT=sshd.service + _COMM=sshd
`- Actions
|- Currently banned: 1
|- Total banned: 1
`- Banned IP list: 192.168.178.11
To manually unblock an IP before the ban expires:
1
sudo fail2ban-client set sshd unbanip 192.168.178.11
โ Conclusion and Next Steps
SSH is a critical protocol for remote Linux server management but also remains a primary target for attackers. By combining Fail2Ban with 2FA, SSH Key Authentication, and IP Restrictions, you create a multi-layered defense that significantly reduces the risk of compromise.
๐ New to SSH Security? Start Here!
Kick off your SSH hardening journey with Your First Steps to a Hardened SSH Server. Learn why securing sshd_config
is critical and how to avoid common security pitfalls.
Drop a comment or reach outโweโre here to help. For more content like this, tools, and walkthroughs, visit my site at Sebos Technology.