Bored? Make Something!

10th June 2020

Making Things Quote Of The Day Blazor Raspberry Pi Nginx

I got bored the other day. As I'm sure lots of people have been over the past few months in lockdown. When I'm bored I make things! Without access to a workshop of some kind, more or less all of my making these days is coding projects or writing. I am spending more time than ever at a computer. At times like this, it is challenging, spending so much time looking at a screen. I have also been spending lots of time working on my side projects. This particular boring day, I didn't feel like working on my side projects (because it felt like work) and I had nothing to really do. I wanted to build something that I WANTED to build, not that I felt some sort of obligation to build.

I've talked before about how I approach coming up with something to build; or rather if I should bother to build something at all. Sometimes I have an idea about trying out a new technology but I'm not really sure what exactly to do with it. Often spinning up the 'Hello, World' for a particular framework or language isn't really satisfying for me. I usually like to have some sort of either useful or slightly-pointless-but-interesting use case to try it out with. In the case of this article it's Microsoft's offering in WebAssembly, Blazor.

I started looking at Blazor... and very quickly lost interest. There is something that happens to me when I get into that "I'm bored" state of mind - I just lose interest in doing anything (even if I normally really enjoy it). I think many people can relate to this, I have loads I could do but I'm just not bothered. For me, what usually breaks this is either physical exercise, or if I get a random spark of inspiration. I had exercised lots the day before so I wasn't interested in doing more (and I think it was raining). However, I did get a random spark of something to play with.

I studied electronic engineering in college and I have a big box of electronics parts, micro controllers and electric motors in my wardrobe. I do love hobby electronics, but I also live in a small apartment and don't have the space for a little workbench or anything. For this reason, the box of parts sits neglected in my wardrobe and never get used. Among the parts is a Raspberry Pi 3 Model B+; on this day, my spark of inspiration was to dig it out and do something web related with it using Blazor.

"Hey, why don't I see if there is some sort of 'quote of the day' API out there... and why don't I make a website that will just render a quote for the day in a browser when I hit the home page... and if I leave it on my home network then I can get a quote of the day to look at each day at raspberrypi.local on my home network!"

So I had the spark, I had the idea of what tech I wanted to use, but I didn't have an idea for what to actually make the thing do! A random thought popped into my head; "Hey, why don't I see if there is some sort of 'quote of the day' API out there... and why don't I make a website that will just render a quote for the day in a browser when I hit the home page... and if I leave it on my home network then I can get a quote of the day to look at each day at raspberrypi.local on my home network!". Sorted! I now knew what I wanted to build and what I wanted to build it with. I was ready to scratch the "build something" itch and it matched up with my criteria for building something. It was interesting to me, it involved some tech I hadn't used before and it served a purpose (however silly and pointless it might be). I was excited, I wasn't bored anymore!


Pi, why you gotta be like this?


The first thing I had to do for this project was to get my Pi up and running. It had been a while since I last used it and I was pretty sure the memory card that had the OS was long overwritten with other stuff. So I dug out a fresh memory card and started by installing a new OS. This is something I have done in the past many times and I always found it a bit of a pain, until now. I found some improved tooling which made the process really easy. The Raspberry Pi Imager tool is a breath of fresh air, insert the card into a reader, pick your OS and click write (I went with the Raspbian Lite OS). The tool now does everything, formatting the card, writing the image and done. This is where the happy Raspberry Pi times ended unfortunately.

please, please, do not leave a Pi on your network with the default password

I decided to set up the Pi in headless mode as I didn't plan to install a graphical user interface. This is fairly simple to set up, you simply add some config files to the boot disk before first boot which enables SSH immediately and configures wireless network access. All that should be left to do is power the device. It should boot, automatically connect to your WiFi and enable SSH. It couldn't be that simple though could it? No, it wasn't! I couldn't find my Pi on the network. My router wasn't showing the device even though it seemed to be booting correctly. Now began a cycle of flashing and reflashing the OS over and over trying different things to make it work. I plugged it into the router via ethernet, validated it was booting, messed around with the networking config to try figure out what was wrong. After hours and hours of toil, I eventually found out that the wireless chip in my Pi was broken - no amount of software hackery would make this work. At this point I shrugged and did what I would have done initially, plugged it in beside my router and left it connected via ethernet ¯\_(ツ)_/¯.

So my Pi was now on my network, SSH was working and I had changed the default password (please, please, do not leave a Pi on your network with the default password). So the next step was setting up the Pi to be able to run a Dotnet Core app.


Dotnet Core & Blazor


To run a Blazor app I would need to install the Dotnet Core 3.1 SDK. This is a pretty straightforward operation for most commercial operating systems but involves a little more work on the Pi. There is a great step by step tutorial here which you can follow for how to install the SDK onto your Pi. This isn't terribly complicated for anyone who knows their way around a Linux file system and command line.

