How to Set Up Fail2ban: Protect Your Server from Brute-Force Attacks
If you expose your home server to the internet, automated attacks will find it. Within minutes of opening SSH or a web service, bots start hammering your server with login attempts.
Fail2ban is your automated security guard. It monitors logs for suspicious activity (repeated failed logins, exploit attempts) and automatically bans offending IP addresses via firewall rules.
In this guide, you’ll learn to install and configure Fail2ban to protect SSH, web services, and more.
What is Fail2ban?
Fail2ban is a log-parsing application that:
- Monitors service logs (SSH, Nginx, Apache, etc.)
- Detects patterns indicating attacks (failed logins, exploit attempts)
- Bans malicious IPs by adding firewall rules (iptables/ufw)
- Unbans automatically after a timeout period
Example: After 3 failed SSH login attempts in 10 minutes, Fail2ban blocks the IP for 1 hour.
Why You Need It
Without Fail2ban, attackers can:
- Brute-force weak passwords (trying thousands of combinations)
- Launch dictionary attacks against SSH
- Exploit vulnerabilities by flooding services
- Consume bandwidth and CPU with automated scans
With Fail2ban:
- Bots get blocked after a few attempts
- Your logs stay clean
- Server resources stay free
- You get email alerts on suspicious activity
Installation
Ubuntu/Debian
sudo apt update
sudo apt install fail2ban -y
CentOS/RHEL/Rocky Linux
sudo yum install epel-release -y
sudo yum install fail2ban -y
Start and Enable
sudo systemctl start fail2ban
sudo systemctl enable fail2ban
sudo systemctl status fail2ban
You should see active (running).
Configuration Basics
Fail2ban uses two types of config files:
.conffiles - Defaults (don’t edit directly).localfiles - Your overrides (survive updates)
Main Config File
sudo cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local
sudo nano /etc/fail2ban/jail.local
This creates a local override that won’t get erased by updates.
Protecting SSH (Essential)
SSH is the #1 target. Let’s protect it first.
Default SSH Jail
Find the [sshd] section in /etc/fail2ban/jail.local:
[sshd]
enabled = true
port = ssh
filter = sshd
logpath = /var/log/auth.log # Debian/Ubuntu
# logpath = /var/log/secure # CentOS/RHEL
maxretry = 3
bantime = 1h
findtime = 10m
What this means:
enabled = true- SSH protection activeport = ssh- Monitor default port 22 (or custom port)maxretry = 3- Ban after 3 failed attemptsbantime = 1h- Keep IP banned for 1 hourfindtime = 10m- Count failures within 10-minute window
Custom SSH Port
If you changed SSH to port 2299:
[sshd]
enabled = true
port = 2299
filter = sshd
logpath = /var/log/auth.log
maxretry = 3
bantime = 1h
findtime = 10m
Restart Fail2ban
sudo systemctl restart fail2ban
Test It
From another machine, try logging in with wrong passwords:
ssh user@your-server # Enter wrong password 3 times
After 3 attempts, you’ll see:
Check the ban:
sudo fail2ban-client status sshd
Output:
Protecting Web Services
Nginx (General Protection)
Create /etc/fail2ban/jail.d/nginx.local:
[nginx-http-auth]
enabled = true
filter = nginx-http-auth
port = http,https
logpath = /var/log/nginx/error.log
maxretry = 5
bantime = 1h
findtime = 10m
[nginx-noscript]
enabled = true
filter = nginx-noscript
port = http,https
logpath = /var/log/nginx/access.log
maxretry = 6
bantime = 30m
[nginx-badbots]
enabled = true
filter = nginx-badbots
port = http,https
logpath = /var/log/nginx/access.log
maxretry = 2
bantime = 24h
[nginx-noproxy]
enabled = true
filter = nginx-noproxy
port = http,https
logpath = /var/log/nginx/access.log
maxretry = 2
bantime = 24h
Filters explained:
nginx-http-auth- Failed HTTP basic authnginx-noscript- Blocked scripts (.php, .asp, etc.)nginx-badbots- Known malicious user agentsnginx-noproxy- Proxy exploit attempts
Apache
[apache-auth]
enabled = true
port = http,https
filter = apache-auth
logpath = /var/log/apache2/error.log
maxretry = 5
bantime = 1h
[apache-badbots]
enabled = true
port = http,https
filter = apache-badbots
logpath = /var/log/apache2/access.log
maxretry = 2
bantime = 24h
Restart After Adding Jails
sudo systemctl restart fail2ban
Advanced Configuration
Whitelist Your IP
Never lock yourself out. Add to /etc/fail2ban/jail.local:
[DEFAULT]
ignoreip = 127.0.0.1/8 ::1 192.168.1.0/24 YOUR_PUBLIC_IP
Replace YOUR_PUBLIC_IP with your home/office IP.
Find your public IP:
curl ifconfig.me
Email Alerts
Get notified when IPs are banned.
Install mail utilities:
sudo apt install mailutils -y
Configure in /etc/fail2ban/jail.local:
[DEFAULT]
destemail = [email protected]
sendername = Fail2ban
action = %(action_mwl)s
action_mwl = ban + send email with logs.
Longer Ban Times for Repeat Offenders
Use the recidive jail to catch repeat attackers:
[recidive]
enabled = true
filter = recidive
logpath = /var/log/fail2ban.log
bantime = 1w
findtime = 1d
maxretry = 3
If an IP gets banned 3 times in 1 day, ban it for 1 week.
Permanent Bans
For persistent attackers, ban permanently:
sudo fail2ban-client set sshd banip 203.0.113.45 -1
-1 = permanent ban.
Protecting Docker Services
If you run Docker containers with exposed ports:
Nextcloud
[nextcloud]
enabled = true
filter = nextcloud
port = http,https
logpath = /var/log/nextcloud/nextcloud.log
maxretry = 3
bantime = 1h
Create filter /etc/fail2ban/filter.d/nextcloud.conf:
[Definition]
failregex = .*Login failed: '.*' \(Remote IP: '<HOST>'.*
ignoreregex =
Vaultwarden (Bitwarden)
[vaultwarden]
enabled = true
filter = vaultwarden
port = http,https
logpath = /path/to/vaultwarden/vaultwarden.log
maxretry = 3
bantime = 12h
Filter /etc/fail2ban/filter.d/vaultwarden.conf:
[Definition]
failregex = ^.*Username or password is incorrect\. Try again\. IP: <HOST>\. Username:.*$
ignoreregex =
Monitoring and Management
Check All Jail Status
sudo fail2ban-client status
Output:
Check Specific Jail
sudo fail2ban-client status sshd
View Banned IPs (All Jails)
sudo fail2ban-client banned
Unban an IP
sudo fail2ban-client unban 203.0.113.45
Or unban all:
sudo fail2ban-client unban --all
Check Logs
sudo tail -f /var/log/fail2ban.log
You’ll see entries like:
Testing Your Configuration
Test Filter Regex
sudo fail2ban-regex /var/log/auth.log /etc/fail2ban/filter.d/sshd.conf
Shows how many matches the filter found in your logs.
Simulate Attack (Safe)
From a different machine (not your main workstation):
for i in {1..5}; do ssh wronguser@your-server; done
Check if it got banned:
sudo fail2ban-client status sshd
Validate Config
sudo fail2ban-client -t
Shows configuration errors before restarting.
Firewall Integration
Fail2ban works with:
- iptables (default)
- ufw (Ubuntu)
- firewalld (CentOS)
- nftables
Check Current Bans (iptables)
sudo iptables -L -n | grep "reject-with"
Check Current Bans (ufw)
sudo ufw status numbered
Fail2ban adds rules like:
Performance Tips
Use Systemd Backend (Faster)
Modern distros can use systemd journal instead of log files:
[DEFAULT]
backend = systemd
Then specify journal tags:
[sshd]
enabled = true
filter = sshd[mode=aggressive]
journalmatch = _SYSTEMD_UNIT=sshd.service
maxretry = 3
Limit Log Scanning
For high-traffic servers, limit how far back Fail2ban looks:
[DEFAULT]
maxlines = 10000
Common Issues
“No jail defined” Error
Make sure jail is enabled = true and you restarted:
sudo systemctl restart fail2ban
Logs Not Found
Check log paths match your system:
ls -la /var/log/auth.log # Debian/Ubuntu
ls -la /var/log/secure # CentOS/RHEL
Accidentally Locked Yourself Out
Prevention: Always whitelist your IP in ignoreip.
Fix: Access via console (KVM/IPMI) or alternate IP, then unban:
sudo fail2ban-client unban YOUR_IP
Or disable Fail2ban temporarily:
sudo systemctl stop fail2ban
Filter Not Matching
Test regex against logs:
sudo fail2ban-regex /var/log/auth.log /etc/fail2ban/filter.d/sshd.conf --print-all-matched
Security Best Practices
- Use with SSH Keys - Fail2ban + key auth = nearly unbreakable
- Don’t Rely on Fail2ban Alone - It’s a layer, not a complete solution
- Monitor Logs - Check weekly for unusual ban patterns
- Update Filters - New exploits need new filters
- Whitelist Carefully - Don’t whitelist entire subnets unless necessary
Configuration Checklist
- Fail2ban installed and running
- SSH jail enabled with correct port
- Your IP whitelisted in
ignoreip - Web service jails configured (Nginx/Apache)
- Email alerts enabled (optional)
- Recidive jail for repeat offenders
- Tested with simulated attack
- Firewall rules verified (
iptables -Lorufw status) - Logs monitored (
/var/log/fail2ban.log)
What to Monitor
Weekly checks:
# Total bans
sudo fail2ban-client status | grep "Jail list"
# Top offending IPs
sudo zgrep "Ban " /var/log/fail2ban.log* | awk '{print $NF}' | sort | uniq -c | sort -rn | head -10
# Current banned IPs
sudo fail2ban-client banned
Beyond Fail2ban
For even stronger protection, combine with:
- Cloudflare - DDoS protection for web services
- GeoIP blocking - Block entire countries (if traffic is local-only)
- Port knocking - Hide SSH behind secret knock sequence
- VPN-only access - Don’t expose services publicly at all
Final Thoughts
Fail2ban is a must-have for any internet-facing server. It won’t stop sophisticated attacks, but it eliminates 99% of automated bot traffic.
Set it and forget it - Fail2ban quietly protects your server while you focus on building cool self-hosted services.
Next Steps:
- Securing Your Home Server: Essential Steps
- SSL Certificates for Self-Hosted Services (coming soon)
- VPN Options for Remote Access (coming soon)
Questions? Join our Discord community or drop a comment below.