fail2ban regex tester
Paste log lines and pick one of fail2ban's filters, or paste your own failregex or filter file. Each line shows whether fail2ban counts it as a failure,
which failregex matched and which address it would ban, as fail2ban-regex reports it. It runs fail2ban 1.1.1's
filters and line processing in your browser; nothing is uploaded.
fail2ban-regex /var/log/auth.log sshd Checked against fail2ban itself
fail2ban ships a test log for each filter. All 1,564 lines of them (96 filters, every mode they use) were run through fail2ban 1.1.1 and through this page's engine: the failures, addresses, users and ignored lines are identical on every line. The filters themselves are fail2ban's, resolved by fail2ban's own reader (129 filter and mode combinations), from fail2ban 1.1.1 (GPL-2.0).
What fail2ban's default sshd filter does not count on a key-only server
Once a server accepts only SSH keys, a password guess no longer produces "Failed password". The client is refused before any password is asked for,
and sshd logs only that the connection closed. fail2ban's sshd filter in its default normal mode does not count those lines, and neither do the
ten-connection streams below (fail2ban 1.1.1, failures counted for the attacking address):
| Ten connections | normal (default) | ddos | extra | aggressive |
|---|---|---|---|---|
| Password guesses for root (the server takes keys only) | 0 | 10 | 0 | 10 |
| The same, from a client that says goodbye | 0 | 10 | 10 | 10 |
| Guesses for a user that does not exist | 10 | 20 | 10 | 20 |
| Connections that never authenticate (LoginGraceTime) | 0 | 10 | 0 | 10 |
0 failures means the address is never banned, whatever maxretry is. Measured with fail2ban 1.1.1 itself and pinned in this page's tests.
What that means in practice, from our own key-only server: the sshd lines it logged from 10 October 2026 to 9 November 2026, one real example line of each
through each mode. "Only with other lines" is a line the filter matches with F-NOFAIL: it counts only when the same connection also logs a failure.
| sshd message | Lines in 30 days | normal (default) | ddos | extra | aggressive |
|---|---|---|---|---|---|
| connection-closed Connection closed by invalid user admin 203.0.113.45 port 51234 [preauth] | 48,747 | only with other lines | counted | not counted | counted |
| invalid-user Invalid user admin from 203.0.113.45 port 51234 | 34,304 | counted | counted | counted | counted |
| received-disconnect Received disconnect from 203.0.113.45 port 51234:11: Bye Bye [preauth] | 19,447 | only with other lines | only with other lines | only with other lines | only with other lines |
| disconnected-preauth Disconnected from invalid user admin 203.0.113.45 port 51234 [preauth] | 19,447 | only with other lines | counted | counted | counted |
| connection-reset Connection reset by authenticating user root 203.0.113.45 port 51234 [preauth] | 3,555 | only with other lines | counted | not counted | counted |
| timeout-before-auth Timeout before authentication for 203.0.113.45 port 51234, pid = 4242 | 2,047 | not counted | counted | not counted | counted |
| unable-to-negotiate Unable to negotiate with 203.0.113.45 port 51234: no matching key exchange method found. Their offer: diffie-hellman-group1-sha1 [preauth] | 294 | not counted | not counted | counted | counted |
| kex-identification error: kex_exchange_identification: read: Connection reset by peer | 288 | not counted | no address | not counted | no address |
| banner-invalid-format banner exchange: Connection from 203.0.113.45 port 51234: invalid format | 284 | not counted | counted | not counted | counted |
| max-auth-attempts error: maximum authentication attempts exceeded for root from 203.0.113.45 port 51234 ssh2 [preauth] | 199 | counted | counted | counted | counted |
| too-many-auth-failures Disconnecting authenticating user root 203.0.113.45 port 51234: Too many authentication failures [preauth] | 199 | not counted | not counted | not counted | not counted |
| pubkey-algorithm-not-accepted userauth_pubkey: signature algorithm ssh-rsa not in PubkeyAcceptedAlgorithms [preauth] | 112 | not counted | not counted | not counted | not counted |
| protocol-major-versions-differ error: Protocol major versions differ: 2 vs. 1 | 25 | not counted | not counted | not counted | not counted |
| banner-no-protocol-version banner exchange: Connection from 203.0.113.45 port 51234: could not read protocol version | 25 | not counted | not counted | not counted | not counted |
| parse-publickey-packet fatal: userauth_pubkey: parse publickey packet: incomplete message [preauth] | 7 | not counted | not counted | not counted | not counted |
| dispatch-run-fatal ssh_dispatch_run_fatal: Connection from 203.0.113.45 port 51234: message authentication code incorrect [preauth] | 6 | not counted | counted | not counted | counted |
| bad-protocol-version error: Bad remote protocol version identification: 'SSH-2.0-' | 1 | not counted | not counted | not counted | not counted |
Counts from LogTriage's server (monthly attack report); successful logins, sessions and sshd's own penalty lines left out.
To count them, set the mode in /etc/fail2ban/jail.local, check it with fail2ban-regex, and restart:
[sshd]
enabled = true
mode = aggressive
# check what it would catch, then apply
fail2ban-regex /var/log/auth.log "sshd[mode=aggressive]"
systemctl restart fail2ban On systemd systems without /var/log/auth.log, test the journal instead: fail2ban-regex systemd-journal "sshd[mode=aggressive]".
How fail2ban reads a line
- The date is found and cut out. fail2ban tries its date templates (most filters only at the start of the line) and removes the matched date; the regexes see the rest. A line whose date is not found is still matched, but fail2ban cannot place it in time.
- prefregex, if the filter has one, must match first. Its
<F-CONTENT>part is what the failregexes then see; sshd's prefregex strips the host and program prefix this way. - Every failregex is tried (fail2ban-regex's default). A match needs an address or failure id:
<HOST>,<ADDR>or<F-ID>. - ignoreregex can drop a match.
- Each failure counts toward the address's maxretry (5 by default) within findtime (10 minutes by default).
Tags you can use in a failregex
| <HOST> | An IPv4 or IPv6 address, or a host name (fail2ban resolves names unless usedns = no). The usual tag for the attacker. |
| <ADDR> | An IPv4 or IPv6 address only, never a host name. |
| <IP4>, <IP6> | Only an IPv4 or only an IPv6 address. |
| <F-USER>…</F-USER> | Captures the user name, shown by fail2ban-regex and usable in actions. |
| <F-ID>…</F-ID>, <F-ID/> | A failure id other than an address (a session or account), counted like an address. |
| <F-NOFAIL>…</F-NOFAIL> | The line matches but is not a failure by itself; sshd uses it for lines that only count together with others of the same connection. |
| <F-MLFID>…</F-MLFID> | Ties lines of one connection together (sshd uses the process id in the prefix). |
| <SKIPLINES> | Skips lines inside a multi-line match (filters with maxlines above 1). |
A filter file for your own application, using fail2ban's shared syslog prefix from common.conf:
[INCLUDES]
before = common.conf
[Definition]
_daemon = myapp
failregex = ^%(__prefix_line)sLogin failed for user <F-USER>\S+</F-USER> from <HOST>$
ignoreregex =
Paste it into "My own failregex or filter file" with a few of your log lines to see each one matched or missed before you deploy it. The page's reader resolves
[INCLUDES], %(…)s and <tags> the way fail2ban does for every filter fail2ban ships. A custom datepattern that no shipped filter uses
falls back to fail2ban's default date templates.
The SSH lines themselves are explained one by one in the sshd log message reference, with counts from our server.
Questions
- Is there an online fail2ban regex tester?
- This page is one. It runs fail2ban 1.1.1's filters and its line processing (date detection, prefregex, failregex, ignoreregex and the sshd connection merging) in your browser, the way fail2ban-regex does. On all 1,564 lines of fail2ban's own test logs it gives the same result as fail2ban, line for line.
- Why does fail2ban-regex say "Missed" for a line that looks like an attack?
- Because no failregex of the filter matches it in the mode you run. fail2ban’s sshd filter in the default normal mode does not count "Timeout before authentication", "kex_exchange_identification" or "Connection closed by authenticating user … [preauth]" as failures. The mode ddos or aggressive does: pick it above and the line shows as a failure.
- How do I make fail2ban ban SSH clients on a server that only accepts keys?
- Set the filter mode in jail.local: under [sshd] add "mode = aggressive" (or ddos), then restart fail2ban. In the default normal mode, password guesses against an existing account on a key-only server leave only "Connection closed by authenticating user … [preauth]" lines, which fail2ban does not count, so those clients are never banned.
- Does fail2ban read OpenSSH 10’s sshd-session lines?
- Yes, from fail2ban 1.1.1 (August 2026) on: its sshd filter accepts both sshd and sshd-session as the program name (_daemon = sshd(?:-session)?), because OpenSSH 9.8 and later log most messages from sshd-session. Older fail2ban versions miss those lines, so upgrade, or test your version’s filter file here with your own lines.
- Can I test my own failregex or filter file?
- Yes. Choose "My own failregex or filter file" and paste either one failregex per line, or a whole filter file. A filter file is read the way fail2ban reads it, including [INCLUDES] before = common.conf, %(__prefix_line)s and <tags>; this reader gives the same failregex as fail2ban for every filter fail2ban ships.
- How many failures get an address banned?
- fail2ban’s jail.conf defaults are maxretry = 5 failures within findtime = 10 minutes, then a bantime of 10 minutes. The table above counts failures per address over the whole paste; whether they fall inside findtime depends on their times.
Seeing more than fail2ban bans?
Load the whole auth.log into the free analyzer: SSH brute force, user-name guessing and a login that succeeded after failures, per address. Nothing is uploaded.
Investigating something right now? LogTriage checks every address in the file against threat intelligence and writes the incident report: 10 analyses a month free. The incident pack adds the in-depth AI analysis and files up to 100 MB: 25 analyses for $19, one payment, no subscription. Pricing
Every query on this site's reference pages, the Sigma rules and a cheat sheet in one download: the Incident Response Kit, $29 once.