Repository navigation
10 Fail2Ban SSH Mail FTP
Service jails differ from web jails: the evidence is authentication failures, the thresholds must tolerate humans, and a false positive can lock out an administrator or a mail client.
Measured on the reference host over ~3.5 days: 8,070 Failed password and 3,581
Invalid user events from 507 unique IPs, with usernames targeted by name
(ubuntu, admin, and even the hostname and domain names of the server). SSH is the most
attacked service on any public Linux host.
[sshd]
enabled = true
backend = systemd
journalmatch = _SYSTEMD_UNIT=ssh.service + _COMM=sshd
maxretry = 4
findtime = 10m
bantime = 1d
port = ssh # ban TCP/22 only
action = %(action_)s
%(action_abuseipdb_async)sNotes:
-
backend = systemdavoids depending on/var/log/auth.log(some hosts log to journal only); -
maxretry = 4in 10 minutes: humans mistype a key/password a couple of times, bots hit dozens; -
bantime = 1dwithbantime.increment = truegrows repeat offenders up tobantime.maxtime; -
port = sshkeeps the firewall ban scoped to SSH.
# if auth.log exists
fail2ban-regex /var/log/auth.log /etc/fail2ban/filter.d/sshd.conf | tail -5
# journal-only host: export a sample first
journalctl -u ssh --since "-2 hours" --no-pager > /tmp/ssh-sample.log
fail2ban-regex /tmp/ssh-sample.log /etc/fail2ban/filter.d/sshd.conf | tail -5Expect matches on lines like:
sshd-session[123]: Failed password for root from 198.51.100.7 port 44432 ssh2
sshd-session[123]: Invalid user ubuntu from 198.51.100.7 port 47192
sshd -T | grep -Ei '^(passwordauthentication|permitrootlogin|maxauthtries|kbdinteractiveauthentication)'Recommended target:
| Setting | Recommended | Why |
|---|---|---|
PermitRootLogin |
prohibit-password (keys only) |
password guessing against root is the main attack |
PasswordAuthentication |
no (if all users have keys) |
removes the whole class of password brute force |
MaxAuthTries |
3–4
|
fail2ban sees the failures sooner |
KbdInteractiveAuthentication |
no |
avoids PAM password fallback |
⚠️ Do not lock yourself out. Keep an existing SSH session open, have a second terminal or out-of-band console, edit/etc/ssh/sshd_config.d/*.conf, runsshd -t, then reload (systemctl reload ssh). Never test ban rules with your own management IP.
[recidive]
enabled = true
logpath = /var/log/fail2ban.log
findtime = 1d
maxretry = 5
bantime = 4w
banaction = nftables[type=allports]Exclude it from reporting (skip_jails = recidive): the same IP was already reported by the
specific jail; recidive would only create duplicates.
/var/log/exim4/mainlog:
2026-01-02 03:04:05 auth_login authenticator failed for H=(localhost) [198.51.100.7]: 535 Incorrect authentication data
2026-01-02 03:04:06 auth_login authenticator failed for H=(localhost) [198.51.100.7]: 435 Unable to authenticate at present: authentication socket read error or premature eof
The first line is a client failure (535). The second is not a client failure: 435 means
the auth backend could not be reached (for example Dovecot auth is down or its socket is
misconfigured). Never put 435 into a fail2ban filter — during a backend outage it bans every
legitimate mail client that tries to authenticate.
Measured on a production host: 7,196 435 lines in one day and six bans, all caused by a
broken Dovecot auth process (CRAM-MD5 mechanism can't be supported with given passdbs with a
PAM passdb). After fixing auth_mechanisms and removing 435 from the filter, the bans were
lifted and genuine 535 attacks continued to be blocked.
The stock exim-isp filter only matches 535, and that is correct. Keep the filter at 535:
# /etc/fail2ban/filter.d/exim-auth-fail.conf
[Definition]
# 535 = bad credentials (client abuse); 435 = auth backend fault (never match it).
failregex = ^\s*\S+ authenticator failed for .*?\[<HOST>\](?::\d+)?(?: I=\[\S+\](?::\d+)?)?: 535 Incorrect authentication data.*$
ignoreregex =Jail:
[exim-auth-fail]
enabled = true
filter = exim-auth-fail
logpath = /var/log/exim4/mainlog
maxretry = 15
findtime = 1h
bantime = 1d
port = 25,465,587The threshold is deliberately generous: mail clients retry. If 435 appears in the log, do not
filter it — diagnose the auth path instead:
dovecot -n | grep auth_mechanisms
journalctl -u dovecot --since "-10 min" | grep -iE "fatal|auth"
systemctl status dovecot exim4Fix the backend (for example remove cram-md5 when the passdb is PAM/passwd, then restart
Dovecot). After that, only 535 (real bad credentials) reaches fail2ban.
Category mapping for this jail: the project maps it to
18(Brute-Force); add11(Email Spam) only if you also observe spam delivery attempts.
fail2ban-regex /var/log/exim4/mainlog /etc/fail2ban/filter.d/exim-auth-fail.conf | tail -5If the host serves mailboxes, IMAP brute force is a separate vector:
[dovecot]
enabled = true
filter = dovecot
logpath = /var/log/mail.log
maxretry = 10
findtime = 10m
bantime = 1d
port = 110,143,993,995The stock dovecot filter matches auth failed / aborted logins. Test on a sample:
fail2ban-regex /var/log/mail.log /etc/fail2ban/filter.d/dovecot.conf | tail -5If the same failure already appears in Exim's log, keep both jails but exclude one from reporting to avoid duplicates (or accept one report per 20 minutes — the worker aggregates by IP anyway).
[proftpd]
enabled = true
filter = proftpd
logpath = /var/log/proftpd/proftpd.log
maxretry = 5
findtime = 10m
bantime = 1d
port = 20,21,989,990Measured: 3,995 failed logins in one day from two IPs. But 2,880 of them came from the
owner's own IP with a wrong username (cam_*: no such user). Always whitelist the administrator's
address before enabling this jail:
[DEFAULT]
ignoreip = 127.0.0.1/8 ::1 203.0.113.10 # ...your office/owner IPTest with the stock filter:
fail2ban-regex /var/log/proftpd/proftpd.log /etc/fail2ban/filter.d/proftpd.conf | tail -5| Exposure | SSH | Web | FTP | |
|---|---|---|---|---|
| Minimal / small VPS | maxretry 4 / 10m / 1d |
off | off | off |
| Typical public host | + recidive 4w |
attack-path + PHP probes | SMTP AUTH 15/1h
|
5/10m + owner whitelist |
| Aggressive | + key-only SSH, custom port | + nginx-forbidden, rate limits |
+ Dovecot | only if FTP is really needed |
Aggressive settings increase the risk of locking out legitimate users; always keep
ignoreip current.
# jail exists and has the actions
fail2ban-client get sshd actions
fail2ban-client get exim-auth-fail actions
fail2ban-client get proftpd actions
# thresholds and current state
fail2ban-client get sshd maxretry
fail2ban-client status sshd
# the firewall really contains the address
nft list set inet f2b-table addr-set-sshdFail2ban reduces noise; it does not fix weak authentication:
- SSH: key-only auth, no root password, limited users,
AllowUsers/AllowGroups; - Mail: strong passwords, SPF/DKIM/DMARC, TLS, rate limits at the MTA;
- FTP: prefer SFTP/SSH, or restrict port 21 to trusted networks;
- Web: WAF/CDN rules for volumetric attacks; fail2ban handles the long tail.
Next: Web Protection · Verification & Rollback · Agent Prompts: Fail2Ban Setup
Fail2Ban_AbuseIPDB · repository · releases · issues · MIT