- HTML 69.9%
- Python 16.7%
- CSS 13.4%
| Filename | Latest commit message | Latest commit date |
|---|---|---|
One post per project that did not have one yet, written from each project's own material rather than a summary of the card blurb: - The IP scanner post covers the actual mechanism - the unprivileged ICMP interface each OS provides, why alive/filtered/dead are three answers and not one bit, and the mDNS/NetBIOS naming measurement. - The Vortex post is about the Synchronet backup recovered in August, and why six years of daily call logs turned out to be the part worth having. - The BBS HQ post is about keeping a directory honest by redialling it, and rendering each board's ANSI as text instead of a screenshot. The IP scanner post originally used a Markdown table, which is dropped in favour of a list: styles.css has no table rules, so it would have been the site's first and rendered unstyled. Co-Authored-By: Claude Opus 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01W8MK9iamaX3fXBy99oqQsw |
||
| assets | ||
| blog | ||
| contact | ||
| posts | ||
| build.py | ||
| index.html | ||
| README.md | ||
| styles.css | ||
badcluster.dev
Source for the Bad Cluster site. Static HTML/CSS, no JS framework, no build tooling beyond a small Python script that generates the blog pages from Markdown.
Structure
index.html Generated - home page (don't hand-edit, see build.py)
styles.css Shared stylesheet for every page
assets/ Images
blog/ Generated - blog index + one folder per post
contact/ Generated - contact page
posts/ Source - Markdown files, one per blog post
build.py Regenerates index.html, blog/, and contact/ from
the content below and posts/*.md
Anything under blog/ or contact/, plus index.html itself, is build
output. Hand-editing those will work until the next python3 build.py,
which overwrites them. Edit posts/*.md for blog content, or build.py
itself for the home page, header/footer, or page templates.
Adding a blog post
Create a new file in posts/, named however you like (the date in the
filename is just for sorting convenience - the real date comes from
frontmatter). Format:
---
title: Your Post Title
date: 2026-07-04
summary: One sentence, shown on the blog index page.
---
Body in Markdown from here on. Headings, links, lists, `inline code`,
and fenced code blocks all work.
Then rebuild:
python3 build.py
Requires the markdown package: pip install markdown.
Editing the home page or templates
The home page content, header, footer, and page shell are all defined as
Python strings in build.py (see build_home(), render_header(),
render_footer(), page_shell()). Edit those, then rerun the build.
Contact form
The contact form posts to Formspree. To make it actually deliver messages to you:
- Create a free account at formspree.io and add a new form.
- Copy the form endpoint URL it gives you (looks like
https://formspree.io/f/abcd1234). - In
build.py, replace theFORM_ACTIONplaceholder with that URL. - Rerun
python3 build.pyand redeploy.
Until that's done, the form is wired up correctly but has nowhere real to
send to - build.py will print a reminder every time you build if the
placeholder is still in place.
Local preview
Browser security blocks the page's absolute paths (/styles.css, etc.)
when opened directly as a file:// URL. Serve it locally instead:
python3 -m http.server 8000
Then open http://localhost:8000/.
Deploying
Hosted on oracle1, served by nginx, git-based: /var/www/badcluster.dev
on the server is a clone of this repo (origin =
git.badcluster.dev/arelas/badcluster-site). No GitHub Pages, no CNAME
file, no separate build step - the generated files are committed, so a
pull is the whole deploy.
You log in as ubuntu, but the checkout is owned by opc, so run git
as opc:
ssh [email protected]
sudo -u opc -H git -C /var/www/badcluster.dev pull
Plain git as ubuntu fails with "detected dubious ownership". Don't
fix that by adding the directory to ubuntu's safe.directory - the
warning goes away, but the pull then writes ubuntu-owned files into an
opc tree and the next deploy breaks in a stranger way.
The pull also refuses to run if the server's working tree is dirty,
which is what happens when a page gets edited on the server directly.
Check sudo -u opc -H git -C /var/www/badcluster.dev status first, and
make sure whatever is in there has been brought back into this repo (as
a build.py change, rebuilt) before discarding it:
sudo -u opc -H git -C /var/www/badcluster.dev checkout -- .