sudo fail2ban-client status nginx-botsearchwhy-banned <ip_address_in_question>If you run fail2ban in front of a public-facing service, you'll eventually want to answer questions like "why was this IP banned?", "what did they try?", or "which scanners are hitting me hardest this week?". The good news: fail2ban already logs everything you need. You just have to know how to ask.
This post collects a handful of one-liners I keep coming back to when investigating ban activity on an nginx server. They assume a setup with fail2ban tailing nginx access logs, but the patterns work for any jail.
198.51.100.0/24 (TEST-NET-2)&& 203.0.113.0/24 (TEST-NET-3) which is an RFC 5737 documentation address (reserved, can never be a real server IP — same idea as 192.168.x.x but for examples).When you see a banned IP and want to know what it did, you need two pieces of information:
fail2ban writes its activity to /var/log/fail2ban.log. Each match gets a Found line with a timestamp, and each ban gets a Ban line. Cross-referencing those timestamps against your access log tells you exactly which requests triggered the action.
The simplest query: what's been happening lately?
sudo grep -E "Ban |Found " /var/log/fail2ban.log | tail -20This shows the last 20 events across all jails. You'll see lines like:
[nginx-botsearch] Found 198.51.100.42 - 2026-05-20 15:07:04
[nginx-botsearch] Ban 198.51.100.42The Found line is the filter matching a log entry. The Ban line is fail2ban actually taking action (which happens once maxretry is exceeded within findtime).
Once you have an IP of interest, pull everything related to it from both logs:
sudo grep "198.51.100.42" /var/log/fail2ban.log /var/log/nginx-proxy/access.log*You'll get the full story: each fail2ban event, plus every request that IP made (across rotated access logs too, since the * glob picks up access.log.1, etc.).
For compressed rotated logs, add a zgrep pass:
sudo zgrep "198.51.100.42" /var/log/nginx-proxy/access.log.*.gzWant to know which scanners are the most persistent? Aggregate by IP and sort by frequency:
sudo grep "Ban " /var/log/fail2ban.log | awk '{print $NF}' | sort | uniq -c | sort -rn | head -20Output looks like:
4 198.51.100.42
3 198.51.100.43
2 203.0.113.47
1 203.0.113.182The number on the left is how many times that IP has been banned. Repeat offenders show up at the top — useful if you want to consider a longer ban time for chronic abusers (or feed them into a recidive jail).
fail2ban exposes a one-shot summary of who's currently in the doghouse:
sudo fail2ban-client bannedThis shows banned IPs grouped by jail. Much faster than grepping the log when you just want to know "is this IP currently blocked?"
For per-jail detail (including filter stats and recent ban history):
sudo fail2ban-client status nginx-botsearchIf you find yourself running the cross-reference query often, drop it in a script:
sudo tee /usr/local/bin/why-banned > /dev/null <<'EOF'
#!/bin/bash
# Usage: why-banned <ip>
ip="$1"
if [ -z "$ip" ]; then
echo "Usage: why-banned <ip>"
exit 1
fi
echo "=== fail2ban events ==="
sudo grep "$ip" /var/log/fail2ban.log
echo
echo "=== nginx access entries ==="
sudo grep "$ip" /var/log/nginx-proxy/access.log* 2>/dev/null
sudo zgrep "$ip" /var/log/nginx-proxy/access.log.*.gz 2>/dev/null
EOF
sudo chmod +x /usr/local/bin/why-bannedThen any time you see a banned IP and wonder what happened:
why-banned 198.51.100.42You get the full story in one shot: every fail2ban event for that IP, plus every request it made across both live and rotated logs.
For interactive use, add these to ~/.bashrc or ~/.zshrc:
alias f2b-recent='sudo grep -E "Ban |Found " /var/log/fail2ban.log | tail -20'
alias f2b-top='sudo grep "Ban " /var/log/fail2ban.log | awk "{print \$NF}" | sort | uniq -c | sort -rn | head -20'
alias f2b-banned='sudo fail2ban-client banned'The commands above assume:
/var/log/fail2ban.log (the default on Debian/Ubuntu)/var/log/nginx-proxy/access.log with rotated copies in the same directoryIf your paths differ (e.g., /var/log/nginx/access.log for a non-containerized nginx), substitute accordingly. The patterns themselves don't change.
Bans aren't fire-and-forget. Periodically reviewing what's getting banned helps you spot:
The data has been there the whole time. These queries just make it easy to surface.