Install and configure Fail2ban with advanced rules and email alerts

Intermediate 45 min Apr 01, 2026 22 views
Ubuntu 24.04 Ubuntu 22.04 Debian 12 AlmaLinux 9 Rocky Linux 9 Fedora 41

Set up Fail2ban intrusion prevention system with custom SSH, web server, and application protection rules. Configure email notifications and advanced filtering to automatically block malicious IP addresses based on log patterns.

Prerequisites

  • Root or sudo access
  • Active SSH service
  • Basic understanding of log files
  • Email server or SMTP access for notifications

What this solves

Fail2ban protects your server from brute force attacks and malicious access attempts by monitoring log files and automatically blocking suspicious IP addresses. This tutorial covers advanced configurations including custom jails for SSH, web servers, email alerts, and whitelist management for production environments.

Step-by-step installation

Update system packages

Start by updating your package manager to ensure you get the latest security patches and dependencies.

sudo apt update && sudo apt upgrade -y
sudo dnf update -y

Install Fail2ban and required dependencies

Install Fail2ban along with mail utilities for email notifications and additional filtering tools.

sudo apt install -y fail2ban sendmail iptables-persistent whois
sudo dnf install -y fail2ban sendmail iptables-services whois

Create main configuration file

Create a local configuration file to override default settings. Never edit the main jail.conf file directly as updates will overwrite your changes.

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

Configure basic Fail2ban settings

Edit the main configuration file with your preferred settings for ban times, retry attempts, and email notifications.

[DEFAULT]

Ban hosts for 24 hours (86400 seconds)

bantime = 86400

Number of failures before a host gets banned

maxretry = 5

Time frame in which failures are counted (10 minutes)

findtime = 600

Backend for storing ban information

backend = systemd

Destination email for notifications

destemail = admin@example.com

Sender email address

sender = fail2ban@example.com

Email subject line

subject = [Fail2ban] %(name)s: banned %(ip)s from %(fq-hostname)s

Enable email notifications

action = %(action_mwl)s

Whitelist your IP addresses (replace with your actual IPs)

ignoreip = 127.0.0.1/8 ::1 203.0.113.10/32

Custom ban action with detailed logging

banaction = iptables-multiport banaction_allports = iptables-allports

Configure SSH protection jail

Add enhanced SSH protection with custom settings for port and log monitoring. This jail monitors both password and key-based authentication failures.

[sshd]
enabled = true
port = 22
filter = sshd
logpath = /var/log/auth.log
maxretry = 3
bantime = 3600
findtime = 300

Advanced SSH filter with additional patterns

[sshd-aggressive] enabled = true port = 22 filter = sshd-aggressive logpath = /var/log/auth.log maxretry = 2 bantime = 86400 findtime = 600

Create custom SSH filter

Create an aggressive SSH filter that catches more attack patterns including connection drops and invalid users.

[Definition]

Aggressive SSH filter that catches multiple attack patterns

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 (?:password|publickey) for . from (?: port \d)?(?: ssh\d*)?$ ^%(__prefix_line)sROOT LOGIN REFUSED. FROM \s$ ^%(__prefix_line)siI user . from \s$ ^%(__prefix_line)sUser .+ from not allowed because not listed in AllowUsers\s*$ ^%(__prefix_line)srefused connect from \S+ \(\)\s*$ ^%(__prefix_line)sConnection closed by .\[preauth\]\s$ ^%(__prefix_line)sConnection from .on unused port\s$ ignoreregex = [Init]

Read common prefixes

journalmatch = _SYSTEMD_UNIT=sshd.service + _COMM=sshd

Configure web server protection

Add protection for Nginx and Apache web servers against common attacks like 404 flooding and authentication failures.

# Nginx protection
[nginx-http-auth]
enabled = true
filter = nginx-http-auth
logpath = /var/log/nginx/error.log
maxretry = 3
bantime = 3600

[nginx-noscript]
enabled = true
filter = nginx-noscript
logpath = /var/log/nginx/access.log
maxretry = 6
bantime = 86400

