BLOG POSTS
How to Protect SSH with Fail2ban on Ubuntu 24

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.

Leave a reply

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