Building my personal Swiss Army Knife website, Part 2

Curious software engineer
Search for a command to run...

Curious software engineer
I use Digital Ocean, it's not the cheapest, but it's ok. I pay like 6 USD a month.
In this series, I will treat subjects related to software development, software engineering, and related career.
How it works?
It’s the summer holidays, after all. So I wanted to spent some time with my 7 years old daughter to teach her programming. ⌨️ I spent some time before discussing with her some of the basics concept verbally: the different parts of a computer, and bas...

This article is a follow up on my previous one introducing the concept of SE Spectrum: https://sonny.alvesdi.as/a-better-way-to-discuss Existing solutions For long, the easiest way to run a spectrum was to use visual drawing or diagram tools like ...

Introduction to SE Spectrum

One of the greatest tool available on GitHub is Dependabot. For those not familiar with it, in short it's a bot reviewing your list of dependencies and proposing PRs to update them. https://docs.github.com/en/code-security/getting-started/dependabot-...

Photo by Harli Marten on Unsplash As long as I remember I have always been interested by skepticism. And I think one element that really resonated with me has been that conference talk by Phil Plait: https://www.youtube.com/watch?v=FrFRbGjUtJk 15 ...

I would like to present you the v0.0.1 of my Swiss Army Knife services website!
I decided to call it utile.space.
Utile because it is a synonym of useful and comes from French! And .space because it sounded adequate.
Also, I made the source code freely available:
As I introduced in my introductory article, I am going to share with you my development journal.
Note that there is already too much to talk about in this version. So I am going to split my journey into many articles.
I started the journey by getting a new NGINX server conf for my new domain utile.space. And setup SSL with certbot like described in my article.
server {
server_name utile.space;
location /ip/ {
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Host $http_host;
proxy_pass http://127.0.0.1:8080/;
}
location /pdf/ {
alias /usr/share/nginx/html/pdf/;
autoindex on;
}
listen 443 ssl; # managed by Certbot
ssl_certificate /etc/letsencrypt/live/utile.space/fullchain.pem; # managed by Certbot
ssl_certificate_key /etc/letsencrypt/live/utile.space/privkey.pem; # managed by Certbot
include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
}
You can notice two extras things.
I have lots of free and useful PDF resources that I wanted to reshare. So I declared a location to allow me to share them. Note that to make those files visible publicly, I used the instructions: autoindex on.
See the results at https://utile.space/pdf/
I already had my tool to get IP on ip.alvesdi.as from the following article.
So I added a reverse proxy to reuse it. I got some issues because I was missing a trailing slash on the reverse proxy and location, I believe. Something I should investigate later to properly understand the problem.
See the results at: https://utile.space/ip/
I had a sample go project running on Docker in my personal library. So I started from that template.
Here was the Dockerfile:
FROM golang:latest AS build
WORKDIR /go/src
COPY server.go .
RUN CGO_ENABLED=0 go build server.go
FROM scratch AS runtime
COPY --from=build /go/src/server /
EXPOSE 3000/tcp
CMD ["/server"]
I use the latest golang image to compile server.go into a binary. Then I copy that binary into a new image based on scratch. Scratch, which is an empty image basically.
You may have noticed I prepend CGO_ENABLED=0 in front of go build. This is to make sure the binary would be compatible with the scratch image. Otherwise, it would not.
I started with something easy. I started with the rolling dice feature. My goal was to have an endpoint that could allow me to roll a die of any faces between 2 and 100.
Please find the code below.
package main
import (
"fmt"
"net/http"
"math/rand"
"strconv"
"regexp"
)
func home(w http.ResponseWriter, r *http.Request) {
// evaluate only if i in [2-100]
re := regexp.MustCompile("/d(100|1[0-9]|[2-9][0-9]?)")
match := re.FindStringSubmatch(r.URL.Path)
if match == nil {
http.Error(w, "Bad request", http.StatusBadRequest)
return
}
dice, err := strconv.Atoi(match[1])
if err != nil {
http.Error(w, "Unknown error", http.http.StatusInternalError)
return
}
fmt.Fprintf(w, strconv.Itoa(rand.Intn(dice)+1))
}
func main() {
http.HandleFunc("/", home)
http.ListenAndServe(":3000", nil)
}
I went with one endpoint only and would parse the location using a regular expression. For those allergic to regular expression, sorry, that's kind of my kink ^^
Anyway, let me explain it. "/d(100|1[0-9]|[2-9][0-9]?)" means first I am expecting to receive a request that will start with /d. Then in parentheses, I specified 3 different cases, consider the | as a simple "or". Then the request is either /d100, between /d10 to /d19, or finally between /d2 to /d9, and because of the ?, /d20 to /d99. I end up covering any case between /d2 to /d100.
With the regex, I capture the number n of the faces. And I use it with the function rand.Intn to generate a pseudo-random number. I also add 1 to it to make sure the result is between 1 and n.
With that, I ran a docker container on my server and plugged it into a new location in my NGINX server conf.
location /api/ {
proxy_pass http://127.0.0.1:3000/;
}
As I said, I am doing this as a hobby, so it has to give me quick results and not take me too much time to develop. So I started easy ;)
In the next articles, I will describe the following of my journey. I will discuss the beginning of my experience with Dart and the first problems I had on the front-end. I will also go through the deployment scripts I wrote to have a rough automated process to publish my work. Lastly, I will explain how I made the logo, I am not a designer, and I think I came with something not bad. And I want to show you it's not that complicated to do.