[nginx-badbots]
enabled = true
filter = nginx-badbots
logpath = /var/log/nginx/access.log
maxretry = 2
bantime = 86400

[nginx-noproxy]
enabled = true
filter = nginx-noproxy
logpath = /var/log/nginx/access.log
maxretry = 2
bantime = 86400

Apache protection

[apache-auth] enabled = true filter = apache-auth logpath = /var/log/apache2/error.log maxretry = 3 bantime = 3600 [apache-badbots] enabled = true filter = apache-badbots logpath = /var/log/apache2/access.log maxretry = 2 bantime = 86400 [apache-noscript] enabled = true filter = apache-noscript logpath = /var/log/apache2/access.log maxretry = 6 bantime = 86400

Create custom web attack filter

Create a filter to detect common web application attacks including SQL injection attempts and directory traversal.

[Definition]

Custom filter for detecting web application attacks

failregex = ^ -.\"(GET|POST|PUT|DELETE).\\x.\" (4[0-9][0-9]|5[0-9][0-9]).$ ^ -.\"(GET|POST).(union|select|insert|drop|delete|update|script|alert).\" (4[0-9][0-9]|5[0-9][0-9]).$ ^ -.\"(GET|POST).\\.\\./.\" (4[0-9][0-9]|5[0-9][0-9]).$ ^ -.\"(GET|POST).(eval|exec|system|passthru).\" (4[0-9][0-9]|5[0-9][0-9]).$ ^ -.\" 40[4-9] .$ ignoreregex =

Configure email notifications

Set up detailed email notifications with custom templates that include attack information and geographic data.

[Definition]

Custom email action with enhanced information

actionstart = printf %%b "Hi,\n The jail has been started successfully.\n Regards,\n Fail2Ban" | mail -s "[Fail2Ban] : started on hostname" actionstop = printf %%b "Hi,\n The jail has been stopped.\n Regards,\n Fail2Ban" | mail -s "[Fail2Ban] : stopped on hostname" actioncheck = actionban = printf %%b "Hi,\n The IP has just been banned by Fail2Ban after attempts against on hostname.\n\n Lines containing IP: in \n grep '' | tail -20\n\n WHOIS information for :\n whois | head -20\n\n Regards,\n Fail2Ban" | mail -s "[Fail2Ban] : banned from hostname" actionunban = printf %%b "Hi,\n The IP has just been unbanned by Fail2Ban.\n\n Regards,\n Fail2Ban" | mail -s "[Fail2Ban] : unbanned from hostname" [Init] name = default dest = root logpath = /var/log/fail2ban.log

Enable and start Fail2ban service

Start the Fail2ban service and enable it to start automatically on system boot.

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

Configure firewall persistence

Ensure that Fail2ban rules persist across reboots and integrate properly with your firewall configuration.

sudo systemctl enable netfilter-persistent
sudo netfilter-persistent save
sudo systemctl enable iptables
sudo service iptables save

Advanced configuration and monitoring

Set up log rotation

Configure log rotation for Fail2ban to prevent log files from consuming excessive disk space.

/var/log/fail2ban.log {
    daily
    missingok
    rotate 30
    compress
    delaycompress
    postrotate
        /usr/bin/fail2ban-client flushlogs >/dev/null 2>&1 || true
    endscript
    create 640 root adm
}

Create monitoring script

Create a monitoring script to track Fail2ban performance and generate daily reports.

#!/bin/bash

Fail2ban daily report script

echo "=== Fail2ban Daily Report - $(date) ===" echo "" echo "Active Jails:" fail2ban-client status echo "" for jail in $(fail2ban-client status | grep "Jail list:" | cut -d: -f2 | sed 's/,//g'); do echo "=== $jail jail status ===" fail2ban-client status $jail echo "" done echo "Recent ban activity (last 24 hours):" grep "Ban " /var/log/fail2ban.log | grep "$(date --date='1 day ago' '+%Y-%m-%d')\|$(date '+%Y-%m-%d')" echo "" echo "Top 10 banned IPs:" grep "Ban " /var/log/fail2ban.log | awk '{print $7}' | sort | uniq -c | sort -nr | head -10

Make monitoring script executable

