I had a bit of an idea, and the PiAlert was the result. A video is the best demonstration but in short, different coloured lights light up when certain things are triggered, and a counter is kept for each light. My primary trigger is access attempts on port 22 (SSH) on my servers. Its usually all automated attempts, but after 24 Hours one of my VPS’s where I have normal login enabled recorded 1633 attempts, and another where I have SSH set to only allow password-less logins via SSH Keys recorded 9 attempts. Similarly, automated WordPress logins were detected once. The video shows it being manually triggered prior to it being exposed to the outside world.
And some photos of it in action
I won’t lie. This is at best an alpha level item. I’ve uploaded all the code and design files in the hope that someone finds it interesting and possible wants to help improve it for others.
I haven’t been able to share this post in the Raspberry_Pi subreddit as I was banned over 4 months ago for asking about the Pi HQ Camera (boring story). I’ve tried for the last 4 months to at least appeal the ban but no one replies to the mod mail. If anyone wants to help rectify that by speaking to the mods I’d be over the moon so I can get my project posted there!
I’m a bit late for the whole “lockdown project movement”, and seeing as I worked through any lock downs that happened I didn’t get the time to sit and tinker like I would have. That changed recently thanks to surgery where I’m now sat up in the house with very little to do.
After the recent incident with one of my servers I realised I quite enjoyed watching the logs scroll past showing what was happening. I usually run
tail -n 80 -f /var/log/apache2/error.log
tail -n 80 -f /var/log/apache2/access.log
tail -n 80 -f /var/log/auth.log
and it’s interesting seeing what pages random bots are trying to access, or what accounts they attempt to login to SSH via. It’s also got that same look as hacker movies do. I figured I could create a more visually appealing system and thats where this project came from.
Watching SSH logins have changed recently for me since I implemented a more strict login procedure – the number of failed attempts have dropped dramatically and this is evident after running this for 24 hours – as detailed above.
This post will be split into three sections, Hardware, Server Software Configuration and Pi Software.
The Blinkt! has been attached using DuPont wires which have been cut at one end and soldered direct onto the same 40-PIN GPIO connector on the Blinkt!, because I had to use the Pi’s GPIO pins to also hook up the 4 digit display.
Getting the Blinkt! to work this way turned out to be a bit tricker than I first thought. I thought my Blinkt! just had some poor mechanical connections in the connector and the amount of trial and error it took to get it working was more than I want to admit to. It turns out, after reaching out to Pimoroni on twitter that early versions of the Blinkt! used Pin 2 for 5V, instead of Pin 4, as shown on pinout.xyz. In my haste I ordered a second Blinkt! in case my one was faulty – but now I have to think of another project to use the second one for!
All these components were then put into a case I designed in Tinkercad and 3D Printed on my Ender 3 Pro, which to an extent worked, but I could not get my head around how to create a case that clips together for a friction/clip fit. I ended up throwing two large columns that an M5 Screw would fit into to hold it all together. These columns are off centre to all room for the Pi to fit.
This took 9 iterations of printing, measuring and tweaking before I got the front part of the case looking pretty decent. Each time I printed it something else could just be moved a bit over, or it could just be adjusted ever so slightly, and because I’m using Tinkercad a few times I ended up moving a key part or two and had to almost start over again. During my iterations I ended up getting rid of my attempt at clamps to keep the Blinkt! in place, and resorted to a hot glue gun (a first for me!). I ended up using that on the 4 digit display, and to keep the Pi Zero set. One of the last iterations was the mounting for the Pi Zero itself. I had initially left it floating in the case but plugging the usb cable was a bit of an adventure with it moving about so much. My final revision, if there ever is one, is to remove the screw posts and holes for M5 screws, and figure out how to get the case to snap-fit together. If anyone wants to take a bash at remixing it, please, feel free! My only other issue is I wouldn’t mind a piece of opaque glass or acrylic to sit over the front. On the one hand it hides the obvious parts that look very tech-y, and two, it should diffuse the light somewhat.
The Pi Zero W I used was used previously in another project that needed the 40 Pin GPIO connecter mounted backwards. This actually turned out to be a bonus, and as it was being popped in a case and this will more than likely be its final project, I decided to bend some of the pins to help it fit a bit better.
A final design idea is that I really should have included a button or two, even just hidden around the case somewhere. One for cycling through the detected hits so I don’t have to wait on a specific hit to see that number, and one to switch off the display with a short press, and gracefully shut the Pi down with a long press. If needed, its always accessible via SSH and if absolutely needed I could write a URL route that calls
Server Software Configuration
As part of the process of securing and monitoring my servers after my last incident I verified that fail2ban was actually installed on them. fail2ban is an amazing piece of FOSS software that, in summary, watches logs on your sever, takes a note if anything is happening that shouldn’t be like multiple failed login attempts to the SSH Service, and bans that IP Address from reaching your server if the issue is severe or repeated for a predetermined time. By default it watches SSH traffic, but it can also be extended to monitor other things like the amount of 404 errors, or incorrect login attempts to WordPress etc.
Part of fail2ban allows you to create custom actions when various triggers happen. This ended up being more difficult than just plonking a curl request in and I ended up reaching out and asking on GitHub because no matter what I tried it wasn’t working. For ease of reference – this is how I made custom actions for fail2ban on a debian based server –
Create a jail.local file and add the following
[sshd] enabled = true port = ssh banaction = pinotifyred[myhost="SCRIPTHOSTSERVER"]
Replacing SCRIPTHOSTSERVER with a suitable URL (i.e dev.testing:8080) - no protocol at the start, no path at the end, and no trailing slash.
This inherits all the actions for SSHD, so it will continue to ban as normal, but it allows us to define additional actions. Unfortunately, you can’t just define a command to run here (and this was my issue), but instead tell it what action you would like to run, which gets called from the action.d folder. In the action.d folder create a file named after the ban action, in this case pinotifyred.conf, and have the following code in there
[Definition] # sends get request like "http://example.com/red" actionban = curl --fail "http://<my-host>/red" >> /dev/null [Init] # overwrite this in jail as action parameter: my-host = SCRIPTHOSTSERVER
Again, replacing SCRIPTHOSTSERVER with a suitable URL (i.e dev.testing:8080) - no protocol at the start, no path at the end, and no trailing slash. You can see that the actual address and protocol are set here in the actionban section.
This code calls the action ban, and replaces the <my-host> variable with what it has been defined as. I couldn’t get it to work without having that as a variable.
This code performs the command required, and also defines some variables that are needed for fail2ban to work. As a bonus feature, the way this is set up means that you can send a curl or wget request with various parameters including what IP has been banned, time and date it was banned etc, so if you’re after a more data-rich solution this could also be used. To do that, you could have a file in your action.d folder containing something similar to
[Definition] #sends get request like "http://example.com/ban.php?jail=sshd&ip=192.0.2.100": actionban = curl -G --data-urlencode "jail=%(name)s" --data-urlencode "ip=" --fail "http://<my-host>/ban.php" [Init] overwrite this in jail as action parameter: my-host = SCRIPTHOSTSERVER
As a small side note – I think theres a bug here in that the ban action is being called when an IP is unbanned. It’s something I’ll look into later as it’s possibly double counting.
I’ll be completely honest. The code is an absolute mess. It’s written in Python 3 by someone (me) who doesn’t know python, but knows how to search for and get answers on Stack Exchange, and with a grasp of basic programming fundamentals, managed to create the python program.
I’m not going to go over the process for formatting and getting you Pi to a headless and login-able state via SSH as that been done a thousand times before. The code below is hosted at GitHub, with only two files, the main
script to be run at startup, and a
library, gracefully used from RaspberryTips.
You can see the code in its entirety at my GitHub page.
This Python program just simply sets itself up to act as a HTTP server (and I know its not meant for production, but this is one of those “quick and easy” projects) and listen for any requests. Its single threaded, so if it gets a lot of attention it’ll more than likely fall down. It simply waits for a URL, if its defined, it runs an action. The action is to light up the Blinkt! in a Larson style scanner and then increment the counter. Depending on the URL means different colours LED’s illuminate. Theres no real error checking, theres no check to make sure the counter won’t overflow, and the program has the added benefit of showing me that even my home network is constantly under attack by malformed URL’s looking to gain access via any vulnerability they can find (which also throws up an exception error but doesn’t crash the program).
The penultimate piece of the puzzle is setting up the Pi so that as soon as it boots, it loads this script, and then just sits and runs. This is accomplished by editing
in vi by adding the command thats usually used to run the program –
python3 /home/pi/PiAlert/pialert.py &
The last piece of this whole puzzle is making sure the Pi, which is sitting behind a firewall on a home network with a Dynamic IP, will always be able to be reached by my VPS’s. I could use Dynamic DNS or any of the other myriad of services out there, however someone on the self hosted subreddit created a free service called freemyip.com which does exactly what I need it to do, and does it well. The service doesn’t seem popular yet and with the phenomenal price of free I’m sure that won’t be the same for long — but given how simple it is I would gladly kick a few quid their way. I also noticed that a second service has been set up by someone else on the sub, sliceport.com which I’ll have to give a bash at some point.
My code has 4 coloured lights set, and I have them set up as follows:
- Blue for failed WordPress attempts on this site
- Red for failed SSH attempts on Server A
- Purple for failed SSH attempts on Server B
- Green for failed URL’s from Server C
I’ll probably extend and change this as time goes on but this is a good indicator of what’s happening without having to log in to any server.
The best part? The design is somewhat neutral and is very, very flexible. If I decide I don’t want this anymore I can rewrite the code and turn it into a clock, or a counter for page hits, or any other number of things. Theres 8 RGB Leds and 4 7-Segment displays. Its also very portable. I have it sitting at my desk where I write my code, and its a nice reminder that bad people are trying bad things. But because of the low power requirements it can be ran from a battery pack – I could plug it in anywhere in the house where it will get a WiFi signal and it’ll happily run the code, and if a different network is needed all I have to do is SSH in, or create a new
file on the
So in summary — the codes a mess and could really be refactored. If I ever learn python it’ll be one of the first things I do. The enclosure could do with some love, and again, if I ever learn a 3D Modelling program I’ll get to that as well. But apart from that? I’m happy.