
How to Protect SSH with Fail2Ban on Ubuntu 24
Securing SSH access is critical for any server deployment, as SSH attacks are among the most common threats facing Linux servers today. Fail2Ban is a powerful intrusion prevention framework that analyzes log files and automatically bans IP addresses showing malicious behavior, making it an essential tool for protecting SSH services. In this guide, you’ll learn how to install, configure, and optimize Fail2Ban on Ubuntu 24 to create robust SSH protection, including advanced filtering rules, monitoring techniques, and troubleshooting common deployment issues.
How Fail2Ban Works
Fail2Ban operates by monitoring log files for patterns indicating malicious activity, then executing actions like firewall rules to block offending IP addresses. The system uses three core components:
- Filters – Regular expressions that parse log entries to identify suspicious patterns
- Actions – Commands executed when a filter triggers, typically iptables rules
- Jails – Configuration units combining filters and actions with specific parameters
When someone attempts to brute force your SSH service, Fail2Ban detects repeated authentication failures in /var/log/auth.log
, counts the attempts within a specified time window, and automatically adds firewall rules blocking the source IP. This automated response happens within seconds, effectively stopping attacks in progress.
The framework supports multiple backends including iptables, firewalld, and even cloud provider APIs, making it adaptable to various infrastructure setups. For most Ubuntu deployments, iptables integration provides the fastest response times with minimal system overhead.
Step-by-Step Installation and Configuration
Installing Fail2Ban on Ubuntu 24 is straightforward, but proper configuration requires attention to detail. Start with a fresh system update and installation:
sudo apt update && sudo apt upgrade -y
sudo apt install fail2ban -y
sudo systemctl enable fail2ban
sudo systemctl start fail2ban
Verify the installation and check the default status:
sudo systemctl status fail2ban
sudo fail2ban-client status
The default configuration files are located in /etc/fail2ban/
. Never modify jail.conf
directly as updates will overwrite your changes. Instead, create a local configuration file:
sudo cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local
sudo nano /etc/fail2ban/jail.local
Configure the basic SSH jail by modifying these key sections in jail.local
:
[DEFAULT]
# Ban hosts for 1 hour (3600 seconds)
bantime = 3600
# Consider failures over last 10 minutes (600 seconds)
findtime = 600
# Ban after 5 attempts
maxretry = 5
# Ignore local IP addresses
ignoreip = 127.0.0.1/8 ::1 192.168.1.0/24
[sshd]
enabled = true
port = ssh,22
filter = sshd
logpath = /var/log/auth.log
maxretry = 3
bantime = 7200
For enhanced SSH protection, create a custom filter for more aggressive detection. Create /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)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$
^%(__prefix_line)srefused connect from \S+ \(\)$
^%(__prefix_line)sReceived disconnect from : 11: Bye Bye$
^%(__prefix_line)sConnection closed by $
Apply the configuration and restart Fail2Ban:
sudo systemctl restart fail2ban
sudo fail2ban-client reload
Advanced Configuration and Monitoring
Beyond basic SSH protection, Fail2Ban offers sophisticated features for comprehensive server security. Configure email notifications by adding these parameters to your jail.local
:
[DEFAULT]
destemail = admin@yourdomain.com
sendername = Fail2Ban-Server
mta = sendmail
action = %(action_mwl)s
Monitor Fail2Ban activity using these essential commands:
# Check jail status
sudo fail2ban-client status sshd
# View banned IPs
sudo fail2ban-client get sshd banip
# Manually ban an IP
sudo fail2ban-client set sshd banip 192.168.1.100
# Unban an IP
sudo fail2ban-client set sshd unbanip 192.168.1.100
# View jail logs
sudo tail -f /var/log/fail2ban.log
For high-traffic servers, implement progressive banning with multiple jails. Create /etc/fail2ban/jail.d/progressive-sshd.local
:
[sshd-short]
enabled = true
filter = sshd
action = iptables[name=SSH, port=ssh, protocol=tcp]
logpath = /var/log/auth.log
maxretry = 3
findtime = 600
bantime = 3600
[sshd-long]
enabled = true
filter = sshd
action = iptables[name=SSH-LONG, port=ssh, protocol=tcp]
logpath = /var/log/auth.log
maxretry = 6
findtime = 86400
bantime = 604800
Performance Analysis and Comparison
Fail2Ban’s impact on system performance is minimal, but understanding the metrics helps optimize configurations. Here’s a comparison of different configuration approaches:
Configuration | CPU Usage | Memory (MB) | Response Time (ms) | Protection Level |
---|---|---|---|---|
Default SSH jail | 0.1% | 12-15 | 200-500 | Basic |
Aggressive filtering | 0.3% | 18-25 | 150-300 | High |
Progressive banning | 0.5% | 25-35 | 100-250 | Very High |
Multiple services | 1.2% | 45-60 | 300-600 | Comprehensive |
Compared to alternatives like DenyHosts or SSHGuard, Fail2Ban offers superior flexibility and integration options:
Feature | Fail2Ban | DenyHosts | SSHGuard |
---|---|---|---|
Multi-service support | Yes | SSH only | Limited |
Custom filters | Full regex support | Basic | Moderate |
Action flexibility | Unlimited | Host files only | Firewall only |
Unban mechanisms | Automatic/Manual | Manual only | Automatic only |
Real-World Use Cases and Examples
Development teams using VPS services often deploy Fail2Ban across multiple environments. A typical setup for a web development server includes protecting SSH, web applications, and database services simultaneously:
[nginx-http-auth]
enabled = true
filter = nginx-http-auth
port = http,https
logpath = /var/log/nginx/error.log
maxretry = 6
[nginx-noscript]
enabled = true
port = http,https
filter = nginx-noscript
logpath = /var/log/nginx/access.log
maxretry = 6
[mysql-auth]
enabled = true
filter = mysql-auth
port = 3306
logpath = /var/log/mysql/error.log
maxretry = 3
bantime = 86400
For production environments on dedicated servers, implement geolocation blocking combined with Fail2Ban. Install GeoIP support:
sudo apt install geoip-bin geoip-database -y
Create a custom action at /etc/fail2ban/action.d/iptables-geoip.conf
:
[Definition]
actionstart = iptables -N f2b-
iptables -A f2b- -j RETURN
iptables -I -p --dport -j f2b-
actionstop = iptables -D -p --dport -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 }' | head -n1)
iptables -I f2b- 1 -s -j
echo "$(date): Banned from $COUNTRY" >> /var/log/fail2ban-geoip.log
actionunban = iptables -D f2b- -s -j
Troubleshooting Common Issues
Several issues commonly arise during Fail2Ban deployment. Log file permissions problems often prevent proper monitoring:
# Fix auth.log permissions
sudo chmod 644 /var/log/auth.log
sudo chown root:adm /var/log/auth.log
# Restart rsyslog to ensure proper logging
sudo systemctl restart rsyslog
When Fail2Ban doesn’t detect attacks, verify your filter patterns match actual log entries:
# Test filter against logs
sudo fail2ban-regex /var/log/auth.log /etc/fail2ban/filter.d/sshd.conf
# Check for custom SSH ports
sudo grep "Port" /etc/ssh/sshd_config
If using non-standard SSH ports, update your jail configuration:
[sshd]
enabled = true
port = 2222
filter = sshd
logpath = /var/log/auth.log
For systemd-based logging systems, ensure Fail2Ban can access journal logs:
# Add fail2ban user to systemd-journal group
sudo usermod -a -G systemd-journal fail2ban
# Configure jail for systemd backend
[sshd]
enabled = true
filter = sshd
backend = systemd
maxretry = 3
Memory issues on resource-constrained systems can be resolved by optimizing the database backend:
[DEFAULT]
# Use SQLite instead of memory database
dbfile = /var/lib/fail2ban/fail2ban.sqlite3
dbpurgeage = 86400
Best Practices and Security Considerations
Implement whitelist management to prevent accidentally banning legitimate users. Create /etc/fail2ban/jail.d/whitelist.local
:
[DEFAULT]
ignoreip = 127.0.0.1/8
::1
192.168.0.0/16
10.0.0.0/8
172.16.0.0/12
your.office.ip.address
Regular maintenance ensures optimal performance. Set up automated log rotation and cleanup:
# Create maintenance script
cat > /usr/local/bin/fail2ban-maintenance.sh << 'EOF'
#!/bin/bash
# Clean old database entries
fail2ban-client unban --all
# Rotate logs if they exceed 100MB
find /var/log -name "fail2ban.log*" -size +100M -exec logrotate -f /etc/logrotate.d/fail2ban {} \;
# Check jail status and restart if needed
if ! fail2ban-client ping > /dev/null 2>&1; then
systemctl restart fail2ban
fi
EOF
chmod +x /usr/local/bin/fail2ban-maintenance.sh
# Add to crontab
echo "0 2 * * 0 /usr/local/bin/fail2ban-maintenance.sh" | sudo crontab -
Monitor Fail2Ban effectiveness with custom metrics collection. Install and configure a simple monitoring script:
#!/bin/bash
# Fail2Ban metrics collection
LOGFILE="/var/log/fail2ban-metrics.log"
DATE=$(date '+%Y-%m-%d %H:%M:%S')
BANNED_COUNT=$(fail2ban-client status sshd | grep "Currently banned" | awk '{print $4}')
TOTAL_BANNED=$(fail2ban-client status sshd | grep "Total banned" | awk '{print $4}')
echo "$DATE,ssh_currently_banned,$BANNED_COUNT" >> $LOGFILE
echo "$DATE,ssh_total_banned,$TOTAL_BANNED" >> $LOGFILE
For comprehensive security, integrate Fail2Ban with other protective measures. Consider implementing rate limiting at the SSH daemon level by adding these directives to /etc/ssh/sshd_config
:
MaxAuthTries 3
MaxSessions 2
ClientAliveInterval 300
ClientAliveCountMax 2
LoginGraceTime 60
Advanced users should explore the official Fail2Ban documentation at fail2ban.readthedocs.io for custom development and integration possibilities. The framework’s Python-based architecture allows for sophisticated extensions and custom actions beyond basic IP blocking.
Remember that Fail2Ban is one component of a comprehensive security strategy. Combine it with strong SSH key authentication, regular security updates, network segmentation, and monitoring solutions for maximum protection against modern attack vectors.

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.