BLOG POSTS
How to Protect SSH with Fail2Ban on Ubuntu 24

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.

Leave a reply

Your email address will not be published. Required fields are marked