With the SDK installed, it was time to test it by spinning up an new Blazor Server app and running it. Thankfully the Dotnet CLI makes this very easy. Under your desired directory simply execute dotnet new blazorserver QuoteOfTheDay. Now we have a ready to use Blazor Server app ready to run on our Pi. To run the app simply execute dotnet run in the root directory of the project. This will start the app listening on http://localhost:5000 by default.

In my case I wanted more than just the 'Hello, World!' of Blazor apps running. So I needed to modify the template app that the CLI created for me. However, my app code is running on a remote host without a UI and I am NOT a Vim guy (no offence to Vim people, I just can't bring myself to learn how to use it for more than editing small config file). My go to text editor/IDE is VS Code. To solve this problem I used the wonderful VS Code remote development tooling. This is a great tool set which allows you to SSH onto a remote machine and edit files in your IDE that reside on your remote machine. With these tools set up, I started to remove all the code I didn't want from the Blazor template and started building out the features I wanted.

There are some great things out of the box with the Dotnet Core framework. In memory caching and a http client are available out of the box with the built in DI framework.

I'm not going to go in depth on the implementation details of QuoteOfTheDay app I built, if you are interested you can find the source code on my Github. However, I will give some of the broad strokes. As I mentioned earlier, Blazor is Microsoft's WebAssembly offering. In the context of the Dotnet ecosystem, this means that you can write C# code to control your web apps front end instead of JavaScript. This code is then compiled into a binary that can be executed natively by your browser. WebAssembly is still in it's early days but it starting to generate interest and wider support. Some positives of it are, killing JavaScript (yay, I HATE JS) and fairly wide support across major browsers.

Lets take a look at some of the fun stuff in building this app. There are some great things out of the box with the Dotnet Core framework. In memory caching and a http client are available out of the box with the built in DI framework. Both of these were used in the app linked above. The basic flow of the app is as follows, the home page is hit, this causes the app to call out to the They Say So API to get the quote of the day. The response is then cached before rendering it on the UI. The caching is needed as the API has a rate limit of 10 requests an hour unless you pay for it. As the quote of the day data wont change until the next day anyway, caching works great here.

You might think that the project is done, we wrote our app and it seems to work pretty nicely. However, you will remember earlier on I said the app was running by default on http://localhost:5000. This is is fine if you are accessing the website from inside the Pi, but on the rest of the network, there is no port exposed which routes to this, so the website isn't wont be accessible to any other device on the local network. The next step is to make the Pi accessible on the local network.


Reverse Proxy & App Service


There are many different ways to make your app accessible to your local network while running on the Pi. By default, ports 80 and 443 are open on the Pi. These are the standard http and https ports. You can address a Pi on your network by hitting http://raspberrypi.local in your browser. This will try to create a http connection to your Pi on port 80. If you have nothing set up to listen to this, then your Pi wont respond in a meaningful way.

Nginx is a very commonly used and easy to configure reverse proxy server

It is possible to make your Dotnet app respond directly to request to your Pi running on the built in Kestrel server. However, Kestrel was never designed to be used directly on the internet. I know we aren't planning on running this app on the public internet, but, lets just pretend it is a do some good practice stuff. So what we need is a reverse proxy server. This server will run on our Pi and listen on ports 80 and 443. Requests to your server on these ports will then be routed to an app running internally on some port. In our case, we will route requests to http://raspberrypi.local, to our app running on http://localhost:5000.

For our reverse proxy server, we are going to run Nginx. Nginx is a very commonly used and easy to configure reverse proxy server. This will run as a background service on the Pi and will start up when the Pi boots. With that in mind, we might also like to run our Blazor app as a service, which will also start when the Pi boots after Nginx starts. This means each time the Pi is rebooted or power cycled, the reverse proxy will come online, followed by our app, and will successfully begin serving requests again instead of manually having to start the app service.

I have some what glossed over the implementation of the above steps and just given the broad strokes on accomplishing the task. However, I used a fantastic blog post as a reference for some of the above. The post goes through the steps of installing Nginx on a Pi and configuring an app to run as a service behind the revers proxy, you can read it here.


Conclusion


With all of the above steps in place, we now have a wonderfully simple and robust web app, running on our local network, which will give us a quote of the day!


I hope you have enjoyed this article on being bored and building something. Hopefully by reading this you might have been inspired to dust off something you have lying around to tinker with. Building something is never a waste of tim, and building silly things can be as useful as building useful things. For me, it's all just experience. Finally, don't get down when you are bored and can't think of anything to do, look for that little spark, you can find it almost anywhere. If you are a maker and you are bored, just make something, anything, no matter how silly! It's hard at a time like this, we are all struggling in one way or another... Bored? Make something!


Happy making things!
- Ian