alex's site

This week: I made this site!

by
alex
on

I made this site!

My spring term finished, so I decided I'd finally start some computer-y projects again. I've barely worked on anything computer-y since my cross-country coming-of-age move over a year ago, and now that life is finally slowing down a bit, I thought it'd be nice to get back into the flow of things.

I've had three domains for a while: sm64.us, tonsi.gay, and nim.cx. I had the site for sm64.us hosted on a friend's VPS, but I've had my own VPS for a while, and I'd been intending to move the site over and put something on the other two domains as well. So, that's what I did this week!

The main issue stopping me from doing it before was SSL. See, I have kind of a weird setup. I run my sites using Apache, and because I really like subdomains, I configured Apache so that subdomains correspond to subfolders in my document root. For example, http://test.nim.cx/index.html is served from /var/www/html/nim.cx/test/index.html, and subdomain-less http://nim.cx/index.html is served from /var/www/html/nim.cx/www/index.html.

This works great, buuuuuuut SSL is annoying because having an arbitrary number of subdomains means I need to get a wildcard certificate. I couldn't figure out how to do this with Let's Encrypt in the past, but coming back to the problem, I figured it out pretty quickly.

To initially obtain certificates, I ran this command:

certbot run --cert-name nim.cx -a manual -d nim.cx,*.nim.cx -i apache

This asks for a certificate covering nim.cx and *.nim.cx. When running this command, I actually had to complete two challenges; a DNS challenge and an HTTP challenge. Initially, I barely even knew what a "challenge" even was, so this didn't jump out to me as concerning, and I simply completed the challenges manually and bam! Certificates!

The issues came when trying to automate renewal, though. Given that I have three domains to do this on, that means six challenges I'd have to do manually to renew my certificates, which isn't great. So I looked into automation.

As it turns out, most of the automation solutions fail. I'm pretty sure this is because the renewal issues two challenges (and I think it issues two challenges because I'm covering both nim.cx and *.nim.cx with the same certificate). If a script is meant to automate DNS challenges, it won't be able to automate the HTTP challenge. I can set my preferred challenge to DNS (not HTTP because the wildcard requires DNS), but that would result in me getting two different DNS challenges that involve putting TXT records on the same name and... honestly that'd probably work? I dunno? To be honest I didn't really think about it this far lol.

Anyway what I ended up doing was writing a quick authentication hook script for certbot. One issue was that the same script is run for both challenges, despite them being... different... challenges... so I had to use the presence of the CERTBOT_TOKEN environment variable to figure out whether the current challenge was DNS or HTTP.

#!/bin/bash

if [ -n "$CERTBOT_TOKEN" ]
then
    echo "HTTP: Create http://$CERTBOT_DOMAIN/.well-known/acme-challenge/$CERTBOT_TOKEN => $CERTBOT_VALIDATION"

    DOCUMENT_ROOT="/var/www/html/$CERTBOT_DOMAIN/www"
    CHALLENGE_DIR="$DOCUMENT_ROOT/.well-known/acme-challenge"

    mkdir -p "$CHALLENGE_DIR"
    printf "%s" "$CERTBOT_VALIDATION" > "$CHALLENGE_DIR/$CERTBOT_TOKEN"
else
    echo "DNS: Create TXT _acme-challenge.$CERTBOT_DOMAIN => $CERTBOT_VALIDATION"

    SEC_KEY="..."
    API_KEY="..."

    payload='{"secretapikey":"'"$SEC_KEY"'","apikey":"'"$API_KEY"'","name":"_acme-challenge","type":"TXT","content":"'"$CERTBOT_VALIDATION"'","ttl":"600"}'
    endpoint='https://porkbun.com/api/json/v3/dns/create/'"$CERTBOT_DOMAIN"

    curl -s -d "$payload" -H 'Content-Type: application/json' -X POST "$endpoint"

    sleep 15
fi

So now I can just run this big command to renew!

certbot certonly --manual --manual-auth-hook [...]/certbot-acme-auth.sh --manual-cleanup-hook [...]/certbot-acme-cleanup.sh -d nim.cx,*.nim.cx --dry-run

Another approach I could maybe try is instead of having 3 domain,*.domain certs for each of my domains, having 2 certs, one containing the roots for all 3 domains at once and the other containing the wildcards at once. But then... I dunno, that seems a bit weird. But I might try it later.

Anyway, after I had the SSL for my sites set up, I was able to move sm64.us over from my friend's server. I had to change a bunch of stuff in my setup for the new paths but it all seems to work now.

Then, I got to work on this site! All the dynamic content on my sites is generated by CGI scripts written in NodeJS (which is exactly as cursed as it sounds). Currently, this site reads posts (like this one) from disk, processes them into static HTML, and then injects them into a template. I'll write more about it once my Markdown parser is finished. :)