TL;DR: Fail2ban monitors log files for failed login attempts and automatically bans IP addresses that show malicious behavior. After 3-5 failed SSH attempts, the attacker's IP gets blocked by the firewall. This guide covers installation, SSH protection, custom jails for web services, and monitoring banned IPs.

What Is Fail2ban?

Fail2ban is an intrusion prevention framework that:

  • Monitors log files for failed authentication attempts
  • Detects patterns indicating brute force attacks
  • Automatically updates firewall rules to block attackers
  • Unbans IPs after a configurable time period

Why you need it: Any server exposed to the internet will receive constant automated login attempts. Check your SSH logs, you'll see hundreds of failed attempts from IPs around the world. Fail2ban turns reactive security into proactive defense.

How It Works

  1. Fail2ban watches log files (e.g., /var/log/auth.log)
  2. When it sees repeated failures from one IP, it triggers a "jail"
  3. The jail adds a firewall rule blocking that IP
  4. After the ban time expires, the IP is automatically unblocked

Installation

Debian/Ubuntu


sudo apt update
sudo apt install fail2ban -y
            

CentOS/RHEL/Fedora


sudo dnf install epel-release -y
sudo dnf install fail2ban -y
            

Start and Enable Service


sudo systemctl enable fail2ban
sudo systemctl start fail2ban
sudo systemctl status fail2ban
            

Configuration Basics

