Yoink! An adventure in Tailscale, Wake-on-LAN, and Node.js for armv6

Jun 14, 2023

Let me start this one off with some backstory. Skip to the TL;DR if you don't care. I have a """server""", which is actually just a computer which belonged to my school until they threw it out, about 5 years after they should have done. It's a HP Compaq Elite 8000 with a Core 2 Duo E8400 and 6GB of RAM (upgraded from 2). This thing was being actively used (with Windows 7) up until 2022. For all I know, some of these machines are still in use, but I haven't been there in over a year now, so I wouldn't know.

Anyway, for the 8 months, this machine has dutifully sat in my kitchen in my student accommodation, just barely getting by as a Minecraft server for me and a few friends. The wonderful thing about student accommodation is that the electricity bill is included in rent, which means that my electricity is pretty much being subsidised by the many people who only use the sockets in their room to charge their phone and their laptop. This was all wonderful, until the semester ended, at which point I had to come home to the wonderful world of UK electricity bills. After some quick maths, I decided it was probably less cost effective to run this machine than to just host a Minecraft server with a provider like Shockbyte, so I sadly shut it down.

Now, I recently discovered the magic of Tailscale, a really cool service which lets me access my ex-school computer from anywhere as if I were on the same LAN, which made me think about what else I could use it for. One idea I had was to use it as a NAS. Sadly it only has one drive bay (which I'm using for the boot drive), but it occurred to me I could probably rip out the optical drive and just put a hard drive in instead. Stay tuned for a picture of the mess that will surely ensue when I get around to buying a drive.

So, if I want to run this as a NAS, but avoid running up the 'leccy bill, what can I do? The answer, I decided, was to only have the server on when I wanted to use it, and the solution to this was to use wake-on-LAN, since I might not necessarily be in the same place as the server.

TL;DR: want to have server while minimising power usage, server should turn off when not in use and wake up when I need it to.

So, I needed a way to send WOL packets to my server from anywhere. Sadly, it's not possible to just send them over Tailscale, but that does somewhat simplify things anyway. Instead, I can use a Raspberry Pi on the same network (and Tailscale) to host a web app, which could then be used to send WOL pings to the server. Of course, excellent solutions to this problem exist, such as UpSnap, but I deliberately did not look into these because where's the fun in that.

Instead, I wrote my own app. It's called 'yoink', and the code is, of course, on GitHub. It's a work in progress, but there isn't that much more to add, really. The app is written in Node, using Nunjucks for templating (it's old, yes I know, but it's simple, and I know how to use it). Happily, libraries for sending WOL pings from Node already exist, so the amount of code I needed to write was minimal. Having got the app running, I then needed to get it going on my Raspberry Pi. It's worth noting that my Raspberry Pi is the original model B+ from 2014.

The first thing I did once yoink was working was get it compiling to a Docker image with GitHub actions. It's on Docker Hub, if you're interested. I considered trying to run the Docker image on my Pi, but decided this was too much effort, since I would have to get my image compiling for architectures other than amd64. Instead, I decided I would just run it directly under Node. One small problem, though, is that node hasn't supported armv6 since 2019.

All hope is however, not lost, because there are unofficial versions of Node compiled for armv6. There's even a handy little script for installing it...except it hasn't been updated in 2 years. However, it was easy enough to just substitute in the url for the latest version, and we're off! At this point though, it occurred to me, why the hell hasn't someone written a proper install script for Node on armv6 which doesn't need manually updating every time a new version comes out. I took it upon myself to undertake such a task, and the result was this monstrosity of a python script (I haven't actually uploaded the code yet, but it should get there soonish). Anyway, with Node installed on the Pi, the app works great, and I could start my server from anywhere in the world (as long as it has internet)!

The day after creating yoink, my good friend mikaljo did the work for me, and updated the GitHub action workflow to compile for many exotic architectures, such as ppc64le, s390x, and crucially, armv6. With this, I was able to spend several minutes waiting for Docker to install on my Pi, but at least now I don't have to clone the repository to run it. Thanks, mikaljo!

So, it works, at least until the Pi undervolts and crashes because my power supply is terrible. I'll cross that bridge when I get to it.

This website is made entirely in vanilla HTML and CSS, templated with Nunjucks, and served by Express.js. Sometimes you don't need a UI framework!