Skip to content
Home
Open source · Personal project
← Selected work

Minnumst: a self-hosted family history archive

Minnumst (Icelandic: "let us remember") is a shared written history of our ancestors: a public archive for reading stories, an editorial desk for writing them, and an API that keeps every story revision. I built it end to end, from the app to the hardened host it runs on, so that the only thing reachable from the internet is a TLS-terminating proxy and every write is authenticated before it reaches the application.

Minnumst's public archive in dark mode: a name search beside a photo of Grafarkirkja, a turf church in Höfðaströnd
57 → 75
Lynis hardening index, scored in CI
254 → 0
Trivy findings, API image moved to Alpine
1
public entry point: Traefik

Network and access

  • Only Traefik publishes ports. HTTP redirects to HTTPS with Let's Encrypt certificates and HSTS, and the API is rate-limited.
  • Authentik forward-auth, with TOTP MFA, guards the whole editorial desk and every write to the API; reads stay public and there is no in-app login to attack.
  • PostgreSQL sits alone with the API on an internal network with no route in or out. Traefik discovers services through a socket proxy that only lists containers.

Host, provisioned as code

  • OpenTofu creates the Hetzner server, firewall and data volume, with state encrypted before it leaves the operator's machine.
  • Ansible hardens Ubuntu 24.04 to the CIS benchmark (Level 1, selected Level 2), with every setting citing its CIS section and NIST control: LUKS-encrypted data, unattended updates, key-only SSH, a default-deny nftables firewall and auditd.
  • Nightly database backups are encrypted with age to a key that never touches the server, and CI restores one into a fresh database on every change.

Containers and supply chain

  • Every container runs as non-root, with a read-only root filesystem, no Linux capabilities and no-new-privileges, on Alpine images pinned by digest.
  • Dependencies are locked, every GitHub Action is pinned to a commit SHA, and CodeQL, Trivy and zizmor scan the code, images and workflow on every change.
  • Releases are multi-arch images published with build provenance and an SBOM.

Verified, not just configured

  • A CI job applies the host hardening to a real Ubuntu 24.04 VM, requires a second run to change nothing, and reports the Lynis index before and after.
  • An end-to-end job runs the production Compose stack and checks the edge from outside: redirect, HSTS and CSP, refused unauthenticated writes, the rate limit and network isolation.
  • Playwright browser tests of both frontends fail on any Content Security Policy violation.
Technologies
  • OpenTofu
  • Ansible
  • Docker Compose
  • Traefik
  • Authentik
  • FastAPI
  • React
  • PostgreSQL