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.
📑 Table of Contents
- How Fail2ban Works
- Installing Fail2ban
- On Ubuntu/Debian
- On RHEL/CentOS/AlmaLinux
- Configuration File Structure
- Basic Configuration
- Create jail.local
- Protecting SSH (sshd Jail)
- Aggressive SSH Protection
- Protecting Web Servers
- Apache Protection
- Nginx Protection
- Protecting Other Services
- MySQL/MariaDB
- Postfix (Mail Server)
- Dovecot (IMAP/POP3)
- WordPress (with custom filter)
- Managing Fail2ban
- Essential Commands
- Viewing Logs
- Advanced Configuration
- Progressive Banning (Recidive Jail)
- Custom Ban Times Based on Offense Count
- Whitelist Specific IPs
- Email Notifications
- Testing Your Configuration
- Test Filter Regex
- Simulate a Ban
- Performance Optimization
- Use Efficient Backend
- Optimize for High-Traffic Servers
- Fail2ban with Firewalld (RHEL/CentOS)
- Monitoring and Statistics
- Using fail2ban-client
- Create a Simple Report Script
- Troubleshooting
- Common Issues
- Complete Production Configuration
- Conclusion
How Fail2ban Works
Fail2ban operates by:
- Monitoring log files – Watches authentication logs, web server logs, etc.
- Matching patterns – Uses regex filters to identify failed attempts
- Counting failures – Tracks failed attempts per IP address
- 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.logfor ban activity - Use progressive banning for repeat offenders
- Combine with other security measures like SSH key authentication and firewalls
Was this article helpful?
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.