# Visualizing fail2ban ban logs

**URL:** https://discourse.nodered.org/t/visualizing-fail2ban-ban-logs/96181
**Category:** General
**Created:** [22 March 2025 20:31 UTC](https://discourse.nodered.org/t/visualizing-fail2ban-ban-logs/96181 "2025-03-22T20:31:32Z")
**Posts on this page:** 7
**Page:** 1

<div class="post-metadata">

### Author: ![Becker](https://avatars.discourse-cdn.com/v4/letter/b/c77e96/32.png) [@Becker](https://discourse.nodered.org/u/Becker)
#### Post date: [22 March 2025 20:31 UTC](https://discourse.nodered.org/t/visualizing-fail2ban-ban-logs/96181/1 "2025-03-22T20:31:32Z")

</div>

Hi, I would like to visualize the banned IPs from fail2ban log.  
for example:

 ![grafik](https://us1.discourse-cdn.com/flex026/uploads/nodered/original/3X/c/3/c376754bb70314c628eb8d57cfdeec286b43214c.png)  
or  
 ![grafik](https://us1.discourse-cdn.com/flex026/uploads/nodered/original/3X/4/3/436d174761beb913929720925539800baf6043af.png)

I preferd and tried the first one, but exec with sudo doesn´t work. fail2ban client needs root.  
I don´t want to run NR as root.

the scond, fail2ban.log has to be filtered, I've tried a few things, but haven't come up with any results.  
Did anyone already built something for fail2ban ?

---

<div class="post-metadata">

### Author: ![Colin](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/colin/32/17040_2.png) [@Colin](https://discourse.nodered.org/u/Colin)
#### Post date: [22 March 2025 21:06 UTC](https://discourse.nodered.org/t/visualizing-fail2ban-ban-logs/96181/2 "2025-03-22T21:06:36Z")

</div>

> [@Becker](#):
>
> exec with sudo doesn´t work

You can allow the node red user to use sudo  
to execute only the command you want without having to enter a password.  
Use `sudo visudo` to edit the config file to allow that.

---

<div class="post-metadata">

### Author: ![Colin](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/colin/32/17040_2.png) [@Colin](https://discourse.nodered.org/u/Colin)
#### Post date: [22 March 2025 21:07 UTC](https://discourse.nodered.org/t/visualizing-fail2ban-ban-logs/96181/3 "2025-03-22T21:07:56Z")

</div>

Or maybe add the node red user to whatever group has access to those logs. Look at the permissions on the log file.

Edit. Use `ls -l /var/log/fail2ban.log` to see.

---

<div class="post-metadata">

### Author: ![Becker](https://avatars.discourse-cdn.com/v4/letter/b/c77e96/32.png) [@Becker](https://discourse.nodered.org/u/Becker)
#### Post date: [22 March 2025 22:00 UTC](https://discourse.nodered.org/t/visualizing-fail2ban-ban-logs/96181/4 "2025-03-22T22:00:53Z")

</div>

> [@Colin](#):
>
> /var/log/fail2ban.log

.log I can see without root.

the fail2ban client needs root, I did add node-red user in visudo, but exec says fail2ban needs root.

---

<div class="post-metadata">

### Author: ![Colin](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/colin/32/17040_2.png) [@Colin](https://discourse.nodered.org/u/Colin)
#### Post date: [23 March 2025 07:27 UTC](https://discourse.nodered.org/t/visualizing-fail2ban-ban-logs/96181/5 "2025-03-23T07:27:33Z")

</div>

> [@Becker](#):
>
> exec says fail2ban needs root.

You have to use sudo in the command in the exec node, but configure visudo to not need a password for the fail2ban command.

---

<div class="post-metadata">

### Author: ![Becker](https://avatars.discourse-cdn.com/v4/letter/b/c77e96/32.png) [@Becker](https://discourse.nodered.org/u/Becker)
#### Post date: [23 March 2025 21:19 UTC](https://discourse.nodered.org/t/visualizing-fail2ban-ban-logs/96181/6 "2025-03-23T21:19:27Z")

</div>

thats my solution:

 ![grafik](https://us1.discourse-cdn.com/flex026/uploads/nodered/original/3X/2/d/2dad442585b9274f06c28748213accb15aa5b5de.png)

 ![grafik](https://us1.discourse-cdn.com/flex026/uploads/nodered/original/3X/d/b/db081d250f8cfea8ebe3f21289975e91c7fc4e48.png)

```auto
[{"id":"dc71ac07a95659c3","type":"exec","z":"7667425061cb9763","command":"tail -n 100 /var/log/fail2ban.log | grep \"Ban\"","addpay":"","append":"","useSpawn":"false","timer":"2","winHide":false,"oldrc":false,"name":"fail2ban","x":320,"y":420,"wires":[["11e68e569fe20be4"],[],[]]},{"id":"285f2b0fa73c5141","type":"inject","z":"7667425061cb9763","name":"jede Minute","props":[{"p":"payload"}],"repeat":"60","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"true","payloadType":"bool","x":110,"y":420,"wires":[["dc71ac07a95659c3","c29ab3f614c5082b"]]},{"id":"11e68e569fe20be4","type":"split","z":"7667425061cb9763","name":"Log aufteilen","splt":"\\n","spltType":"str","arraySplt":1,"arraySpltType":"len","stream":false,"addname":"","property":"payload","x":550,"y":400,"wires":[["804b2ce39b17f98a"]]},{"id":"804b2ce39b17f98a","type":"function","z":"7667425061cb9763","name":"Fail2Ban","func":"let logEntry = msg.payload;\nif (!logEntry.trim()) {\n return null;\n}\nlet regex = /(\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2},\\d{3})\\s+fail2ban.actions\\s+\\[\\d+\\]:\\s+NOTICE\\s+\\[([^\\]]+)\\]\\s+Ban\\s+([a-fA-F0-9:.]+)/;\nlet match = regex.exec(logEntry);\nif (match) {\n let timestamp = match[1];\n let service = match[2];\n let ipAddress = match[3];\n let date = new Date(timestamp.replace(',', '.'));\n let timeInMillis = date.getTime();\n let result = {\n IP: ipAddress,\n Dienst: service,\n time: timeInMillis\n };\n msg.payload = result;\n return msg;\n} \nelse {\n node.warn(\"Kein passender Log-Eintrag gefunden\");\n return null;\n}","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":540,"y":440,"wires":[["e3eabf06f5759e16"]]},{"id":"e3eabf06f5759e16","type":"influxdb out","z":"7667425061cb9763","influxdb":"65f9e27871c73f7e","name":"Fail2Ban","measurement":"Fail2Ban","precision":"ms","retentionPolicy":"","database":"database","precisionV18FluxV20":"ms","retentionPolicyV18Flux":"","org":"organisation","bucket":"bucket","x":760,"y":440,"wires":[]},{"id":"b732a0ce799cc393","type":"influxdb in","z":"7667425061cb9763","influxdb":"65f9e27871c73f7e","name":"Fail2Ban","query":"select * from \"Fail2Ban\" order by time desc Limit 30","rawOutput":false,"precision":"","retentionPolicy":"","org":"organisation","x":320,"y":480,"wires":[["9318c96dd873b946"]]},{"id":"602fae0cf5cf60fe","type":"ui_template","z":"7667425061cb9763","group":"0174de37aa15dc39","name":"Fail2Ban","order":6,"width":0,"height":0,"format":"<style>\n tr:hover {\n background-color: #f9f9f9;\n }\n td,\n th {\n font-size: 14px;\n border: 1px solid #ddd;\n }\n th {\n background-color: #f2f2f2;\n text-align: center;\n }\n\n td {\n text-align: left;\n }\n</style>\n<div>\n <table class=\"table table-bordered\" style=\"width: 100%; border-collapse: collapse;\">\n <thead>\n <tr>\n <th>Zeitpunkt</th>\n <th>IP Adresse</th>\n <th>Dienst</th>\n </tr>\n </thead>\n <tbody>\n <tr ng-repeat=\"entry in msg.payload\">\n <td>{{ entry.time }}</td>\n <td>{{ entry.IP }}</td>\n <td>{{ entry.Dienst }}</td>\n </tr>\n </tbody>\n </table>\n</div>","storeOutMessages":true,"fwdInMessages":false,"resendOnRefresh":true,"templateScope":"local","className":"","x":760,"y":480,"wires":[[]]},{"id":"c29ab3f614c5082b","type":"delay","z":"7667425061cb9763","name":"1s","pauseType":"delay","timeout":"1","timeoutUnits":"seconds","rate":"1","nbRateUnits":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"allowrate":false,"outputs":1,"x":130,"y":480,"wires":[["b732a0ce799cc393"]]},{"id":"9318c96dd873b946","type":"function","z":"7667425061cb9763","name":"InfluxDB","func":"let data = msg.payload;\nif (Array.isArray(data)) {\n msg.payload = data.map(entry => {\n let date = new Date(entry.time);\n let weekday = date.toLocaleDateString('de-DE', { weekday: 'short' });\n let day = date.toLocaleDateString('de-DE', { day: '2-digit' });\n let month = date.toLocaleDateString('de-DE', { month: '2-digit' });\n let year = date.toLocaleDateString('de-DE', { year: 'numeric' });\n let time = date.toLocaleTimeString('de-DE', { hour: '2-digit', minute: '2-digit', second: '2-digit' });\n let formattedDate = `${weekday}, ${day}.${month}.${year} - ${time} Uhr`;\n return {\n time: formattedDate,\n IP: entry.IP,\n Dienst: entry.Dienst\n };\n });\n return msg;\n}\nelse {\n node.error(\"Die Daten sind im falschen Format\");\n return null;\n}","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":540,"y":480,"wires":[["602fae0cf5cf60fe"]]},{"id":"65f9e27871c73f7e","type":"influxdb","hostname":"192.168.168.5","port":8086,"protocol":"http","database":"db","name":"InfluxDB","usetls":false,"tls":"","influxdbVersion":"1.x","url":"http://localhost:8086","timeout":10,"rejectUnauthorized":true},{"id":"0174de37aa15dc39","type":"ui_group","name":"Fail2Ban","tab":"2353ff8665d46bde","order":1,"disp":true,"width":"10","collapse":false,"className":""},{"id":"2353ff8665d46bde","type":"ui_tab","name":"Fail2Ban","icon":"pan_tool","order":2,"disabled":false,"hidden":false}]

```

Grafana could also use it:

 ![grafik](https://us1.discourse-cdn.com/flex026/uploads/nodered/original/3X/7/0/7035a6ff119e412f658ed0fa08f3996199fc21d2.png)

---

<div class="post-metadata">

### Author: ![system](https://us1.discourse-cdn.com/flex026/uploads/nodered/original/1X/d073cd938eafa2e558d7c2cd59003b3ef4963033.png) [@system](https://discourse.nodered.org/u/system)
#### Post date: [6 April 2025 21:20 UTC](https://discourse.nodered.org/t/visualizing-fail2ban-ban-logs/96181/7 "2025-04-06T21:20:21Z")

</div>

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.