Fail2ban configuration lives in /etc/fail2ban/:

  • jail.conf, Default configuration (don't edit directly)
  • jail.local, Your custom overrides (create this)
  • jail.d/, Directory for individual jail configs
  • filter.d/, Regex patterns for detecting attacks
  • action.d/, What to do when attacks are detected

Important: Never edit jail.conf directly, updates will overwrite your changes. Always use jail.local or files in jail.d/.

Create jail.local


sudo cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local
sudo nano /etc/fail2ban/jail.local
            

Key Configuration Options

Option Default Description
bantime 10m How long to ban an IP
findtime 10m Time window for counting failures
maxretry 5 Failures before ban
ignoreip 127.0.0.1/8 IPs to never ban

Protecting SSH

SSH protection is typically enabled by default. Verify and customize:

Create SSH Jail Configuration


sudo nano /etc/fail2ban/jail.d/sshd.local
            

Add:

[sshd]
enabled = true
port = ssh
filter = sshd
logpath = /var/log/auth.log
backend = systemd

# Ban after 3 failed attempts within 10 minutes
maxretry = 3
findtime = 10m

# Ban for 1 hour
bantime = 1h

# Never ban these IPs (your home IP, etc.)
ignoreip = 127.0.0.1/8 ::1 192.168.1.0/24

Note: Replace 192.168.1.0/24 with your local network range to avoid accidentally banning yourself.

Apply Changes


sudo systemctl restart fail2ban
            

Verify SSH Jail Is Active


sudo fail2ban-client status sshd
            

Expected output:

Status for the jail: sshd
|- Filter
|  |- Currently failed: 0
|  |- Total failed:     0
|  `- File list:        /var/log/auth.log
`- Actions
   |- Currently banned: 0
   |- Total banned:     0
   `- Banned IP list:

Aggressive Protection Settings

For servers that don't need to be lenient:

[sshd]
enabled = true
port = ssh
filter = sshd
logpath = /var/log/auth.log
backend = systemd

# Very strict: 2 failures = ban
maxretry = 2
findtime = 10m

# Ban for 24 hours
bantime = 24h

# Increase ban time for repeat offenders
bantime.increment = true
bantime.multipliers = 1 5 30 60 1440
# 1st ban: 24h, 2nd: 5 days, 3rd: 30 days, 4th: 60 days, 5th+: permanent

ignoreip = 127.0.0.1/8 ::1 192.168.1.0/24

Custom Jails for Other Services

Nextcloud

Create filter:


sudo nano /etc/fail2ban/filter.d/nextcloud.conf
            

Add:

[Definition]
failregex = ^{"reqId":".*","level":2,"time":".*","remoteAddr":"<HOST>","user":".*","app":"core","method":".*","url":".*","message":"Login failed:.*$
            ^{"reqId":".*","level":2,"time":".*","remoteAddr":"<HOST>","user":".*","app":"core","method":".*","url":".*","message":"Trusted domain error.*$
datepattern = ,"time":"%%Y-%%m-%%dT%%H:%%M:%%S

Create jail:


sudo nano /etc/fail2ban/jail.d/nextcloud.local
            

Add:

[nextcloud]
enabled = true
port = 80,443
protocol = tcp
filter = nextcloud
logpath = /path/to/nextcloud/data/nextcloud.log
maxretry = 3
bantime = 1h
findtime = 10m

Nginx (Basic Auth)


sudo nano /etc/fail2ban/jail.d/nginx-auth.local
            

Add:

[nginx-http-auth]
enabled = true
port = http,https
filter = nginx-http-auth
logpath = /var/log/nginx/error.log
maxretry = 3
bantime = 1h
findtime = 10m

Apache

[apache-auth]
enabled = true
port = http,https
filter = apache-auth
logpath = /var/log/apache2/error.log
maxretry = 3
bantime = 1h
findtime = 10m

Monitoring and Management

View All Jail Status


sudo fail2ban-client status
            

View Specific Jail Details


sudo fail2ban-client status sshd
            

View Banned IPs


# All jails
sudo fail2ban-client banned

# Specific jail
sudo fail2ban-client status sshd | grep "Banned IP"
            

Manually Ban an IP


sudo fail2ban-client set sshd banip 123.123.123.123
            

Manually Unban an IP


sudo fail2ban-client set sshd unbanip 123.123.123.123
            

View Fail2ban Logs


sudo tail -f /var/log/fail2ban.log
            

Test a Filter (Debug)


# Test if filter catches log entries
sudo fail2ban-regex /var/log/auth.log /etc/fail2ban/filter.d/sshd.conf
            

Email Alerts (Optional)

Get notified when IPs are banned:


sudo nano /etc/fail2ban/jail.local
            

Add to [DEFAULT] section:

[DEFAULT]
destemail = [email protected]
sender = [email protected]
mta = sendmail
action = %(action_mwl)s

Note: Requires a working mail server (sendmail, postfix, or msmtp).

Fail2ban with Docker

Docker containers don't log to the host's log files by default. Options:

Option 1: Forward Docker Logs

Configure Docker to log to syslog:

# In /etc/docker/daemon.json
{
  "log-driver": "syslog",
  "log-opts": {
    "syslog-address": "unix:///dev/log"
  }
}

Option 2: Mount Log Files

In docker-compose.yml:

volumes:
  - /var/log/myapp:/var/log/myapp

Then point Fail2ban to /var/log/myapp/.

Option 3: Fail2ban in Docker

Run Fail2ban itself as a container with access to other container logs.

Best Practices

  1. Always whitelist your IP: Add your home/office IP to ignoreip to avoid locking yourself out
  2. Use key-based SSH: Fail2ban is a safety net, not a replacement for proper authentication
  3. Change default SSH port: Reduces noise from automated scans
  4. Start with lenient settings: Adjust as you understand normal traffic patterns
  5. Monitor regularly: Check banned IPs and logs weekly
  6. Keep Fail2ban updated: Security software needs updates too
  7. Test before production: Verify jails work as expected
  8. Have a backup access method: Console access in case you lock yourself out

Troubleshooting

Fail2ban Won't Start


# Check for config errors
sudo fail2ban-client -t

# View detailed errors
sudo journalctl -u fail2ban
            

IPs Not Being Banned

  • Verify the log file path is correct
  • Test filter with fail2ban-regex
  • Check jail is enabled: fail2ban-client status
  • Verify log timestamps match Fail2ban's expected format

Accidentally Banned Yourself

If you have console access:


sudo fail2ban-client set sshd unbanip YOUR_IP
            

Or stop Fail2ban temporarily:


sudo systemctl stop fail2ban
# Fix the issue
sudo systemctl start fail2ban
            

The Bottom Line

Fail2ban is essential for any internet-exposed server. It's lightweight, effective, and requires minimal maintenance once configured. The combination of Fail2ban with SSH key authentication and a non-standard port makes brute force attacks practically impossible.

Start with SSH protection. Once you're comfortable, add jails for other services. Monitor the logs periodically to understand attack patterns, you'll be surprised how many automated attacks target even small home servers.

References

  1. Fail2ban Official Wiki
  2. DigitalOcean, How to Protect SSH with Fail2ban
  3. Linode, Fail2ban for SSH Protection
  4. AvenaCloud, Fail2ban Ultimate 2025 Guide