
How to Protect SSH with Fail2ban on Ubuntu 24
SSH (Secure Shell) is the backbone of remote server administration, but it’s also one of the most targeted attack vectors on internet-facing servers. Every day, thousands of automated bots scan for open SSH ports and attempt brute-force attacks using common usernames and passwords. Fail2ban is an intrusion prevention tool that monitors log files and automatically bans IP addresses showing suspicious behavior, creating a robust defense layer for your SSH service. In this guide, we’ll walk through setting up Fail2ban on Ubuntu 24 to protect your SSH server, covering installation, configuration, monitoring, and troubleshooting common issues.
How Fail2ban Works
Fail2ban operates as a daemon that continuously monitors specified log files for patterns indicating malicious activity. When it detects repeated failed login attempts or other suspicious patterns, it triggers actions like temporarily banning the offending IP address through iptables or other firewall mechanisms.
The architecture consists of several key components:
- Filters: Regular expressions that define what constitutes a failure or suspicious activity in log files
- Actions: Commands executed when a ban threshold is reached (typically adding iptables rules)
- Jails: Configurations that combine filters and actions with specific parameters like ban time and retry limits
- Backend: The mechanism used to monitor log files (polling, pyinotify, or systemd)
For SSH protection, Fail2ban typically monitors /var/log/auth.log
for failed authentication attempts and uses iptables to block offending IPs at the network level.
Step-by-Step Installation and Setup
Let’s get Fail2ban up and running on your Ubuntu 24 system. First, ensure your system is updated:
sudo apt update && sudo apt upgrade -y
Install Fail2ban from the official repositories:
sudo apt install fail2ban -y
The installation automatically creates the necessary directories and starts the service. Check the status to confirm it’s running:
sudo systemctl status fail2ban
Now we need to configure Fail2ban. The main configuration files are located in /etc/fail2ban/
. Never edit the original jail.conf
file directly as it gets overwritten during updates. Instead, create a local configuration file:
sudo cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local
Open the local configuration file for editing:
sudo nano /etc/fail2ban/jail.local
Here’s a robust configuration for SSH protection. Locate the [sshd]
section and modify it as follows:
[DEFAULT]
# Ban time in seconds (1 hour)
bantime = 3600
# Find time window in seconds (10 minutes)
findtime = 600
# Number of failures before ban
maxretry = 3
# Ignore local IPs (add your admin IPs here)
ignoreip = 127.0.0.1/8 ::1 192.168.1.0/24
# Email notifications (optional)
destemail = admin@yourdomain.com
sender = fail2ban@yourdomain.com
mta = sendmail
[sshd]
enabled = true
port = ssh
protocol = tcp
filter = sshd
logpath = /var/log/auth.log
backend = %(sshd_backend)s
maxretry = 3
bantime = 3600
findtime = 600
If you’re using a non-standard SSH port, update the port parameter accordingly:
port = 2222
For enhanced security, you can create additional jails for different types of SSH attacks. Add these sections to your jail.local
file:
[sshd-aggressive]
enabled = true
port = ssh
protocol = tcp
filter = sshd-aggressive
logpath = /var/log/auth.log
maxretry = 2
bantime = 7200
findtime = 300
[sshd-ddos]
enabled = true
port = ssh
protocol = tcp
filter = sshd-ddos
logpath = /var/log/auth.log
maxretry = 6
bantime = 600
findtime = 120
Create the corresponding filter files. First, the aggressive filter:
sudo nano /etc/fail2ban/filter.d/sshd-aggressive.conf
[Definition]
failregex = ^%(__prefix_line)s(?:error: PAM: )?[aA]uthentication (?:failure|error|failed) for .* from ( via \S+)?\s*$
^%(__prefix_line)s(?:error: )?Received disconnect from : 3: .*: Auth fail$
^%(__prefix_line)sFailed \S+ for invalid user .* from port \d*$
^%(__prefix_line)sUser .+ from not allowed because not listed in AllowUsers$
^%(__prefix_line)sUser .+ from not allowed because listed in DenyUsers$
^%(__prefix_line)sUser .+ from not allowed because not in any group$
And the DDOS filter:
sudo nano /etc/fail2ban/filter.d/sshd-ddos.conf
[Definition]
failregex = ^%(__prefix_line)sdid not receive identification string from $
ignoreregex =
Restart Fail2ban to apply the configuration:
sudo systemctl restart fail2ban
Enable Fail2ban to start automatically on boot:
sudo systemctl enable fail2ban
Monitoring and Management
Fail2ban provides several commands for monitoring and managing bans. Here are the essential ones you’ll use regularly:
Check the status of all jails:
sudo fail2ban-client status
View detailed status for a specific jail:
sudo fail2ban-client status sshd
Manually ban an IP address:
sudo fail2ban-client set sshd banip 192.168.1.100
Unban an IP address:
sudo fail2ban-client set sshd unbanip 192.168.1.100
View current iptables rules created by Fail2ban:
sudo iptables -L -n
For comprehensive monitoring, you can create a simple script to check Fail2ban status:
#!/bin/bash
# fail2ban-monitor.sh
echo "=== Fail2ban Status ==="
sudo fail2ban-client status
echo -e "\n=== SSH Jail Details ==="
sudo fail2ban-client status sshd
echo -e "\n=== Recent Auth Log Entries ==="
sudo tail -20 /var/log/auth.log | grep -E "(Failed|Invalid|Ban)"
echo -e "\n=== Current Bans in iptables ==="
sudo iptables -L f2b-sshd -v -n 2>/dev/null || echo "No f2b-sshd chain found"
Make it executable and run it:
chmod +x fail2ban-monitor.sh
./fail2ban-monitor.sh
Real-World Examples and Use Cases
Let’s look at some practical scenarios where Fail2ban proves invaluable:
Scenario 1: High-Traffic Web Server
A web server hosting multiple sites experiences constant SSH brute-force attempts. The default configuration might be too lenient. Here’s an aggressive setup:
[sshd-strict]
enabled = true
port = ssh
protocol = tcp
filter = sshd
logpath = /var/log/auth.log
maxretry = 2
bantime = 86400 # 24 hours
findtime = 300 # 5 minutes
action = iptables-multiport[name=SSH, port="ssh", protocol=tcp]
sendmail-whois[name=SSH, dest=admin@example.com]
Scenario 2: Development Server with Multiple Users
Development environments often have legitimate users who might mistype passwords. A more forgiving configuration:
[sshd-dev]
enabled = true
port = ssh
protocol = tcp
filter = sshd
logpath = /var/log/auth.log
maxretry = 5
bantime = 1800 # 30 minutes
findtime = 900 # 15 minutes
ignoreip = 127.0.0.1/8 10.0.0.0/8 192.168.0.0/16
Scenario 3: Multi-Service Protection
Protecting multiple services simultaneously:
[multi-service]
enabled = true
port = ssh,http,https,ftp
protocol = tcp
filter = multi-service
logpath = /var/log/auth.log
maxretry = 3
bantime = 7200
findtime = 600
Performance Comparison and Alternatives
Here’s how Fail2ban compares to other SSH protection methods:
Method | Resource Usage | Response Time | Configuration Complexity | Effectiveness |
---|---|---|---|---|
Fail2ban | Low (10-20MB RAM) | 1-5 seconds | Medium | High |
iptables rate limiting | Very Low (<1MB RAM) | Immediate | High | Medium |
SSH key-only auth | None | N/A | Low | Very High |
Port knocking | Low (5-10MB RAM) | Immediate | High | High |
Cloud-based WAF | None (server-side) | Immediate | Low | Very High |
Performance benchmarks on a typical VPS (2GB RAM, 2 CPU cores) show Fail2ban processing approximately 1000 log entries per second with minimal CPU impact (<2% CPU usage).
Advanced Configuration and Best Practices
For production environments, consider these advanced configurations:
Persistent Bans Database
By default, bans are cleared when Fail2ban restarts. To persist bans across restarts:
sudo nano /etc/fail2ban/jail.local
Add to the [DEFAULT] section:
[DEFAULT]
dbfile = /var/lib/fail2ban/fail2ban.sqlite3
dbpurgeage = 86400
Incremental Ban Times
Implement escalating ban times for repeat offenders:
[sshd-escalate]
enabled = true
port = ssh
protocol = tcp
filter = sshd
logpath = /var/log/auth.log
maxretry = 3
bantime.increment = true
bantime.factor = 2
bantime.formula = ban.Time * (1<<(ban.Count if ban.Count<20 else 20)) * banFactor
bantime.maxtime = 604800 # 1 week maximum
Geolocation-Based Filtering
Block entire countries known for hosting malicious activities:
sudo apt install geoip-bin geoip-database -y
Create a custom action:
sudo nano /etc/fail2ban/action.d/iptables-geoip.conf
[Definition]
actionstart = iptables -N f2b-
iptables -A f2b- -j RETURN
iptables -I -p -m multiport --dports -j f2b-
actionstop = iptables -D -p -m multiport --dports -j f2b-
iptables -F f2b-
iptables -X f2b-
actioncheck = iptables -n -L | grep -q 'f2b-[ \t]'
actionban = COUNTRY=$(geoiplookup | awk -F': ' '{print $2}' | awk -F',' '{print $1}')
if [ "$COUNTRY" = "China" ] || [ "$COUNTRY" = "Russia" ]; then
iptables -I f2b- 1 -s -j DROP
fi
actionunban = iptables -D f2b- -s -j DROP
Integration with External Services
Send alerts to Slack or Discord when bans occur:
sudo nano /etc/fail2ban/action.d/slack-notify.conf
[Definition]
actionstart =
actionstop =
actioncheck =
actionban = curl -X POST -H 'Content-type: application/json' --data '{"text":"π¨ Fail2ban: Banned IP for failures in jail "}'
actionunban =
[Init]
webhook_url = https://hooks.slack.com/services/YOUR/WEBHOOK/URL
Common Issues and Troubleshooting
Here are the most frequent issues and their solutions:
Issue 1: Fail2ban Not Starting
Check the configuration syntax:
sudo fail2ban-client -t
Common causes include invalid regex in custom filters or missing log files. Check the service logs:
sudo journalctl -u fail2ban -f
Issue 2: Legitimate Users Getting Banned
Add their IP ranges to the ignore list in jail.local
:
ignoreip = 127.0.0.1/8 ::1 YOUR.OFFICE.IP.RANGE/24
Or create a whitelist file:
sudo nano /etc/fail2ban/whitelist.conf
192.168.1.0/24
10.0.0.0/8
trusted-server.example.com
Reference it in your jail configuration:
ignoreip = 127.0.0.1/8 ::1
ignorecommand = /etc/fail2ban/whitelist.conf
Issue 3: Bans Not Working
Verify iptables integration:
sudo iptables -L -n | grep f2b
If no f2b chains appear, check if iptables is installed and accessible:
sudo apt install iptables -y
sudo which iptables
For systems using ufw, ensure compatibility:
sudo ufw status
sudo fail2ban-client set sshd addignoreip 127.0.0.1
Issue 4: High Memory Usage
Large log files can cause memory issues. Implement log rotation:
sudo nano /etc/logrotate.d/auth-log
/var/log/auth.log {
daily
missingok
rotate 7
compress
notifempty
create 0640 root root
postrotate
systemctl reload fail2ban
endscript
}
Issue 5: False Positives from Applications
Applications using SSH libraries might trigger false positives. Create custom ignore patterns:
sudo nano /etc/fail2ban/filter.d/sshd-custom.conf
[Definition]
failregex =
ignoreregex = ^%(__prefix_line)s.*from port \d+ ssh2: Connection closed by authenticating user myapp
For comprehensive monitoring and alerting, consider integrating with monitoring solutions like Prometheus or using the official Fail2ban documentation for advanced use cases.
Regular maintenance is crucial for optimal performance. Set up a monthly cron job to clean old entries:
sudo crontab -e
0 2 1 * * /usr/bin/fail2ban-client reload > /dev/null 2>&1
With these configurations and practices, your Ubuntu 24 server will have robust SSH protection against automated attacks while maintaining accessibility for legitimate users. Remember to regularly review logs and adjust configurations based on your specific traffic patterns and security requirements.

This article incorporates information and material from various online sources. We acknowledge and appreciate the work of all original authors, publishers, and websites. While every effort has been made to appropriately credit the source material, any unintentional oversight or omission does not constitute a copyright infringement. All trademarks, logos, and images mentioned are the property of their respective owners. If you believe that any content used in this article infringes upon your copyright, please contact us immediately for review and prompt action.
This article is intended for informational and educational purposes only and does not infringe on the rights of the copyright owners. If any copyrighted material has been used without proper credit or in violation of copyright laws, it is unintentional and we will rectify it promptly upon notification. Please note that the republishing, redistribution, or reproduction of part or all of the contents in any form is prohibited without express written permission from the author and website owner. For permissions or further inquiries, please contact us.