Stonethorpe — personal web platform
.NET 10 · ASP.NET Core · Blazor · SQLite · Caddy · Linux VPS
Three production ASP.NET Core applications — a real business's site, an Azure-DevOps-style project tracker, and this portfolio — designed, built, and operated solo on one small Linux VPS.
At a glance
- Three independent .NET 10 apps behind one Caddy reverse proxy, each a Kestrel process under systemd with its own SQLite database
- A live business runs on it: online booking with consent-gated SMS reminders and Square card-on-file for no-show fees — no card data stored
- Column-level encryption for client personal data; the app refuses to start without its keys
- Azure-DevOps-style project tracker in Blazor Server: work items, boards, and GitHub branch/commit linking
- Owner-editable page content inline in the site — no CMS bolted on
- Deliberately boring operations: tarball deploys that can never clobber data, EF migrations at startup, hardened SSH, secrets outside the repo
Overview
Stonethorpe is the umbrella for the web software I run in production: the site and booking system for a working lymphatic-massage practice (advancedlymph.com), the project tracker I manage my own work with, and the portfolio you are reading. All three share one modest VPS and one operational philosophy — small, self-contained, and cheap to keep healthy.
It exists because shipping for real users is different from shipping demos. The business site takes real bookings from real clients, which is why it has the unglamorous parts: SMS reminders that fail closed unless the client has explicitly opted in, a no-show fee held as a Square card-on-file so no card number ever touches the server, and personal data encrypted at the column level with keys the application cannot boot without.
Operationally it is one person's platform, so everything is optimised for low ceremony: Caddy terminates TLS for all three domains, each app is a systemd service, deployments are a publish and a tarball that extracts over the top — schema migrates itself at startup, and the data can't be deployed away. It is the small-scale version of the discipline I build for clients.
Highlights
One VPS, three applications
Caddy reverse-proxies three domains to three Kestrel processes, each an independent systemd service with its own database and secrets. An app can be deployed, restarted, or broken without touching its neighbours.
A real business on top
The massage practice's site handles scheduling end to end: bookings, client records, and SMS reminders. Consent is the gate — no client is ever texted without an explicit opt-in, and the default is off.
Payments without card custody
No-show protection uses Square card-on-file: the card lives in Square's vault, the server keeps only a token, and the flat fee can be charged without the platform ever seeing a card number.
Personal data encrypted at rest
Client-identifying fields are encrypted at the column level, with a separate index key for searchable fields. The keys arrive by environment — without them the application refuses to start, so an unencrypted deployment is impossible rather than merely discouraged.
Project tracker with GitHub integration
A Blazor Server tracker in the Azure DevOps mould — work items, boards, sprints — with branches and commits linked to work items, so the history of a feature reads end to end.
Deployments that can't destroy data
Publish, tarball, extract over the top, restart: static content is replaced, databases and uploads are never touched, and EF migrations bring the schema forward at startup. Content edits made in production stay in production.
Screenshots
Tech
.NET 10 C# ASP.NET Core Razor Pages Blazor Server EF Core SQLite Caddy systemd Linux (Hetzner VPS) Twilio Square API