How to Install and Configure Fail2ban on Linux: Complete Security Guide

Fail2ban is an intrusion prevention tool that protects your Linux server from brute-force attacks. It monitors log files for malicious activity and automatically bans IP addresses that show suspicious behavior. This guide covers installing, configuring, and optimizing Fail2ban on Ubuntu, Debian, RHEL, CentOS, and AlmaLinux.

How Fail2ban Works

Fail2ban operates by:

  1. Monitoring log files – Watches authentication logs, web server logs, etc.
  2. Matching patterns – Uses regex filters to identify failed attempts
  3. Counting failures – Tracks failed attempts per IP address
  4. Taking action – Bans IPs that exceed the threshold using iptables/nftables

Installing Fail2ban

On Ubuntu/Debian

# Update package index
sudo apt update

# Install Fail2ban
sudo apt install fail2ban -y

# Start and enable service
sudo systemctl start fail2ban
sudo systemctl enable fail2ban

# Verify installation
fail2ban-client version

On RHEL/CentOS/AlmaLinux

# Install EPEL repository
sudo dnf install epel-release -y

# Install Fail2ban
sudo dnf install fail2ban fail2ban-firewalld -y

# Start and enable service
sudo systemctl start fail2ban
sudo systemctl enable fail2ban

Configuration File Structure

Fail2ban configuration files are located in /etc/fail2ban/:

/etc/fail2ban/
├── fail2ban.conf      # Main configuration (don't edit directly)
├── jail.conf          # Default jail configurations (don't edit)
├── jail.local         # Your custom jail configurations
├── jail.d/            # Additional jail configs
├── filter.d/          # Filter definitions (regex patterns)
└── action.d/          # Action definitions (ban methods)

Important: Never edit jail.conf directly. Create jail.local to override settings – it won’t be overwritten during updates.

Basic Configuration

Create jail.local

sudo nano /etc/fail2ban/jail.local

Add the following base configuration:

[DEFAULT]
# Ban duration (10 minutes)
bantime = 10m

# Time window for counting failures
findtime = 10m

# Number of failures before ban
maxretry = 5

# Email notifications (optional)
destemail = admin@example.com
sender = fail2ban@example.com

# Action to take (ban and send email)
action = %(action_mwl)s

# Ignore local IPs
ignoreip = 127.0.0.1/8 ::1 192.168.1.0/24

# Backend for log monitoring
backend = auto

# Ban action (use firewalld on RHEL/CentOS)
banaction = iptables-multiport
# banaction = firewallcmd-ipset  # For firewalld

Protecting SSH (sshd Jail)

SSH is the most common target for brute-force attacks. Enable the sshd jail:

[sshd]
enabled = true
port = ssh
filter = sshd
logpath = /var/log/auth.log      # Ubuntu/Debian
# logpath = /var/log/secure      # RHEL/CentOS
maxretry = 3
bantime = 1h
findtime = 10m

Aggressive SSH Protection

For servers under heavy attack, use more aggressive settings:

[sshd-aggressive]
enabled = true
port = ssh
filter = sshd[mode=aggressive]
logpath = /var/log/auth.log
maxretry = 2
bantime = 24h
findtime = 1h

Protecting Web Servers

Apache Protection

