Approach
My approach is largely manual, where it's interesting, and automated where it isn't. By automated, I mean triggering human-authored scripts to perform repetitive task (like deploying, or updating text).
This approach is based largely out of a desire to, I guess, be seen in some limited capacity. But while you might witness some flourishes, my style is still sadly pretty corpo-brained; perhaps because that's where I've spent most of my computer-life, or maybe I'm just that self-domesticated.
Dev Setup
Because I'm kind of corpo brained, I have a fairly formal setup. I've got a README.md, and a Dockerfile, and an example nginx.conf--lol, yup.
Kind of pathetic, I admit. But it does make for smooth developer experience when I come in trying to make some changes after months on hiatus elsewheres.
Some more specifics: I use the NPM package live-server to get live-reloading as I save.
I'm trying to keep the architecture/framework/tooling ((I'm sorry I can't help how I talk)) relatively low-impact (at least compared to what I'd be forced to make for work). So that means no ReactJS, no express, no "sythetics" (lol), and not even a webserver. It's just a plain old nginx container listening behind a reverse proxy.
Dockerfile
FROM nginx:latest
WORKDIR /etc/nginx
COPY ./config/nginx.conf ./
COPY ./config/derelict.ink ./
RUN mkdir html
COPY ./static ./html/static
COPY ./stubs ./html/stubs
COPY ./pages ./html/pages
RUN nginx -t
And a docker compose file for easy deploys. Which lets me do like DOCKER_HOST="ssh://${REMOTE_HOST}" docker compose up -d to redeploy to whatever remote(s) I want with minimal fuss.
compose.yml
name: derelict.ink
services:
web:
build: .
container_name: derelict.ink
ports:
- 127.0.0.1:1234:1234
I did this so I could take advantage of Server-Side Includes (SSI), because I wanted to follow the
Example SSIs
Note these are inside special "SSI Command" HTML comments (<--# -->), but wrapping them here would cause the command to be executed!
# set var="browser-title" value="Colophon"
# set var="page-title" value="🕳️🔍️"
# include file="/stubs/header.shtml"
Git hooks
I use this post-commit hook to make the changelog on the left.
#!/bin/sh
# Append breaks so we can source file directly
git log --format='%ad %s' --date=short \
| sed 's/$/
/' \
> static/text/changelog.txt
echo changelog.txt updated
exit 0
Okay, I've actually since updated this to an incredibly hideous sed one-liner that I'm not going to paste here. Shoot me an email if you want it, and I'll gladly share, though.
Version Control
I use git.
Specifically, I have several repositories. Local (obviously), one corp instance (you know the place), Codeberg, and backup on another VPS that I run.
Actually it's so easy to set up your own private git server. Cross-reference with any missing pieces here, but once you've got your git user set up, you can just do the following to add a backup for an existing repository:
From your git user's home dir (on the remote)
# Easiest to just scp a copy of the repo to the remote
# and use it, rather than faffing about with permissions
# pulling down a repo from some secondary remote...
git clone --bare /home/git/repo-name repo-name
# If you get this error when pushing:
# fatal: detected dubious ownership in repository at
# make sure file ownership is set to git user
chown -R git:git repo-name
Then from your working repository (on your local)
# Add an additional push target (fetch source (AKA source of truth))
# will still live at whatever you have before
git remote set-url --add --push origin git@example.com:repo-name
# Verify remotes
git remote show origin
Changelog
Here's a list of the dates and subjects of the git commits that have gone into making this website. See Git hooks under Dev setup for details on how its made.
2025-09-11 content:
2025-09-10 content(colophon):
2025-09-10 chore:
2025-09-10 content(colophon):
2025-09-10 content(home):
2025-09-05 content(home):
2025-09-05 content:
2025-09-05 style:
2025-08-30 content(colophon):
2025-08-30 content(colophon):
2025-08-30 chore:
2025-08-30 style(changelog):
2025-08-30 style:
2025-08-30 style:
2025-08-29 content(home):
2025-08-29 style:
2025-08-29 content(colophon):
2025-08-29 content:
2025-08-27 chore:
2025-08-27 chore:
2025-08-27 chore:
2025-08-27 chore:
2025-08-27 content:
2025-08-27 chore:
2025-08-27 content:
2025-08-27 refactor:
2025-08-27 chore:
2025-08-27 chore:
2025-08-27 chore:
2025-08-27 doc:
2025-08-27 chore:
2025-08-22 chore:
2025-08-22 content:
2025-08-21 chore:
2025-08-21 content:
2025-08-21 content:
2025-08-21 content:
2025-08-21 doc:
2025-08-21 content:
2025-08-21 chore:
2025-07-25 chore:
2025-07-25 chore:
2025-07-25 content:
2025-07-25 content:
2025-07-25 revert:
2025-06-02 chore:
2025-03-30 content:
2025-03-30 chore:
2025-03-30 content:
2025-03-30 content:
2025-03-30 content:
2025-03-30 doc:
2025-03-30 chore:
2025-03-30 feat:
2025-03-30 chore:
2025-03-30 doc:
2025-03-30 chore:
2025-03-30 content:
2025-03-29 style:
2025-03-29 content:
2025-03-29 content:
2025-03-29 content:
2025-03-29 chore:
2025-03-29 content:
2025-03-29 fix:
2025-03-29 content:
2025-03-29 content:
2025-03-21 content:
2025-03-21 chore:
2025-03-21 content:
2025-03-17 content:
2025-03-17 content:
2025-03-13 content:
2025-03-13 content:
2025-03-13 fix:
2025-03-13 content:
2025-03-13 content:
2025-03-12 content:
2025-03-12 content:
2025-03-12 fix:
2025-03-12 chore:
2025-03-12 chore:
2025-03-12 refactor:
2025-03-12 chore:
2025-03-12 content:
2025-03-12 content:
2025-03-12 refactor:
2025-03-12 refactor:
2025-03-12 content:
2025-03-12 chore:
2025-02-26 content:
2025-02-26 content:
2025-02-26 style:
2025-02-26 fix:
2025-02-26 style:
2025-02-26 content:
2025-02-26 style:
2025-02-26 content:
2025-02-26 style:
2025-02-25 style:
2025-02-25 style:
2025-02-25 doc:
2025-02-25 fix:
2025-02-25 style:
2025-02-25 content:
2025-02-25 style:
2025-02-24 style:
2025-02-23 content:
2025-02-23 style:
2025-02-23 init