/보안/When fail2ban Won't Ban IPs: A 5-Minute Diagnostic Guide for Banned: 0
Securityfail2banSSH 보안

When fail2ban Won't Ban IPs: A 5-Minute Diagnostic Guide for Banned: 0

When fail2ban isn't banning SSH brute-force IPs (Banned: 0), diagnose and fix the six common causes—from systemd backend and failregex through banaction—in five minutes with copy-paste commands.

When fail2ban Won't Ban IPs: A 5-Minute Diagnostic Guide for Banned: 0

When fail2ban Won't Ban IPs: A 5-Minute Diagnostic Guide for Banned: 0

SSH logs are filling up with hundreds of Failed password lines, but fail2ban-client status sshd shows Banned: 0. "I installed it and enabled it—why isn't it blocking?" This is a 5-minute diagnostic manual for exactly that situation. In practice, fail2ban "not blocking" almost always collapses to one of the six causes below. Follow along by copy-pasting the commands as-is.

1. Run these three diagnostic commands first

Before you guess at the cause, find out where the chain broke. Run these three in order.

Bash
# ① 전체 jail 목록 — sshd가 보이는가?
sudo fail2ban-client status

# ② sshd jail의 핵심 수치
sudo fail2ban-client status sshd

# ③ 서비스 상태와 에러/Found 로그
sudo systemctl status fail2ban
sudo journalctl -u fail2ban -e

In the status sshd output, the two numbers that matter are Total failed and Banned. Interpret them as follows.

SymptomInterpretationLikely cause
Total failed is climbing but Banned is 0Detection works, but the ban action isn't taking effectbanaction mismatch (④), ignoreip (⑤), thresholds (⑥)
Total failed stays at 0Stuck at log input or regex matchinglogpath/backend (①), failregex (③)
sshd is missing from status entirelyJail is not enabledjail.local not applied (②)

Hold this branching in your head and the rest is fast. Jump to the matching section below.

2. Cause ①: Can't read the logs (logpath / systemd backend)

Symptom: Total failed stays at 0. journalctl -u fail2ban shows messages like Failed to access socket path or Found no accessible config files for 'logpath'.

This is the #1 most common cause. Especially on Ubuntu 22.04/24.04 and RHEL 9, journald is the default instead of rsyslog, so /var/log/auth.log is empty or missing entirely. If fail2ban is pointed at a file that doesn't exist, of course it reads nothing.

Diagnosis:

Bash
# fail2ban이 실제로 어떤 로그를 보는지
sudo fail2ban-client get sshd logpath

# 배포판별 인증 로그 경로 (둘 중 하나)
ls -l /var/log/auth.log     # Debian/Ubuntu
ls -l /var/log/secure       # RHEL/CentOS/Rocky

# journald에 SSH 로그가 있는지
sudo journalctl -u ssh -n 50      # Ubuntu (서비스명 ssh)
sudo journalctl -u sshd -n 50     # RHEL  (서비스명 sshd)

Fix: If the file log is empty and logs only exist in journald, switch the backend to systemd.

INI
# /etc/fail2ban/jail.local
[sshd]
enabled = true
backend = systemd

To apply it globally, you can put backend = systemd in the [DEFAULT] block instead. After applying, verify the same way: check whether Total failed is climbing.

3. Cause ②: Jail isn't running (enabled=false / jail.local not applied)

Symptom: sshd is missing from the jail list in fail2ban-client status.

Diagnosis & fix: Never edit jail.conf directly. A package update will overwrite it. Put all custom settings in /etc/fail2ban/jail.local.

INI
# /etc/fail2ban/jail.local
[sshd]
enabled = true
Bash
# 설정 다시 읽기 (또는 재시작)
sudo fail2ban-client reload
# 안 먹으면
sudo systemctl restart fail2ban

# sshd가 목록에 떴는지 재확인
sudo fail2ban-client status

reload sometimes fails to pick up jail additions/removals. If you just turned enabled on and it still doesn't show up in the list, don't hesitate—just restart.

4. Cause ③: Detection isn't working (failregex mismatch)

Symptom: Logs are being read, but Total failed is 0. Cases have surged recently where OpenSSH 8.x → 9.x changed the log message format and older filters fail to match.

Diagnosis — Count matching lines yourself with fail2ban-regex.

Bash
# 파일 로그 백엔드일 때
sudo fail2ban-regex /var/log/auth.log /etc/fail2ban/filter.d/sshd.conf

# systemd 백엔드일 때
sudo fail2ban-regex "journalctl -u ssh -o short-iso" /etc/fail2ban/filter.d/sshd.conf

If matched is 0 in the Lines: ... matched at the end of the output, the regex isn't matching.

Fix: Raise the filter mode to aggressive, or upgrade the fail2ban package itself (newer filters support the 9.x format).

INI
# /etc/fail2ban/jail.local
[sshd]
enabled = true
mode = aggressive
backend = systemd
Bash
sudo apt update && sudo apt install --only-upgrade fail2ban   # Debian/Ubuntu
sudo dnf upgrade fail2ban                                     # RHEL 계열

5. Cause ④: Matching works, but bans don't (banaction mismatch)

Symptom: Total failed is climbing and Banned is climbing too, but the attacker keeps trying to connect. The firewall backend is mismatched. On systems where nftables is the default, using an iptables-based banaction puts rules in the wrong place and they have no effect.

Fix — Set the banaction that matches your environment in [DEFAULT].