# Block repeated authentication failures
[apache-auth]
enabled = true
port = http,https
filter = apache-auth
logpath = /var/log/apache2/*error.log
maxretry = 5

# Block bad bots and scanners
[apache-badbots]
enabled = true
port = http,https
filter = apache-badbots
logpath = /var/log/apache2/*access.log
maxretry = 2
bantime = 48h

# Block directory traversal attempts
[apache-noscript]
enabled = true
port = http,https
filter = apache-noscript
logpath = /var/log/apache2/*error.log
maxretry = 5

# Block PHP exploits
[apache-overflows]
enabled = true
port = http,https
filter = apache-overflows
logpath = /var/log/apache2/*error.log
maxretry = 2
bantime = 1h

Nginx Protection

# Block repeated 401/403 errors
[nginx-http-auth]
enabled = true
port = http,https
filter = nginx-http-auth
logpath = /var/log/nginx/*error.log
maxretry = 5

# Block bad bots
[nginx-badbots]
enabled = true
port = http,https
filter = nginx-badbots
logpath = /var/log/nginx/*access.log
maxretry = 2
bantime = 48h

# Block requests for non-existent files (scanners)
[nginx-noscript]
enabled = true
port = http,https
filter = nginx-noscript
logpath = /var/log/nginx/*access.log
maxretry = 6

Protecting Other Services

MySQL/MariaDB

[mysqld-auth]
enabled = true
port = 3306
filter = mysqld-auth
logpath = /var/log/mysql/error.log
maxretry = 5
bantime = 1h

Postfix (Mail Server)

[postfix]
enabled = true
port = smtp,465,submission
filter = postfix
logpath = /var/log/mail.log
maxretry = 5

[postfix-sasl]
enabled = true
port = smtp,465,submission,imap,imaps,pop3,pop3s
filter = postfix-sasl
logpath = /var/log/mail.log
maxretry = 3
bantime = 1h

Dovecot (IMAP/POP3)

[dovecot]
enabled = true
port = pop3,pop3s,imap,imaps
filter = dovecot
logpath = /var/log/mail.log
maxretry = 5

WordPress (with custom filter)

Create a custom filter for WordPress login attacks:

sudo nano /etc/fail2ban/filter.d/wordpress.conf
[Definition]
failregex = ^<HOST> .* "POST /wp-login.php
            ^<HOST> .* "POST /xmlrpc.php
ignoreregex =

Add the jail:

[wordpress]
enabled = true
port = http,https
filter = wordpress
logpath = /var/log/nginx/access.log
          /var/log/apache2/access.log
maxretry = 5
findtime = 5m
bantime = 1h

Managing Fail2ban

Essential Commands

# Check Fail2ban status
sudo fail2ban-client status

# Check specific jail status
sudo fail2ban-client status sshd

# View banned IPs for a jail
sudo fail2ban-client get sshd banip

# Manually ban an IP
sudo fail2ban-client set sshd banip 192.168.1.100

# Manually unban an IP
sudo fail2ban-client set sshd unbanip 192.168.1.100

# Reload configuration
sudo fail2ban-client reload

# Reload specific jail
sudo fail2ban-client reload sshd

# Stop/Start Fail2ban
sudo systemctl stop fail2ban
sudo systemctl start fail2ban

Viewing Logs

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

# View recent bans
sudo grep "Ban" /var/log/fail2ban.log | tail -20

# Count bans per jail
sudo grep "Ban" /var/log/fail2ban.log | awk '{print $6}' | sort | uniq -c

# View banned IPs with timestamps
sudo awk '/Ban/{print $1,$2,$7}' /var/log/fail2ban.log | tail -20

Advanced Configuration

Progressive Banning (Recidive Jail)

Ban repeat offenders for longer periods:

[recidive]
enabled = true
filter = recidive
logpath = /var/log/fail2ban.log
action = %(action_mwl)s
bantime = 1w
findtime = 1d
maxretry = 3

Custom Ban Times Based on Offense Count

Use the bantime.increment feature (Fail2ban 0.11+):

[DEFAULT]
# Enable ban time increment
bantime.increment = true

# Multiplier for each subsequent ban
bantime.factor = 2

# Maximum ban time (1 week)
bantime.maxtime = 1w

# Formula: bantime * (1, 2, 4, 8, 16...)
bantime.formula = ban.Time * (1<<(ban.Count if ban.Count<20 else 20)) * banFactor

Whitelist Specific IPs

[DEFAULT]
# Never ban these IPs
ignoreip = 127.0.0.1/8
           ::1
           192.168.1.0/24
           10.0.0.0/8
           your.office.ip.address

Email Notifications

Get notified when IPs are banned:

[DEFAULT]
destemail = admin@example.com
sender = fail2ban@yourserver.com
mta = sendmail

# Action with email (includes whois info and log lines)
action = %(action_mwl)s

Testing Your Configuration

Test Filter Regex

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

# Test with verbose output
sudo fail2ban-regex /var/log/auth.log /etc/fail2ban/filter.d/sshd.conf --print-all-matched

Simulate a Ban

# Generate failed SSH login (from another machine)
ssh invalid_user@your_server

# Check if it was detected
sudo fail2ban-client status sshd

Performance Optimization

Use Efficient Backend

[DEFAULT]
# Use systemd journal (recommended for systemd systems)
backend = systemd

# Or use pyinotify for file monitoring (most efficient)
backend = pyinotify

Optimize for High-Traffic Servers

[DEFAULT]
# Use ipset for faster IP lookups (handles thousands of IPs)
banaction = iptables-ipset-proto6

# Or use nftables with sets
banaction = nftables-multiport

Fail2ban with Firewalld (RHEL/CentOS)

For systems using firewalld:

[DEFAULT]
banaction = firewallcmd-ipset

Or create a rich rule action:

[DEFAULT]
banaction = firewallcmd-rich-rules

Monitoring and Statistics

Using fail2ban-client

# Overall statistics
sudo fail2ban-client status

# Detailed jail stats
sudo fail2ban-client status sshd

# Currently banned count
sudo fail2ban-client get sshd banip | wc -w

Create a Simple Report Script

#!/bin/bash
# /usr/local/bin/fail2ban-report.sh

echo "=== Fail2ban Status Report ==="
echo "Date: $(date)"
echo ""

for jail in $(fail2ban-client status | grep "Jail list" | sed 's/.*://;s/,//g'); do
    echo "--- $jail ---"
    fail2ban-client status $jail | grep -E "(Currently|Total)"
done

echo ""
echo "=== Recent Bans ==="
grep "Ban" /var/log/fail2ban.log | tail -10

Troubleshooting

Common Issues

Issue: Fail2ban not banning IPs

# Check if jail is enabled
sudo fail2ban-client status

# Verify log path exists
ls -la /var/log/auth.log

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

Issue: Accidentally banned yourself

# Unban from specific jail
sudo fail2ban-client set sshd unbanip YOUR_IP

# Or flush all bans
sudo fail2ban-client unban --all

Issue: Configuration errors

# Verify configuration syntax
sudo fail2ban-client -d

# Check for errors in logs
sudo journalctl -u fail2ban -f

Complete Production Configuration

Here's a comprehensive /etc/fail2ban/jail.local for a web server:

[DEFAULT]
ignoreip = 127.0.0.1/8 ::1 YOUR_OFFICE_IP
bantime = 1h
findtime = 10m
maxretry = 5
backend = auto
banaction = iptables-multiport

[sshd]
enabled = true
port = ssh
filter = sshd
logpath = /var/log/auth.log
maxretry = 3
bantime = 24h

[sshd-ddos]
enabled = true
port = ssh
filter = sshd-ddos
logpath = /var/log/auth.log
maxretry = 10
findtime = 30
bantime = 1h

[nginx-http-auth]
enabled = true
port = http,https
filter = nginx-http-auth
logpath = /var/log/nginx/*error.log
maxretry = 5

[nginx-badbots]
enabled = true
port = http,https
filter = apache-badbots
logpath = /var/log/nginx/*access.log
maxretry = 2
bantime = 48h

[recidive]
enabled = true
filter = recidive
logpath = /var/log/fail2ban.log
bantime = 1w
findtime = 1d
maxretry = 3

Conclusion

Fail2ban is essential for protecting Linux servers from automated attacks. Start with basic SSH protection, then gradually add jails for other services. Monitor your logs regularly to identify attack patterns and adjust your configuration accordingly.

Remember to:

  • Always whitelist your own IP addresses
  • Test configurations before applying to production
  • Monitor /var/log/fail2ban.log for ban activity
  • Use progressive banning for repeat offenders
  • Combine with other security measures like SSH key authentication and firewalls

Was this article helpful?

R

About Ramesh Sundararamaiah

Red Hat Certified Architect

Expert in Linux system administration, DevOps automation, and cloud infrastructure. Specializing in Red Hat Enterprise Linux, CentOS, Ubuntu, Docker, Ansible, and enterprise IT solutions.

🐧 Stay Updated with Linux Tips

Get the latest tutorials, news, and guides delivered to your inbox weekly.

Add Comment