fail2ban Security Guide
fail2ban Security Guide
Section titled “fail2ban Security Guide”Last Updated: 2026-02-09 Server: Hetzner Production (46.224.40.5) Status: ✅ 5 Jails Active | 45+ IPs Banned
Overview
Section titled “Overview”fail2ban is our primary intrusion prevention system, protecting against brute-force attacks by monitoring logs and automatically banning malicious IPs.
┌─────────────────────────────────────────────────────────────┐│ ATTACK FLOW │├─────────────────────────────────────────────────────────────┤│ Attacker → SSH/HTTP → Log Entry → fail2ban → iptables BAN │└─────────────────────────────────────────────────────────────┘Quick Reference Card
Section titled “Quick Reference Card”Daily Monitoring Commands
Section titled “Daily Monitoring Commands”# Status overview (run this first)fail2ban-client status
# Check banned IPs in SSH jailfail2ban-client status sshd
# Live attack monitoring (keep this running)tail -f /var/log/fail2ban.log | grep --color -E "Ban|Found|Unban"
# Today's ban countgrep "Ban" /var/log/fail2ban.log | grep "$(date +%Y-%m-%d)" | wc -lEmergency Commands
Section titled “Emergency Commands”# Manually ban an IP immediatelyfail2ban-client set sshd banip 192.168.1.100
# Unban an IP (use cautiously)fail2ban-client set sshd unbanip 192.168.1.100
# Ban in nginx jailsfail2ban-client set nginx-botsearch banip 192.168.1.100
# Permanent ban via UFW (for persistent attackers)ufw insert 1 deny from 192.168.1.100 comment "Permanent ban - brute force"Current Configuration (Hardened 2026-02-09)
Section titled “Current Configuration (Hardened 2026-02-09)”Active Jails Summary
Section titled “Active Jails Summary”| Jail | Target | Max Retry | Find Time | Ban Time |
|---|---|---|---|---|
| sshd | SSH brute force | 2 | 1 hour | 1 week |
| recidive | Repeat offenders | 2 | 1 week | 30 days |
| nginx-http-auth | HTTP auth attacks | 3 | 10 min | 1 day |
| nginx-botsearch | Bot/scanner detection | 2 | 1 hour | 1 week |
| nginx-req-limit | Request flooding | 5 | 10 min | 1 day |
Configuration File
Section titled “Configuration File”Location: /etc/fail2ban/jail.local
# =============================================================================# fail2ban Configuration - iSu Technologies# Hardened SSH Protection (Updated 2026-02-09)# =============================================================================
[DEFAULT]bantime = 604800 # 1 week defaultfindtime = 3600 # 1 hour windowmaxretry = 3banaction = iptables-multiportignoreip = 127.0.0.1/8 46.224.40.5
# =============================================================================# SSH Protection - Aggressive (1 week ban on 2 failures)# =============================================================================[sshd]enabled = trueport = sshfilter = sshdbackend = systemdmaxretry = 2 # Very strict - 2 failuresbantime = 604800 # 1 week banfindtime = 3600 # 1 hour window
# =============================================================================# Recidive - Repeat Offenders (30 day ban)# =============================================================================[recidive]enabled = truefilter = recidivelogpath = /var/log/fail2ban.logbantime = 2592000 # 30 daysfindtime = 604800 # 1 week windowmaxretry = 2 # After 2 bans
# =============================================================================# Nginx Protection# =============================================================================[nginx-http-auth]enabled = trueport = http,httpsfilter = nginx-http-authlogpath = /var/log/nginx/error.logmaxretry = 3bantime = 86400 # 1 dayfindtime = 600 # 10 minutes
[nginx-botsearch]enabled = trueport = http,httpsfilter = nginx-botsearchlogpath = /var/log/nginx/access.logmaxretry = 2bantime = 604800 # 1 weekfindtime = 3600 # 1 hour
[nginx-req-limit]enabled = trueport = http,httpsfilter = nginx-limit-reqlogpath = /var/log/nginx/error.logmaxretry = 5bantime = 86400 # 1 dayfindtime = 600 # 10 minutesMonitoring Procedures
Section titled “Monitoring Procedures”Daily Check (Morning Routine)
Section titled “Daily Check (Morning Routine)”# 1. Check jail statusfail2ban-client status
# Expected output:# Status# |- Number of jail: 5# `- Jail list: nginx-botsearch, nginx-http-auth, nginx-req-limit, recidive, sshd
# 2. Check SSH jail specificsfail2ban-client status sshd
# 3. Check yesterday's activitygrep "$(date -d 'yesterday' +%Y-%m-%d)" /var/log/fail2ban.log | grep -c "Ban"Real-Time Monitoring
Section titled “Real-Time Monitoring”# Watch attacks live (recommended during incidents)tail -f /var/log/fail2ban.log | grep --color -E "Ban|Found|Unban|WARNING"
# Watch specific jailtail -f /var/log/fail2ban.log | grep sshd
# Count bans per IP (find persistent attackers)grep "Ban" /var/log/fail2ban.log | awk '{print $NF}' | sort | uniq -c | sort -rn | head -20Weekly Statistics
Section titled “Weekly Statistics”# Total bans this weekgrep "Ban" /var/log/fail2ban.log | grep -E "$(date -d '7 days ago' +%Y-%m-%d)|$(date -d '6 days ago' +%Y-%m-%d)|$(date -d '5 days ago' +%Y-%m-%d)|$(date -d '4 days ago' +%Y-%m-%d)|$(date -d '3 days ago' +%Y-%m-%d)|$(date -d '2 days ago' +%Y-%m-%d)|$(date -d '1 day ago' +%Y-%m-%d)|$(date +%Y-%m-%d)" | wc -l
# Top attackers (for permanent banning consideration)grep "Ban" /var/log/fail2ban.log | awk '{print $NF}' | sort | uniq -c | sort -rn | head -10
# Check recidive catchesfail2ban-client status recidiveManual Operations
Section titled “Manual Operations”Banning IPs
Section titled “Banning IPs”# Ban in SSH jail (most common)fail2ban-client set sshd banip <IP>
# Ban in all nginx jailsfail2ban-client set nginx-http-auth banip <IP>fail2ban-client set nginx-botsearch banip <IP>fail2ban-client set nginx-req-limit banip <IP>
# Permanent ban (for persistent attackers - survives restart)ufw insert 1 deny from <IP> comment "Permanent ban - reason here"Unbanning IPs
Section titled “Unbanning IPs”# Unban from specific jailfail2ban-client set sshd unbanip <IP>
# Unban from all jailsfail2ban-client unban <IP>
# Check if IP is bannedfail2ban-client banned | grep <IP>Whitelist Management
Section titled “Whitelist Management”# View current whitelistgrep ignoreip /etc/fail2ban/jail.local
# Add IP to whitelist (edit jail.local)# ignoreip = 127.0.0.1/8 46.224.40.5 YOUR_IP
# Reload after changessystemctl restart fail2banTroubleshooting
Section titled “Troubleshooting”Service Issues
Section titled “Service Issues”# Check service statussystemctl status fail2ban
# Test configuration (before restart)fail2ban-client -t
# View recent errorsjournalctl -u fail2ban --no-pager -n 50
# Restart servicesystemctl restart fail2banCommon Problems
Section titled “Common Problems”| Problem | Solution |
|---|---|
| ”No log file” error | Create log file: touch /var/log/fail2ban.log && chmod 640 /var/log/fail2ban.log |
| Jail not starting | Check filter exists: ls /etc/fail2ban/filter.d/ |
| Bans not working | Verify iptables chain: iptables -L f2b-sshd -n |
| Service won’t start | Check config: fail2ban-client -t |
Missing Log Files
Section titled “Missing Log Files”If log files are deleted (e.g., by attacker):
# Create fail2ban logtouch /var/log/fail2ban.logchmod 640 /var/log/fail2ban.logchown root:adm /var/log/fail2ban.log
# Create nginx logstouch /var/log/nginx/access.log /var/log/nginx/error.logchmod 640 /var/log/nginx/*.logchown www-data:adm /var/log/nginx/*.log
# Restart servicessystemctl restart fail2ban nginxEscalation: Permanent Bans
Section titled “Escalation: Permanent Bans”For IPs that repeatedly attack (caught by recidive multiple times), consider permanent UFW bans:
# Check top repeat offendersgrep "Ban" /var/log/fail2ban.log | awk '{print $NF}' | sort | uniq -c | sort -rn | head -10
# Permanent ban via UFW (example)ufw insert 1 deny from 192.168.1.100 comment "Permanent ban - 50+ attacks"
# Verify permanent bansufw status | grep "DENY"Integration with PLGT Stack
Section titled “Integration with PLGT Stack”fail2ban works alongside our observability stack:
| Feature | fail2ban | PLGT Stack |
|---|---|---|
| Block attacks | ✅ Yes | ❌ No |
| Detect attacks | ✅ Yes | ✅ Yes (Loki) |
| Historical analysis | Limited | ✅ Full (Grafana) |
| Multi-channel alerts | Basic | ✅ Advanced |
| Dashboard visualization | ❌ No | ✅ Yes |
Best Practice: Use both - fail2ban for active blocking, PLGT for deep analysis.
Quick Troubleshooting Checklist
Section titled “Quick Troubleshooting Checklist”- Service running?
systemctl status fail2ban - All 5 jails active?
fail2ban-client status - iptables chains exist?
iptables -L | grep f2b - Log files present?
ls -la /var/log/fail2ban.log - Configuration valid?
fail2ban-client -t - Nginx logs accessible?
ls -la /var/log/nginx/
Related Documentation
Section titled “Related Documentation”Last hardening: 2026-02-09 Maintainer: Nhlanhla Mnyandu (nhlanhla@isutech.co.za)