💾 Archived View for zozoandsqueak.ca › articles › tech › running-zozoandsqueak.gmi captured on 2023-04-26 at 12:50:25. Gemini links have been rewritten to link to archived content

View Raw

More Information

⬅️ Previous capture (2022-06-03)

-=-=-=-=-=-=-

running zozoandsqueak

hosting

my lab is split between a pair of proxmox [1] nodes that run at home and a single proxmox node running on a bare metal server i picked up on sale from ovh [2] a while back. a wireguard vm running in each location provides a private link between the two sites. most of the services running in the environment have been virtualized as either full virtual machines or through lxc containers, but a number of smaller services (including the gemini server) are running on the ovh node in a /miscdocker/ vm, which has typically been used for things that require very little resources (like gemini) or things that i'm just trying out and may migrate to a dedicated environment at a later date (like the grocy server i keep thinking will be a good idea, but never can quite get around to using). one of the proxmox nodes at home runs a virtualized k8s cluster that typically becomes the new home for dockerized apps that are no longer suitable for /misdocker/.

proxy

miscdocker is not directly exposed to the internet, so traffic ingresses through an haproxy instance setup to forward tcp traffic on port 1965.

the frontend:

frontend gemini_in
	mode tcp
	option tcplog
	bind :1965

	use_backend tcp_gemini_1965

the backend:

backend tcp_gemini_1965
	mode tcp
	server gemini miscdocker.chickenoncow.cloud:1965 inter 1000 check

gemini server

zozoandsqueak is using the dockerized version of the gemini server [3].

the command i'm using to start the server is slightly modified from the example provided on the github page:

docker run \
       -d \
       --restart=always \
       -v /etc/letsencrypt/live/zozoandsqueak.ca/:/certs \
       -e PORT=1965 \
       -e DOMAIN=zozoandsqueak.ca \
       -v /opt/zozoandsqueak/:/content \
       -p 1965:1965 \
       adrianhesketh/gemini:latest

certificates

you'll notice from the docker command that the certs are being generated by letsencrypt. i'm using dnsmadeeasy [4] to host DNS for zozoandsqueak.ca and they have an api that works with certbot for automated verification which is nice.

to generate the certificates, another docker container is being utilized, this one is created using an image that comes pre-populated with certbot and the dnsmadeeasy plugin.

docker run \
       --rm \
       -it \
       --name certbot-dnsmadeeasy \
       -v /etc/letsencrypt/dnsmadeeasy.ini:/dnsmadeeasy.ini \
       -v /etc/letsencrypt:/etc/letsencrypt \
       certbot/dns-dnsmadeeasy \
       certonly \
       --dns-dnsmadeeasy \
       --dns-dnsmadeeasy-credentials /dnsmadeeasy.ini \
       -d zozoandsqueak.ca

this generates a set of pem encoded files on the host

├── zozoandsqueak.ca
│   ├── README
│   ├── cert.pem -> ../../archive/zozoandsqueak.ca/cert1.pem
│   ├── chain.pem -> ../../archive/zozoandsqueak.ca/chain1.pem
│   ├── fullchain.pem -> ../../archive/zozoandsqueak.ca/fullchain1.pem
│   ├── privkey.pem -> ../../archive/zozoandsqueak.ca/privkey1.pem

the gemini server is expecting the key and certificate to be in the /server.key/ and /server.crt/ files respectively, so a quick and dirty script to be called as a post hook by cert bot when the certs renew takes care of that.

#!/usr/bin/env bash

DOMAIN=$1

if [[ -z ${DOMAIN} ]]; then
  echo "usage: rebuild_certs DOMAIN"
  exit 1
fi

cd /etc/letsencrypt/live/${DOMAIN}

rm -f server.{key,crt}

cp cert.pem server.crt
cp privkey.pem server.key

this gets mounted into the docker container from /miscdocker/ along with the letsencrypt and dnsmadeeasy config volumes into a script that will be called from a daily cron job

root@miscdocker:~# cat /usr/local/bin/renew_certs
#!/usr/bin/env bash

docker run \
       --rm \
       -it \
       --name certbot-dnsmadeeasy \
       -v /etc/letsencrypt/dnsmadeeasy.ini:/dnsmadeeasy.ini \
       -v /etc/letsencrypt:/etc/letsencrypt \
       -v /opt/letsencrypt:/script \
       certbot/dns-dnsmadeeasy \
       certonly \
       --dns-dnsmadeeasy \
       --dns-dnsmadeeasy-credentials /dnsmadeeasy.ini \
       -d zozoandsqueak.ca \
	--post-hook '/script/rebuild_certs zozoandsqueak.ca' \
	-n

the cron job just runs nightly and dumps its output to a log i can check when it invariably goes wrong

0 0 * * * /usr/local/bin/renew_certs > /var/log/certificate.log 2>&1

content and updating

i spend half my day writing in org-mode for work, and tried the /ox-gemini/ exporter but it left a bunch of garbage in the output, so i've reverted to just writing straight gemini markup. there's a /gemini-mode/ plugin that provides syntax highlighting and that's made me happy enough. i've just dropped the /gemini-mode.el/ into /~/.doom.d/lisp/ and the following bit of code in my doom [5] config loads it.

(add-to-list 'load-path (expand-file-name "lisp" doom-private-dir))
(require 'gemini-mode)

and this little snippet enables the mode for any file with the /.gmi/ suffix

;; automatically enable gemini-mode for *.gmi files
(add-to-list 'auto-mode-alist '("\\.gmi\\'" . gemini-mode))

the content for zozoandsqueak is stored in a private repository on sourcehut [7] and i'm just running a cron job on /misdocker/ to pull the repo into the host directory that's mounted into /content in the gemini container.

links

Proxmox

OVH

a-h/gemini

DNS Made Easy

Doom Emacs

gemini-mode

sourcehut