fail2ban doesn't recognize failed public key ssh logins and I assume that this can be solved by modifying the failregex of /etc/fail2ban/filter.d/sshd.config to match the following line:

<date> <time> <server-hostname> sshd[25917]: Connection closed by <client-ip> [preauth]

But I can't find a decent introduction on how to correctly modify said failregex. As I don't really know what variables like ^%(__prefix_line)s include it's hard to get a working regex.

I understand that the most recent version 0.9.1 includes the regex to matche the "Connection closed by [preauth]" line, but I'm using fai2ban from the Debian repository and the configuration of 0.9.1 is not compatible with the one I have.


This line does it:

^%(__prefix_line)sConnection closed by <HOST> \[preauth\]$

Tested with the following logstring:

Apr 29 12:30:12 sendai sshd[25917]: Connection closed by [preauth]

Successfully tested with:

$ fail2ban-regex ~/ssh.log sshd.conf 

Running tests

Use regex file : sshd.conf
Use log file   : /home/user/ssh.log


|- Regular expressions:
|  [12] ^\s*(?:\S+ )?(?:kernel: \[\d+\.\d+\] )?(?:@vserver_\S+ )?(?:(?:\[\d+\])?:\s+[\[\(]?sshd(?:\(\S+\))?[\]\)]?:?|[\[\(]?sshd(?:\(\S+\))?[\]\)]?:?(?:\[\d+\])?:)?\s*Connection closed by <HOST> \[preauth\]$
`- Number of matches:
   [12] 1 match(es)


Addresses found:
[12] (Wed Apr 29 12:30:12 2015)

Success, the total number of match is 1
  • I assumed fail2ban would log to /var/log/fail2ban.log on matches, but it didn't, only when banned it finally logged. Thank you very much for the help!
    – apoc
    Apr 29 '15 at 15:15
  • I'm using 0.9.3 and the closest filter I could were one for multiline: fail2ban #227f27c. It does not match with your logstring (or mine, for that matter), but for MaxAuthTries=N in /etc/ssh/sshd_config. Do you know if something like your regex is intentionally left out from the default filter? Thanks!
    – timss
    Oct 26 '15 at 17:56

No regex hacking is required (at least since fail2ban 0.10.4). In /etc/fail2ban/jail.conf is the following information:


# To use more aggressive sshd modes set filter parameter "mode" in jail.local:
# normal (default), ddos, extra or aggressive (combines all).
# See "tests/files/logs/sshd" or "filter.d/sshd.conf" for usage example and details.
#mode   = normal

So follow the recommendations by creating /etc/fail2ban/jail.local with your other customisations, along with one of the more stringent modes, for example,

mode   = aggressive

This mode now covers failed public keys.

  • 1
    This is correct answer, excepting that error Connection closed ... [preauth] has basically nothing with failed public keys (you'd get Failed publickey ... instead). See github.com/fail2ban/fail2ban/blob/… for more failed messages. Connection closed means only that the connection was closed on preauth phase (so user is not authenticated for any reason).
    – sebres
    Jan 27 '20 at 14:30
  • 1
    @sebres my system actually does shows the Connection closed… message for "Failure on connect with valid user-name but wrong public keys", which is the final line you linked to.
    – Sparhawk
    Jan 27 '20 at 21:34
  • Sure it does. As well as after every other failure on preauth phase (for example if trying unsupported/disabled auth method, or even if it got closed totally without authentication). As already said, the message has nothing with wrong public keys at all, it just signals that connection is closed before authentication process fulfilled.
    – sebres
    Jan 28 '20 at 12:50
  • @sebres Ah okay got it. On your second point though, I don't get the same behaviour. When I fail with the wrong public key, I don't get the Failed publickey… message, just the Connection closed… one.
    – Sparhawk
    Jan 28 '20 at 23:33
  • Clear, because several messages are logged only in VERBOSE level, see serverfault.com/a/477424/488604
    – sebres
    Jan 29 '20 at 11:23

At least in openssh 7.3 the log messages also contain a port number. So I had to modify sebix's solution to the following:

^%(__prefix_line)sConnection closed by <HOST> port \d+ \[preauth\]$

On Ubuntu 18.04 with OpenSSH 7.6p1 I had to extend the "cmnfailre" rules in /etc/fail2ban/filter.d/sshd.conf by

^%(__prefix_line)sConnection closed by authenticating user <F-USER>.+</F-USER> <HOST> port \d+ \[preauth\]$

to match ssh login attempts without correct ssh key:

Apr 14 15:27:15 ubuntu-server sshd[8719]: Connection closed by authenticating user root x.x.x.x port 42664 [preauth]
Apr 14 15:27:15 ubuntu-server sshd[8721]: Connection closed by authenticating user root x.x.x.x port 42666 [preauth]
Apr 14 15:27:16 ubuntu-server sshd[8723]: Connection closed by authenticating user root x.x.x.x port 42668 [preauth]
Apr 14 15:27:16 ubuntu-server sshd[8725]: Connection closed by authenticating user root x.x.x.x port 42670 [preauth]
Apr 14 15:27:17 ubuntu-server sshd[8727]: Connection closed by authenticating user root x.x.x.x port 42672 [preauth]
  • This worked for my Ubuntu 18.04 as well, thank you! Is there a way to extend the default sshd.conf with just that line or is the only option to copy the whole thing to .local and add it there?
    – chrisan
    Feb 18 '20 at 15:35
  • 1
    @chrisan You could create a file /etc/fail2ban/filter.d/sshd.local like this: ` [Definition] failregex = %(known/failregex)s %(__prefix_line)sConnection closed by authenticating user <F-USER>.+</F-USER> <HOST> port \d+ [preauth]$ ` Feb 19 '20 at 0:59
  • @ArnelA.Borja and that will add to the base .conf not override it? That was my main concern. I created the .local originally but just copied the entire config and added the new filter
    – chrisan
    Feb 20 '20 at 10:33
  • 1
    @chrisan Yes it won't override it, it will just add a new value to failregex, due to %(known/failregex)s. You could confirm this by running sudo fail2ban-regex -v /var/log/auth.log /etc/fail2ban/filter.d/sshd.conf before and after adding the said file; the number of Failregex entries will increase by 1. Feb 28 '20 at 5:24

For me, this works better, as I get tons of legit log entries, matching the "Connection closed" regex, at least in OpenSSH 6.6.1 variations. Believe it also covers the new OpenSSH log format, which includes "port":

^%(__prefix_line)sDid not receive identification string from <HOST>\s*$
^%(__prefix_line)sReceived disconnect from <HOST>: (port \d*: ){,1}11: (Bye Bye){,1} \[preauth\]\s*$

$ cat /etc/*relea* | grep -i desc

$ fail2ban-regex /var/log/auth.log filter.d/sshd.conf

Running tests

Use   failregex file : filter.d/sshd.conf
Use         log file : /var/log/auth.log


Failregex: 39 total
|-  #) [# of hits] regular expression
|  12) [16] ^\s*(<[^.]+\.[^.]+>)?\s*(?:\S+ )?(?:kernel: \[\d+\.\d+\] )?(?:@vserver_\S+ )?(?:(?:\[\d+\])?:\s+[\[\(]?sshd(?:\(\S+\))?[\]\)]?:?|[\[\(]?sshd(?:\(\S+\))?[\]\)]?:?(?:\[\d+\])?:?)?\s(?:\[ID \d+ \S+\])?\s*Did not receive identification string from <HOST>\s*$
|  13) [23] ^\s*(<[^.]+\.[^.]+>)?\s*(?:\S+ )?(?:kernel: \[\d+\.\d+\] )?(?:@vserver_\S+ )?(?:(?:\[\d+\])?:\s+[\[\(]?sshd(?:\(\S+\))?[\]\)]?:?|[\[\(]?sshd(?:\(\S+\))?[\]\)]?:?(?:\[\d+\])?:?)?\s(?:\[ID \d+ \S+\])?\s*Received disconnect from <HOST>: (port \d*: ){,1}11: (Bye Bye){,1} \[preauth\]\s*$

Ignoreregex: 0 total

Date template hits:
|- [# of hits] date format
|  [62412] MONTH Day Hour:Minute:Second

Lines: 62412 lines, 0 ignored, 39 matched, 62373 missed
Missed line(s):: too many to print.  Use --print-all-missed to print all 62373 lines

$ grep "Did not receive identification string from" /var/log/auth.log | wc -l
$ grep "Received disconnect from" /var/log/auth.log | grep -v x.x.x.x | wc -l

In 2021, in Debian with fail2ban=0.11.2-1 (from Bullseye), all you have to do is to add

mode = aggressive

line to /etc/fail2ban/jail.d/defaults-debian.conf file, under [sshd] section. That bans everyone which attempts to login as valid user using wrong public key. No need to do anything else.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.