Log Invalid Login Attempts for Fail2ban and upstream server action

I was hoping Discourse could log invalid login attempts to file, even if it is something you have to configure to do so. Then I could create a custom filter and jail for discourse

I use a centralized fail2ban server. the way it works is all my Containers, Docker images, VMs have a custom ban action:

in fail2ban you specify the action to take in your jail, such as:
action = iptables-allports

then all you have to do is edit that action:
sudo nano /etc/fail2ban/action.d/iptables-allports.conf

actionban = <iptables> -I f2b-<name> 1 -s <ip> -j <blocktype>
      curl -s "https://fail2ban.YourDomain.com:35553/fail2ban.php?token=D2f3Ydy45f6y5FRTfyeFrtYErt&action=add&source=TEST_HOST&reason=TEST_FILTER&ip=111.222.333.444"

With this setup your container/docker/vm will fail2ban them locally, but it will also relay this information to your central fail2ban server. The central server can also take all collected IPs and make them available as txt banlist such as: https://fail2ban.YourDomain.com/banned.txt

Then you can have your pfsense firewall subscribe to this banlist, and you can even share the list with other pfsense routers. This way if they try breaking in on one application, they get banned from everything. This has worked great for me for years.

And all that I need to implement this for discourse is for discourse to write an entry to a log file when there is an invalid login attempt :slight_smile:

1 Like

did you figure out how to hook or log this?


1 Like

Bump. This seems like a very good idea!

Where does Discourse store and show logs?

The NGINX logs
Occasionally NGINX logs may contain some extra tips, they are located at:

cd /var/discourse
./launcher enter app
cd /var/log/nginx
The files access.log and error.log will be there as well as a bunch of rotated compressed files. Running less access.log.2.gz will automatically decompress and display the logfile for you.

This directory is also available on the host at /var/discourse/shared/standalone/log/var-log/nginx .

Unfortunately, the nginx error.log and access.log files do not log any invalid login attempts.

Can anyone suggest another avenue?

Thank you.

1 Like

Agree. It would be great to hook into a fail2ban kind of automated exponential backoff.

1 Like

curious - is this feature request being tracked or planned yet? It would be a good security feature.

log (or hook for) failed login attempts by IP address

Thank you!

1 Like

The nginx access.log file should have lines with 403 responses to the login route that you need for this. Have you checked the logs?

1 Like

ahhh, thank you! I wonder how to access it from outside the docker image/container

Hello @Falco thanks for the reply. I promptly checked the logs just now, a correct password attempt and incorrect password attempt look the same to me (200 response):

(I sanitized the IP address and domain, the rest is untouched)

bad password:

[20/Dec/2021:08:07:31 -0800] "community.example.com" "GET /session/csrf HTTP/1.1" "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:95.0) Gecko/20100101 Firefox/95.0" "session/csrf" 200 1185 "https://community.example.com/" 0.016 0.017 "-"
[20/Dec/2021:08:07:32 -0800] "community.example.com" "POST /session HTTP/1.1" "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:95.0) Gecko/20100101 Firefox/95.0" "session/create" 200 1111 "https://community.example.com/" 0.552 0.550 "-"

good password:

[20/Dec/2021:08:24:50 -0800] "community.example.com" "GET /session/csrf HTTP/1.1" "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:95.0) Gecko/20100101 Firefox/95.0" "session/csrf" 200 1185 "https://community.example.com/" 0.020 0.020 "-"
[20/Dec/2021:08:24:51 -0800] "community.example.com" "POST /session HTTP/1.1" "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:95.0) Gecko/20100101 Firefox/95.0" "session/create" 200 2251 "https://community.example.com/" 1.216 1.216 "-"

so since they are both returning a 200 response, you cannot use this for fail2ban, you will ban all users good or bad password.


Twitter uses 400 for wrong password, but Facebook, LinkedIn, Google and Amazon returns a 200. IMO a 200 sounds wrong, but it appears to be the “normal” thing?

Maybe you can start with a plugin that hooks into this method here

And does what you need?


awesome, thanks for the reply! soon as I get a little bit of downtime I will try making a plugin to generate this info! ( all I need is the ip address logged to a file when somebody tries logging in with an incorrect password eg: invalid login attempt from IP )


thank you! I hope to use this plugin; let me know if you can make it available.