Set correct permissions for the monitoring script and add it to daily cron jobs.

sudo chmod 755 /usr/local/bin/fail2ban-report.sh
sudo ln -s /usr/local/bin/fail2ban-report.sh /etc/cron.daily/fail2ban-report
Warning: Never use chmod 777 on configuration files or scripts. The 755 permission gives read and execute access to everyone while maintaining write access only for root, which is appropriate for system scripts.

Testing and validation

Test SSH jail functionality

Test your SSH jail by attempting failed logins from another system or using a test account.

# Check if fail2ban is monitoring SSH
sudo fail2ban-client status sshd

Monitor live logs during testing

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

Test email notifications

Send a test email notification to verify your email configuration is working.

# Test mail system
echo "Test email from fail2ban" | mail -s "Test Email" admin@example.com

Check mail logs

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

Verify your setup

# Check Fail2ban service status
sudo systemctl status fail2ban

List all active jails

sudo fail2ban-client status

Check specific jail status

sudo fail2ban-client status sshd

View recent Fail2ban activity

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

Check current iptables rules created by Fail2ban

sudo iptables -L -n | grep fail2ban

Test configuration syntax

sudo fail2ban-client -t

Performance optimization

Optimize log processing

Configure Fail2ban to process logs more efficiently for high-traffic servers by adjusting polling intervals and backend settings.

[DEFAULT]

Optimize for high-traffic servers

backend = systemd

Reduce polling interval for faster detection

logencoding = auto

Use systemd journal for better performance

journalmatch = _SYSTEMD_UNIT=sshd.service

Configure database backend

Use SQLite database backend for better performance with large numbers of IPs and persistent storage.

[DEFAULT]

Use database backend for better performance

dbfile = /var/lib/fail2ban/fail2ban.sqlite3 dbpurgeage = 1d

Managing whitelists and permanent bans

Manage IP whitelist

Add trusted IP addresses to prevent them from being banned, including office networks and monitoring systems.

# Add IP to whitelist permanently (edit jail.local)
sudo nano /etc/fail2ban/jail.local

Add to ignoreip line: 203.0.113.0/24

Unban specific IP immediately

sudo fail2ban-client set sshd unbanip 203.0.113.50

Reload Fail2ban configuration

sudo fail2ban-client reload

Create permanent ban list

Set up a permanent ban list for repeat offenders and known malicious IP ranges.

# Permanent IP blacklist - one IP per line

Known attackers

198.51.100.5 198.51.100.0/24

Tor exit nodes (example)

203.0.113.100 203.0.113.101

Apply permanent blacklist

Create a jail that monitors the blacklist file and permanently bans listed IPs.

[blacklist]
enabled = true
filter = blacklist
action = iptables-allports[name=blacklist]
logpath = /etc/fail2ban/ip.blacklist
maxretry = 1
bantime = -1
findtime = 31536000

Integration with monitoring systems

For comprehensive server monitoring, consider integrating Fail2ban logs with Grafana and Prometheus monitoring setup. You can also secure your web applications further by implementing NGINX with modern security headers alongside Fail2ban protection.

Common issues

SymptomCauseFix
Fail2ban won't startConfiguration syntax errorsudo fail2ban-client -t to check config syntax
Email notifications not workingMail system not configuredInstall and configure sendmail: sudo apt install sendmail
Rules not blocking IPsWrong log file path or formatCheck log paths in jail config match actual log locations
Self-lockout from SSHIP not in whitelistAdd your IP to ignoreip in jail.local and reboot server
High CPU usageToo frequent log pollingIncrease findtime and reduce log polling frequency
Bans not persistentFirewall rules not savedRun sudo netfilter-persistent save on Ubuntu/Debian
Systemd journal errorsWrong journalmatch filterVerify service names: systemctl list-units | grep ssh

Next steps

Automated install script

Run this to automate the entire setup

#fail2ban #ssh-security #brute-force-protection #email-alerts #intrusion-prevention

Need help?

Don't want to manage this yourself?

We handle infrastructure for businesses that depend on uptime. From initial setup to ongoing operations.

Talk to an engineer