INI
# /etc/fail2ban/jail.local
[DEFAULT]
# firewalld 환경 (RHEL 9 등)
banaction = firewallcmd-rich-rules
# ufw 환경 (Ubuntu)
# banaction = ufw
# 순수 iptables
# banaction = iptables-multiport
# nftables 직접
# banaction = nftables-multiport

Verify — Check whether the ban rules actually landed.

Bash
sudo iptables -L -n | grep f2b           # iptables
sudo nft list ruleset | grep f2b         # nftables
sudo firewall-cmd --list-all             # firewalld

If the rules don't show up, the banaction is wrong.

6. Causes ⑤ and ⑥: The ignoreip trap and thresholds

Cause ⑤ ignoreip: While adding test IPs or internal ranges, if you put something as broad as 0.0.0.0/0, everything is effectively excluded from bans. Or you add your own public IP and then test from that IP, and mistakenly conclude that "it isn't blocking."

INI
[DEFAULT]
ignoreip = 127.0.0.1/8 ::1 10.0.0.0/8   # 필요한 만큼만, 좁게

Cause ⑥ thresholds: findtime = 10m, maxretry = 5 means "ban after 5 failures within 10 minutes." If the attack comes in slowly, it never hits the threshold and never gets banned.

INI
[sshd]
findtime = 10m
maxretry = 5
bantime  = 1h

For testing, lower them—e.g. maxretry = 2, bantime = 5m—so you can verify quickly.

Isolating the action — The best trick for separating detection from the ban action is a manual ban.

Bash
sudo fail2ban-client set sshd banip 1.2.3.4
sudo iptables -L -n | grep 1.2.3.4   # 또는 nft / firewall-cmd

If a manual banip works but automatic bans don't → it's a detection problem (①②③). If even the manual ban doesn't work → it's a banaction problem (④).

A practitioner's note: Whenever I set up a new server, I always verify the action first with set sshd banip. Eighty percent of a 5-minute debug is just splitting "detection vs. ban"—and one manual banip line cuts that in half immediately. Two hours of wandering on Ubuntu 24.04 because I forgot backend = systemd is what built this habit.

7. Complete jail.local example and diagnostic flowchart

Copy-paste this and uncomment the line that matches your environment.

INI
# /etc/fail2ban/jail.local
[DEFAULT]
backend   = systemd
ignoreip  = 127.0.0.1/8 ::1
findtime  = 10m
maxretry  = 5
bantime   = 1h
# 방화벽 환경에 맞춰 하나만 활성화
banaction = firewallcmd-rich-rules   # firewalld
# banaction = ufw                    # ufw
# banaction = iptables-multiport     # 순수 iptables
# banaction = nftables-multiport     # nftables

[sshd]
enabled = true
mode    = aggressive
backend = systemd
port    = ssh

6-cause diagnostic flowchart

CODE
fail2ban-client status sshd
├─ sshd missing from status? ─────────→ ② jail.local enabled=true + restart
├─ Total failed = 0 ?
│    ├─ get sshd logpath / journalctl empty? → ① backend=systemd
│    └─ fail2ban-regex matched=0 ?           → ③ mode=aggressive / upgrade
└─ Total failed↑ but Banned=0 or still not blocked?
     ├─ set sshd banip 1.2.3.4 also not blocked? → ④ change banaction
     ├─ your IP / a broad range in ignoreip?     → ⑤ clean up ignoreip
     └─ threshold not reached?                   → ⑥ check findtime/maxretry

Prevention checklist: ⬜ backend matches the environment (journald or not) ⬜ settings only in jail.local ⬜ banaction matches the firewall backend ⬜ ignoreip kept minimal ⬜ package is up to date ⬜ after changes, verify with fail2ban-regex and a manual banip

Frequently asked questions (FAQ)

Q. Total failed is climbing but Banned is 0. A. Detection is fine; the ban action is misaligned. Check cause ④ (banaction), cause ⑤ (ignoreip), and the thresholds. Isolating the action with fail2ban-client set sshd banip is the fast path.

Q. I reloaded but the config didn't take effect. A. reload sometimes doesn't pick up jail additions/removals. Do a full restart with sudo systemctl restart fail2ban and confirm with fail2ban-client status.

Q. It says it's banned, but SSH still connects. A. Two things. Existing sessions stay up even after the firewall rule is added (only new connections are blocked). And if banaction doesn't match the actual firewall backend (nftables/firewalld/ufw), the rules are inert. Confirm the rules exist with iptables -L -n | grep f2b or equivalent.

Q. auth.log is empty on Ubuntu 22.04/24.04. A. With journald as the default, /var/log/auth.log is empty or gone. Switch to backend = systemd and confirm logs exist with journalctl -u ssh.

Q. Bans disappear after a reboot. A. That's close to expected behavior. Bans lift when bantime expires. If you need permanent bans, use bantime = -1 or incremental banning (bantime.increment = true).

확인 정보
✦ ✦ ✦
편집 검토 · Editorial Review

Nodelog는 모든 콘텐츠의 내용과 출처를 공개 전에 검토합니다. 환경(OS·버전)에 따라 결과가 달라질 수 있는 기술 정보는 공식 문서와 함께 확인하며, 검토 기준과 정정 원칙은 편집 정책에서 안내합니다. 오류를 발견하시면 이메일로 제보해 주세요 — 확인 후 신속히 정정합니다.

편집 책임 · Nodelog 기술 편집팀·발행 · ·업데이트 ·

Comments

Be the first to comment.