Adventures in the WWW.

Gianmaria Piergianni

How hard could it be to write and host a website without breaking the bank?

Well, let's just say that it isn't as easy as you may expect...

Introduction

First thing first, let me explain why putting all the effort behind making a website in the first place: I had some free time and a spare Raspberry Pi Zero W laying around on my desk (which I was using as a pwnagotchi) and I thought to myself that I could get much more use out of that sweet ARM chip.

The last picture of my beloved wtx

Little did I know that using a six years old processor would be so problematic.

Registering a free domain

The first step was to register a domain on the web -a text based lable with the only advantage of being easier to memorize than the website IP- possibly with my name on it.

The first service that came to mind was "Ngrok": a service that allows developers to expose local servers to the web by tunneling a connection from the localhost to a ngrok domain.

Issue is you don't get to choose (or associate) a custom domain without a "premium account" and your website is blocked off to first time visitors by a warning which disappears only if you have session cookies or a custom header in the client's request.

An example of what my page looked like when hosted with Ngrok

Since i was not willing to have a website that looks like a phishing scheme, I went back to the drawing board and started doing some research.

I came across a domain registrer for "eu.org" subdomains (nic.eu.org) and, after signing up to some sketchy websites that promised to provide working nameservers, I finally managed to apply for two domains under my name using the cloudfare basic account.
However, since every application is checked by hand, I may have to wait a couple months before i can migrate this website to the new domain.(The current one was bought for 0.91 euros from Namecheap, that's why it's almost free).

Now that we have a domain we just need some way to host our website.

Trasforming my Raspberry Pi into a server

Finally we can dwelve into the technical side of the project: programming the server and getting the package to run on my ancient Raspberry Pi Zero W.

At first I thought that the best way to run a server on a computer the size of half a credit card was to use baremetal rust but, since even the most basic crate that handles HTTP requests does not have support for a no_std project (most are based on the mio crate which requires an OS for its I/O event queue as it makes frequent use of epoll calls), I had to install some lightweight linux distro.

Initially I intended on using Arch Linux as I am quite familiar with it and -despite not being official- there is a port for ARM processors. Much to my disappointment, I soon discovered that the development of Arch for ARMv6 processor has been discontinued since February 2022 and I could not find a valid image file to flash on the SD card on any of the unofficial archives.

Not willing to spend any more time looking for answers on ancient forums, I decided to just use the lite version of the Raspberry OS.
While I was downloading the necessary files I rememberd that the computer I used to flash the SD card broke down months ago and my current one does not have any SD slot on the I/O panels.

Determined to finish what I started, I tore down the old PC and retrieved the reader which I connected to the motherboard using the USB headers and was ready to flash the OS on the chip.

If someone is trying to follow along, I advise using the Raspberry Pi imager as it allows you to set a SSID and password for your network and turn on SSH without having to mess with any of the system files.

setting-raspberry-1setting-raspberry-2
Settings I used when flashing the image to my SD

Now that my Raspberry was ready I could start programming the web server...

Coding a simple web server

Now the grand finale: writing the rust script to run the server. Everything is pretty straight-forward if you have any experience with the tokio or hyper crate.
(up to date code can be found on my github profile)

The main loop only consists of creating a service from a generic function "serve_request"

pub async fn server() -> Result<(), Infallible>{

        let make_svc = make_service_fn(move |conn: &AddrStream| {
        let addr = conn.remote_addr();

        let service = service_fn(move |req| { 
                serve_request( req ,addr)
        });
        async move {Ok::<_, Infallible>(service) }
});
            
And the function itself with a "match" statement:

[...]
match (req.method(), req.uri().path()) {
         (&Method::GET, "/") => {
            let body = fs::read_to_string("main.html").await.unwrap();
            let body = body; 
            Ok(Response::builder()
                .header("Content-Type", "text/html")
                .body(Body::from(body))
                .unwrap())
        } 
[...]
            
Remember to link the relevant css page into every html and to add an arm to the match statement for your main.css file.

Now just connect to localhost using a custom port (I will use 7878 but as long as you don't pick one used by some other protocol it will not cause any problem).

let addr = ([127, 0, 0, 1], 7878).into();
let server = Server::bind(&addr).serve(make_svc);
            
And we are basically set.

Building and Hosting our website

Now we just need to build the application (remember to specify the arm architecture as a target otherwise you won't be able to run it on the Raspberry chip) and I will use "CloudFlare" to tunnel the connection to my new domain.

Ipotetically you could build the application directly on the Raspberry but, as you can probably see from the screenshot, it will not be a fast process to say the least.

1700951191

I will not describe the process of creating and running a CloudFlare tunnel as it is well documented and easy to follow.

Just a heads-up, if you are using an ARMv6 chip you will not be able to install or run the latest package. In order for it to work you have to download an earlier build (files can be found here, for some reason any package after version 2023.8.1 is empty or not working).

Conclusions

Finally we proved that it is possible to have a perfectly working website using some inexpensive components and lots of patience.
That said, I strongly advise to buy a newer chip if you are going to attempt this project. Compatibility issues are not fun to deal with, and a more performant device means not having to worry too much about the complexity of the program or the number of concurrent visitors.

I will try to improve the code by adding logging functionalities and changing the style of the site (the css is heavily inspired by another tech blog).

UwU