Well, this tale begins off of my dive into the indie web. One of the projects I came across was a tattooed qr code on someone’s arm, which seemed like a cool idea. However, it made me consider something: what if you want to reprogram it after the fact? Well, simple solution, you can just use a link shortener, and rewrite the link. Deciding to consider trying out a qr code tattoo, or a sticker that would be left up somewhere, I started looking into a way to run a link shortener. I wanted to self host, so I wouldn’t need a paid subscription to bitly or something, so Shlink seemed like a good option. I figured it’d need a volume or something, but no. It wanted a database… and an api key?
The database bit seemed… fine, I guess, but the api key seemed weird to me. Looking into the documentation, it seemed to be for telemetry. Wait, why does a link shortener need telemetry? I mean I could just not use it, but then the Bad Thoughts started to begin. If I didn’t want the telemetry, it would be left in as bloat. How much extra bloat is there?
Looking further, I found out that Shlink also uses an external site to add links. Hold on, what’s the point of self hosting if I just use an external site to configure it anyways?
At that point, I decided to try writing my own link shortener, with blackjack, and hookers a declarative configuration. For my use case, I’d be using configmaps and technically GitHub for storing the config, but I could self host that or use a local file or something if I wanted. I also thought “you know what, it’s a simple project, and I’ve been wanting to work on learning rust anyways. Let’s use rust!”, which is how this super simple project got blown way out of proportion.
Assuming that whoever reading this hasn’t tried programming in rust, it’s a very low-level language. This is great in terms of removing bloat, but means that it sucks ass for high level things such as, wouldn’t you guess, web development! I found a few different web frameworks in rust, but the most common seemed to be actix-web. I decided to go with that, as it seemed simple enough from the example code. Oh how wrong I was.
The first bit was getting a server of any kind up and running. Easy peasy, copy the demo code, and we’re rolling. The next was to use a hashmap to store the paths and links. Got that made, and onto redirects based on the path… okay, a little harder than expected. I had to use a responder type, added as a service, and then realized the painful fact that: RUST TYPES ARE CONFUSING! We have strings, str, &str, which are all apparently different things, not to mention static types and lifetimes. Also, global values are an unexpected pain in the ass! I didn’t anticipate needing an extra library to create a hashmap as a global variable. I could’ve made two aligned vecs, but I don’t know if that would make things any easier. Regardless, I was able to get paths from a global variable, and initialize that global variable using a table type from a .toml file.
Next up was automatically building the program in a docker container, so it’s easy to deploy to kubernetes. I pretty much copy-pasted the templating from my blog, and adjusted it to build and package a rust program. Sadly, I’m not aware of a way to only install the dependencies for a rust program, although I’m probably just missing something. This was easy to get working, except for running the program… every time, I’d get a “no file found” error. I’d try copying the file to different spots, copying some additional files over, hoping it’d work. No luck. I gave up my trying, and googled it, finding out that I was just missing libc. Then I had a fun 3 hours debugging a dns error, as the container couldn’t download the apk. I tried a different package names, updating the repo, till I realized the issue.

Of course, as soon as that was fixed, and I added a config volume, it worked great.
Now that all of that nonsense was figured out, and my code was in a working state, I decided to try and make it a little better, and less janky. I had to ask on discord how to pass through some additional values to the service, which I was able to get some very kind advice on from someone who went by sabrinajewson. Setting up the value worked, but I had to struggle with some rust type bs and statics, but eventually got it working. The project is pretty simple, and the build and deploy code ended up being longer than the actual program (so far at least…), but it’s working enough to deploy. I’m most likely going to continue working on it, and probably going to add some extra features, and maybe a better way to read data from a configmap on kubernetes. And a readme I’ve got to write… why is a functioning project so much work?
