[{"content":"HomeStack is a privacy-focused home infrastructure project built for a family of three. Everything runs on a single-board computer at home — no cloud dependencies for the services that matter most.\nThe stack covers identity and access management, file storage, photo management, a knowledge base, financial tracking, and encrypted off-site backups. Every service is integrated with single sign-on, monitored, and backed by a tested recovery procedure.\nStatus: Live since May 2026. Part II in progress.\nDashboard # A public status dashboard is coming — live service health, uptime, and stack metrics.\nRead how it was built # The full build history is documented as a series of notes — the decisions, the trade-offs, and what went wrong along the way.\nRead the HomeStack Part I series →\nRead the HomeStack Part II series →\n","date":"10 May 2026","externalUrl":null,"permalink":"/projects/homestack/","section":"Projects","summary":"A self-hosted infrastructure stack running on a Raspberry Pi in the living room. Replacing Google Photos, cloud storage, a password manager, a wiki, and financial tracking with something owned, documented, and proven to be recoverable.","title":"HomeStack","type":"projects"},{"content":"Home Assistant as the brain. Local control for lights, climate, energy, and security cameras — no cloud dependencies, no data leaving the house. Integrated with the HomeStack identity layer.\nPlanning: TBD\n","date":"10 May 2026","externalUrl":null,"permalink":"/projects/smart-home/","section":"Projects","summary":"Home Assistant as the brain. Local control for lights, climate, energy, and security cameras — no cloud dependencies, no data leaving the house.","title":"Smart Home","type":"projects"},{"content":"A dedicated inference server for the family. Open source models running locally — for document analysis, search, and daily assistance. No prompts sent to external APIs, no training on family data. Built on the foundation HomeStack provides.\nPlanning: TBD\n","date":"10 May 2026","externalUrl":null,"permalink":"/projects/private-ai-llm/","section":"Projects","summary":"A dedicated inference server for the family. Open source models running locally — for document analysis, search, and daily assistance. No prompts sent to external APIs, no training on family data.","title":"Private AI \u0026 LLM","type":"projects"},{"content":"","date":"25 May 2026","externalUrl":null,"permalink":"/tags/adguardhome/","section":"Tags","summary":"","title":"Adguardhome","type":"tags"},{"content":"","date":"25 May 2026","externalUrl":null,"permalink":"/tags/authentik/","section":"Tags","summary":"","title":"Authentik","type":"tags"},{"content":"","date":"25 May 2026","externalUrl":null,"permalink":"/tags/borgmatic/","section":"Tags","summary":"","title":"Borgmatic","type":"tags"},{"content":"A server in the living room. A family depending on it. I advise governments on digitalisation and IT governance — at home, I practice what I preach.\nEvery note follows the same thread: why a decision was made, what it meant for the people it was built for, how it worked technically, and what the project keeps teaching me. From the strategic to the operational. From the technical to the human.\nMost homelab blogs show you how. These notes ask why — and what it means when the system you built is the one your family depends on. Enterprise thinking, a Raspberry Pi, and the obligation to explain every decision to a non-technical family and to yourself. The notes are where that story lives.\n","date":"25 May 2026","externalUrl":null,"permalink":"/","section":"Built for a family. Running in our home. Enterprise thinking. Learning by doing. Documented honestly.","summary":"A server in the living room. A family depending on it. I advise governments on digitalisation and IT governance — at home, I practice what I preach.\nEvery note follows the same thread: why a decision was made, what it meant for the people it was built for, how it worked technically, and what the project keeps teaching me. From the strategic to the operational. From the technical to the human.\n","title":"Built for a family. Running in our home. Enterprise thinking. Learning by doing. Documented honestly.","type":"page"},{"content":"","date":"25 May 2026","externalUrl":null,"permalink":"/series/homestack-part-ii/","section":"Series","summary":"","title":"HomeStack Part II","type":"series"},{"content":"","date":"25 May 2026","externalUrl":null,"permalink":"/tags/incident/","section":"Tags","summary":"","title":"Incident","type":"tags"},{"content":"","date":"25 May 2026","externalUrl":null,"permalink":"/tags/msmtp/","section":"Tags","summary":"","title":"Msmtp","type":"tags"},{"content":"","date":"25 May 2026","externalUrl":null,"permalink":"/notes/","section":"Notes","summary":"","title":"Notes","type":"notes"},{"content":"","date":"25 May 2026","externalUrl":null,"permalink":"/tags/operations/","section":"Tags","summary":"","title":"Operations","type":"tags"},{"content":"","date":"25 May 2026","externalUrl":null,"permalink":"/tags/security/","section":"Tags","summary":"","title":"Security","type":"tags"},{"content":"","date":"25 May 2026","externalUrl":null,"permalink":"/series/","section":"Series","summary":"","title":"Series","type":"series"},{"content":"","date":"25 May 2026","externalUrl":null,"permalink":"/tags/","section":"Tags","summary":"","title":"Tags","type":"tags"},{"content":" Why # There is a version of self-hosting that looks like building things. New services, migrations, architecture decisions. That version has a narrative arc and a clear sense of progress.\nThen there is the other version. The one that looks like reading a daily digest and finding something that needs attention. A security advisory for a component that routes all DNS traffic. A mail header that does not match the envelope sender. A breaking change in the next version of the identity provider. A power cut that takes the whole stack down and requires physical intervention to recover.\nThis version does not have a narrative arc. It has a maintenance schedule.\nThe weeks documented here are that version. They are what ownership actually costs.\nFamily # On a Tuesday morning in May the power went out. Everything in the house came back when the power did — except the home server, which crashed during the outage and locked itself in a kernel error loop that prevented the network from coming up.\nThe consequence was immediate and unexpected. The server is also the DNS resolver for the home network. Without it, no device in the house could look up any address. The wifi showed connected. The router was working. But nothing could reach the internet, because the system that translates names to addresses was not responding.\nThe server required a physical restart — unplugging it and plugging it back in. No remote access was possible. This is the kind of thing that sounds like a minor inconvenience until it happens at a moment when someone needs to use the internet and the person who knows what to do is not home.\nThe to-do list now includes an uninterruptible power supply and a DNS fallback configuration. Neither was considered necessary before this happened.\nTech # Four separate maintenance actions happened in the space of a week, each of which illustrates a different aspect of what ongoing operation requires.\nThe DNS service received two security updates in three days. The first addressed a vulnerability in how it forwarded queries under certain encryption configurations — a class of issue that enables cache poisoning, which can redirect traffic without the user noticing. The second was a hotfix for a caching bug. Both required finding the correct version tag, updating a configuration file, pulling the new image, and restarting the container. Neither was complex. Both were necessary.\nThe identity provider that handles authentication for all services had a new release with a breaking change: the default network address it listens on changed in a way that would have made it unreachable on an IPv4-only network after the upgrade. The fix required adding four explicit configuration lines before running the upgrade. Missing that detail in the release notes would have locked every authenticated service — password manager, photo library, file storage, wiki — until the error was diagnosed and corrected. The release notes were read carefully. The fix was applied. The upgrade completed without incident.\nThe same release introduced per-provider control over which authentication flows each application is permitted to use. Eight providers were updated to allow only the flows they actually need. One application received an exception because it uses a flow that no browser-based service would ever need — a device code flow for command-line registration. The others were restricted to the standard web authentication flow and its renewal mechanism, with everything else disabled.\nThe mail routing problem was the smallest item and the most instructive. System notifications — backup confirmations, scheduled task results, security alerts — travel through a mail relay that has been working correctly for weeks. A configuration line that was never needed before became necessary when the mail server started rejecting messages because the visible sender in the message body did not match the sender declared in the transmission envelope. One line in the configuration file corrected it. The fix took ten minutes. Finding that the problem existed required noticing, in a daily digest, that a scheduled task had stopped producing confirmation messages.\nProject # The maintenance log for this period contains no new services, no architectural changes, no migrations. It contains eight version updates, one incident response, one near-miss on a breaking change, and several small configuration corrections.\nThis is the normal state of a running system. The building phase ends. The operating phase does not.\nThe cost of ownership is not the hardware or the hosting fees, though those are real. It is the sustained attention required to notice when something has quietly changed. The DNS vulnerability was announced on a Tuesday. The AdGuard Home hotfix shipped on a Thursday. The Authentik release notes described the breaking change in a paragraph that is easy to skim past. The mail header mismatch had been silently failing for days before it surfaced in a log review.\nNone of these required deep expertise to resolve. All of them required reading carefully and acting promptly. That discipline — maintaining it week after week, for a system that mostly works and rarely demands attention — is what running infrastructure actually involves.\nThe power cut was a reminder that the infrastructure exists in a physical world where things go wrong without warning. The response revealed two gaps in the resilience design. Both are now on the list.\n","date":"25 May 2026","externalUrl":null,"permalink":"/notes/the-cost-of-ownership/","section":"Notes","summary":"Security patches, a power cut, a mail header mismatch, and a breaking change that almost wasn’t caught. The unglamorous work of keeping a system running.","title":"The cost of ownership","type":"notes"},{"content":"","date":"23 May 2026","externalUrl":null,"permalink":"/tags/data-sovereignty/","section":"Tags","summary":"","title":"Data-Sovereignty","type":"tags"},{"content":" Why # Moving data out of commercial cloud services is not a technical problem. It is a series of decisions.\nWhat do you keep? What do you discard? What belongs in a permanent archive versus a working folder? Which files are yours to decide about, and which belong to someone else who will make that decision themselves when the time comes?\nThese questions do not have technical answers. The infrastructure exists to hold whatever you decide — but the decisions themselves require sitting with a folder full of someone\u0026rsquo;s documents and being honest about what it contains.\nThis week was that work.\nFamily # The external drive that has been sitting in a drawer contains the complete digital history of everyone in this household. Eight hundred gigabytes. Photos from every phone anyone has owned since 2008. Documents going back further. Backups of backups, some of which turn out to be duplicates of other backups. Files that were clearly important once and whose purpose is now unclear.\nThe approach was to sort before importing. The principle is simple: importing disorder creates disorder. A document archive that contains everything — including irrelevant things, duplicates, and files that belong to people who haven\u0026rsquo;t been consulted — is not a useful archive. It is a more organised version of the problem it was meant to solve.\nSome of the data on the drive belongs to other family members. Their folders were not touched. They will decide what they want imported when they join the stack. That is not a technical decision to make on their behalf.\nThe photos are different. A single import of the full library — close to five hundred gigabytes for one person\u0026rsquo;s Google Photos account alone — goes into a shared family photo system where everyone will eventually have access. That migration started this week and is still running.\nTech # The photo migration (to Immich) revealed a constraint that planning had missed. The home server has a fast internal drive, but it is not large enough for half a terabyte of photos plus everything else the system already holds. The solution — moving the photo library to a larger external drive connected via USB — was straightforward, but the timing mattered: it had to happen before the second batch of imports, not after.\nThe first batch also demonstrated that the server\u0026rsquo;s memory limit is not generous enough for the combination of import processing and machine learning running simultaneously. The server froze completely during the first large run. A restart, a swap file, and adjusted resource limits for the duration of the migration were the response. The import resumed correctly — the tool checks what already exists on the server before uploading anything, so nothing was lost.\nThe document archive required a different kind of work. Not a tool problem but a classification problem. Three systems need to understand which documents belong where: a permanent archive for official records (Paperless-ngx), a working storage system for files that are still in active use (Seafile), and a knowledge base for procedures and reference material (Outline). The boundary between the first two is the most important distinction, and it is not always obvious.\nA contract that is still being negotiated belongs in the working system. The same contract, signed and filed, belongs in the permanent archive. A tax return in progress belongs in the working system. The submitted return belongs in the permanent archive. The working system changes. The archive does not.\nGetting that boundary right before importing anything required looking at several thousand files and making a judgment about each one. Six hundred duplicates were removed. Several hundred files went to a category that means: the person this belongs to should decide. Roughly a thousand documents are ready for the permanent archive. The rest will wait.\nProject # Two workstreams running in parallel produced the same observation from different directions: the hardest part of data migration is not the infrastructure. It is the judgment.\nThe infrastructure can hold whatever you give it. The photo system deduplicates on content hash — if the same image appears in three different exports, it is stored once. The document archive processes optical character recognition on everything it receives, making every file searchable regardless of format. These are solved problems.\nWhat the infrastructure cannot do is decide which files are worth keeping, which person a document belongs to, or whether a folder of work files from a job that ended five years ago needs to come with you into a system your family will rely on.\nThose decisions were made this week, one folder at a time. The work is not finished. The triage category that means \u0026ldquo;I am not sure yet\u0026rdquo; contains sixty-three items. The category that means \u0026ldquo;this belongs to someone else\u0026rdquo; is waiting for Part III, when the rest of the family comes online. The category that means \u0026ldquo;decide this yourself\u0026rdquo; has nearly seventeen hundred items that will require a different kind of attention.\nThe archive is being built to last. That is worth being careful about.\n","date":"23 May 2026","externalUrl":null,"permalink":"/notes/everything-you-ever-saved/","section":"Notes","summary":"Eight hundred gigabytes of family history. Thousands of documents. The work of deciding what belongs where — and to whom.","title":"Everything you ever saved","type":"notes"},{"content":"","date":"23 May 2026","externalUrl":null,"permalink":"/tags/immich/","section":"Tags","summary":"","title":"Immich","type":"tags"},{"content":"","date":"23 May 2026","externalUrl":null,"permalink":"/tags/migration/","section":"Tags","summary":"","title":"Migration","type":"tags"},{"content":"","date":"23 May 2026","externalUrl":null,"permalink":"/tags/outline/","section":"Tags","summary":"","title":"Outline","type":"tags"},{"content":"","date":"23 May 2026","externalUrl":null,"permalink":"/tags/paperless/","section":"Tags","summary":"","title":"Paperless","type":"tags"},{"content":"","date":"23 May 2026","externalUrl":null,"permalink":"/tags/seafile/","section":"Tags","summary":"","title":"Seafile","type":"tags"},{"content":"","date":"23 May 2026","externalUrl":null,"permalink":"/tags/storage/","section":"Tags","summary":"","title":"Storage","type":"tags"},{"content":"","date":"21 May 2026","externalUrl":null,"permalink":"/tags/documentation/","section":"Tags","summary":"","title":"Documentation","type":"tags"},{"content":"","date":"21 May 2026","externalUrl":null,"permalink":"/tags/grafana/","section":"Tags","summary":"","title":"Grafana","type":"tags"},{"content":"","date":"21 May 2026","externalUrl":null,"permalink":"/tags/homepage/","section":"Tags","summary":"","title":"Homepage","type":"tags"},{"content":"","date":"21 May 2026","externalUrl":null,"permalink":"/tags/hugo/","section":"Tags","summary":"","title":"Hugo","type":"tags"},{"content":" Why # There is a moment in any infrastructure project when the work shifts from building to inhabiting. The services are running. The backups complete overnight. The alerts fire when they should. The question stops being \u0026ldquo;will this work\u0026rdquo; and becomes \u0026ldquo;how do I live with this.\u0026rdquo;\nTwo things mark that shift more clearly than anything else: a control panel that shows you the state of everything at once, and a public voice that explains what you built and why.\nThis week produced both.\nFamily # The admin dashboard is invisible to everyone except the person who operates the stack. It is a single page — reachable only from inside the home network or through the management VPN — that shows every running service, the state of every host, and live metrics from the tools that watch over the infrastructure. Not for anyone else. For the person who needs to know, at a glance, whether everything is fine.\nThe public site is the opposite. It is for anyone who wants to understand what this project is, why it exists, and how it was built. Not a tutorial. Not a feature list. A record of decisions, their reasoning, and what they cost.\nThe family is not mentioned by name anywhere on the public site. That is a deliberate rule. The people this infrastructure is built for are described by their relationship to it — a partner, a daughter, a guest — not by who they are. Privacy-first applies to the documentation as much as to the stack itself.\nTech # The admin dashboard required solving a problem that sounds simple and is not: how do you show live data from twenty-seven services, spread across three hosts, without giving the dashboard software more access than it needs?\nThe answer involved three layers. A read-only proxy sits between the dashboard and the container runtime, allowing the dashboard to see which containers are running while blocking every write operation. Secrets — API keys, passwords — never appear in configuration files; they are injected at runtime from a separate file that stays out of version control. And cross-host metrics flow through the central monitoring system that already collects everything, rather than having the dashboard reach out to each host separately.\nSeveral widgets did not make it. The log aggregation system listens only on the local machine, not accessible from containers. The reverse proxy on the gateway server shares its network with the tunnel manager and does not expose its dashboard. These are not failures — they are correct security decisions that happen to be inconvenient. The dashboard shows what it can without compromising what it should not touch.\nThe public site had a different kind of problem: too many moving parts at the start, not enough at the end. The original plan had five separate Hugo projects, each with its own subdomain and configuration. Running them locally required five terminal windows. Navigating between them opened new browser tabs. The theme state did not persist across origins.\nThe solution was obvious in retrospect and invisible in planning: consolidate to one project, one URL, one configuration to maintain. The subdomains that disappeared became redirects. Nothing was lost. The operational overhead dropped by four-fifths.\nThe site launched with twelve notes covering the full history of Part I — written retrospectively from project logs, following a four-part structure that forces every technical note to include why the decision mattered, what it meant for the people who use the system, and what pattern it established. The structure is a constraint. Constraints are useful.\nProject # The admin dashboard and the public site are different tools built for different audiences. But they share an underlying intent: making the stack legible.\nThe dashboard makes it legible to the operator — one place to see whether the system is healthy, whether anything needs attention, whether the tools that watch the infrastructure are themselves being watched.\nThe public site makes it legible to anyone else — a record of what was built, the reasoning behind it, and the honest account of where the plan changed when it met reality. The architecture document that required three complete rewrites before the implementation started. The subdomains that seemed essential on paper and were obviously redundant in practice.\nA system that cannot be explained is a system that cannot be handed over. Both of these tools are, in the end, about the same thing: making sure that the infrastructure exists for the people it serves, not just for the person who built it.\n","date":"21 May 2026","externalUrl":null,"permalink":"/notes/moving-in/","section":"Notes","summary":"Building a control panel for a system you operate. Building a public voice for a project you believe in. Both are the same gesture.","title":"Moving in","type":"notes"},{"content":"","date":"21 May 2026","externalUrl":null,"permalink":"/tags/observability/","section":"Tags","summary":"","title":"Observability","type":"tags"},{"content":"","date":"21 May 2026","externalUrl":null,"permalink":"/tags/umami/","section":"Tags","summary":"","title":"Umami","type":"tags"},{"content":"","date":"17 May 2026","externalUrl":null,"permalink":"/tags/headscale/","section":"Tags","summary":"","title":"Headscale","type":"tags"},{"content":"","date":"17 May 2026","externalUrl":null,"permalink":"/tags/oauth2/","section":"Tags","summary":"","title":"Oauth2","type":"tags"},{"content":"","date":"17 May 2026","externalUrl":null,"permalink":"/tags/oidc/","section":"Tags","summary":"","title":"Oidc","type":"tags"},{"content":"","date":"17 May 2026","externalUrl":null,"permalink":"/tags/pangolin/","section":"Tags","summary":"","title":"Pangolin","type":"tags"},{"content":" Why # There is a category of error that is more dangerous than a broken system: a system that appears to be working correctly while doing something fundamentally different from what was intended.\nA security control that blocks the wrong traffic. An authentication layer that never fires. A middleware that every request bypasses without leaving a trace.\nThese errors are not visible in monitoring. They do not produce alerts. They show up only when you read the source carefully enough to understand what the software actually does — not what you assumed it did when you configured it.\nThis week produced two of them, discovered on the same day.\nFamily # The services the family uses — password manager, photos, files, wiki — were not affected. They continued working throughout. The problem was in the administrative layer: the control panel for managing the gateway that routes all external traffic.\nThat control panel had been inaccessible for days. Every attempt to open it returned an error without explanation. The investigation into why took most of a day and rewrote two decisions in the process.\nTech # The first discovery came from reading log files carefully. The gateway\u0026rsquo;s reverse proxy was logging the source address of every incoming request. That address was always the same: the internal IP address of the tunnel software itself, not the actual client making the request. The IP restriction that was supposed to limit access to the administrative dashboard to the management VPN had never worked. Every request from the public internet carried the same internal address. The filter had no effect. The gateway had been publicly reachable for weeks while appearing to be restricted.\nThe second discovery came from source validation. The original plan for fixing the authentication problem involved replacing the existing middleware with a different component — one that would connect the gateway\u0026rsquo;s authentication to the central identity system running on the home server. A decision record was written, reviewed, and approved. Then the documentation for the gateway software was read more carefully.\nThe middleware in question is not a replaceable component. It is integral to how the gateway software manages sessions. Replacing it would not fix the authentication flow — it would break session management entirely. The proposed architecture was based on a misunderstanding of how the software works.\nThe decision record was rewritten the same day it was written. The new version took a different approach: use the gateway software\u0026rsquo;s built-in identity provider integration, which connects to the central identity system through the documented interface rather than around it. That approach worked. The administrative dashboard became accessible. Authentication through the central identity system succeeded end-to-end.\nThe fix for the IP restriction problem was different. The root cause — the tunnel software passing its own internal address instead of the client\u0026rsquo;s — cannot be solved at the filter level. It requires a different configuration at the tunnel layer itself. That fix was documented and deferred; the non-functional filter was removed rather than left in place creating a false sense of security.\nOne additional problem emerged during the investigation. The containers on the gateway server needed to resolve the hostname of the central identity system to connect to it correctly. The workaround — editing a configuration file on the host — did not persist inside the containers and reset on every restart. The correct solution was to embed the hostname resolution directly in the container configuration, where it is version-controlled and survives any restart.\nProject # Three separate problems were resolved in a single day, each discovered while investigating the previous one. A non-functional security filter. An authentication architecture built on a misreading of the documentation. A DNS workaround that worked on the host but not inside the containers that actually needed it.\nThe day\u0026rsquo;s work produced four commits and a rewritten decision record.\nThe rewrite is worth noting. Writing a decision record, discovering it is wrong before implementation, and rewriting it on the same day is not a failure of the planning process. It is the planning process working correctly. The record existed to be scrutinised. The scrutiny found the error. The implementation that followed the corrected record worked on the first attempt.\nThe alternative — implementing first, discovering the error in production, and debugging a broken authentication system while the family tries to use their services — would have been significantly worse.\nThe security filter that never worked raises a different question. The system appeared secure. The monitoring showed nothing unusual. There was no alert, no log entry, no signal of any kind that the filter was not doing what it was configured to do. The discovery came from reading the proxy logs with enough attention to notice that the source address was always the same.\nThat kind of attention is not automatic. It requires time set aside specifically to look at things that appear to be working.\n","date":"17 May 2026","externalUrl":null,"permalink":"/notes/the-assumption-that-broke-the-architecture/","section":"Notes","summary":"A security layer that had never worked. A decision record rewritten the same day it was written. And the discipline that made both discoveries possible.","title":"The assumption that broke the architecture","type":"notes"},{"content":"","date":"17 May 2026","externalUrl":null,"permalink":"/tags/traefik/","section":"Tags","summary":"","title":"Traefik","type":"tags"},{"content":"","date":"16 May 2026","externalUrl":null,"permalink":"/tags/alloy/","section":"Tags","summary":"","title":"Alloy","type":"tags"},{"content":"","date":"16 May 2026","externalUrl":null,"permalink":"/tags/caddy/","section":"Tags","summary":"","title":"Caddy","type":"tags"},{"content":"","date":"16 May 2026","externalUrl":null,"permalink":"/tags/cadvisor/","section":"Tags","summary":"","title":"Cadvisor","type":"tags"},{"content":"","date":"16 May 2026","externalUrl":null,"permalink":"/tags/cloudflare/","section":"Tags","summary":"","title":"Cloudflare","type":"tags"},{"content":"","date":"16 May 2026","externalUrl":null,"permalink":"/tags/crowdsec/","section":"Tags","summary":"","title":"Crowdsec","type":"tags"},{"content":" Why # There is a difference between infrastructure you control and infrastructure you depend on. For most of the time HomeStack has been running, that line ran through a single service: the commercial tunnel (Cloudflare) that routed all external traffic through someone else\u0026rsquo;s network before it reached the server at home.\nIt was convenient. It absorbed attacks, handled certificates, and required almost no configuration. It was also a dependency — on a company\u0026rsquo;s continued existence, continued pricing, continued policy decisions. Every service in the stack was reachable from the outside only because a third party allowed it to be.\nRemoving that dependency turned out not to be a single decision. It was seven.\nFamily # Nothing about this week was visible from the outside. All six services stayed reachable. Passwords, photos, files, notes — all accessible the same way they had always been, from anywhere.\nWhat changed was where the traffic went and who controlled the path. Before this week, a request to open the photo library traveled through servers in the United States before reaching the Raspberry Pi in the study. After this week, it goes directly to a small server in Frankfurt — one I rent, configure, and back up myself — and from there through an encrypted tunnel to the Pi.\nThe difference is not visible. That is the point. Sovereignty should not require accepting a worse experience.\nTech # The first step was standing up a new server. Before any migration could happen, that server needed to be hardened from scratch: access locked to SSH keys and a second factor, a firewall that blocks everything except what is explicitly needed, intrusion detection active from the first minute. The lesson from running the Pi is that a server on the public internet attracts automated scanners within seconds of becoming reachable. Eight failed login attempts arrived before the first service was deployed.\nThe tunnel software (Pangolin) itself took three sessions to get right. The core problem was a chain of proxies: external traffic arrives at the new server, gets forwarded through an encrypted tunnel to the Pi, hits a reverse proxy that routes it to the right service. Each proxy in that chain needs to speak the same protocol as the one before it. Getting that handshake right — particularly the part where the inner proxy needs the hostname to route correctly, not just the IP address — was not documented anywhere in a way that matched the actual behavior of the software.\nThe debugging pattern that finally worked was the same one that works for most network problems: start at one end, verify what arrives at each step, find where the chain breaks. In this case the break was a single missing field — the server name indication that tells the receiving proxy which site the request is for. Once that was in place, all six services came up within minutes.\nThe management layer followed a different path. The VPN that allows administering the stack from outside the home network had been running on a commercial coordination service (Tailscale). Replacing it with a self-hosted equivalent (Headscale) meant migrating four devices one at a time — laptop first, phones, then the Pi, then the server itself last — keeping the commercial fallback active until every device was confirmed working on the new system. The order mattered: the server hosts its own coordination service, so migrating it last meant there was always a working fallback if something went wrong.\nThe DNS migration came third. Moving the domain away from the last external provider exposed a behavior that was not documented: the new provider does not activate DNS records until its own nameservers are set as authoritative for the domain. Records in the dashboard, records not visible on the nameservers — an hour of debugging that ended with a single configuration change and everything resolving correctly within minutes.\nThe certificate infrastructure changed alongside the DNS. The old setup used a wildcard certificate that required API access to the DNS provider to prove domain ownership. The new setup uses a different proof method that requires no external API at all — each subdomain gets its own certificate, renewed automatically by the server responding to a challenge on port 443. Simpler, fewer dependencies, and the certificates renewed themselves correctly within thirty seconds of the configuration change.\nProject # WS1 started as a workstream with four steps. By the time it closed, it had seven. Each step revealed the next dependency. The original plan did not account for the certificate infrastructure being coupled to the DNS provider, or for the DNS provider having an activation mechanism that differed from every other DNS service used before.\nThat is not a planning failure. A dependency you cannot see until you are close enough to touch it is not a dependency you could have planned around. The correct response is to document it when you find it — so the next migration, on the next system, does not repeat the same hour of debugging.\nCloudflare is no longer in the path. No DNS, no tunnel, no certificate infrastructure, no API token anywhere in the configuration. The last reference was removed from a configuration file that turned out to have been dead code for months — the setting was there, the plugin was built in, and none of it had ever been used.\nThat is a clean exit.\n","date":"16 May 2026","externalUrl":null,"permalink":"/notes/cutting-the-last-wire/","section":"Notes","summary":"Replacing a commercial tunnel service sounds like a single decision. It turns out to be a chain of seven.","title":"Cutting the last wire","type":"notes"},{"content":"","date":"16 May 2026","externalUrl":null,"permalink":"/tags/dns/","section":"Tags","summary":"","title":"Dns","type":"tags"},{"content":"","date":"16 May 2026","externalUrl":null,"permalink":"/tags/letsencrypt/","section":"Tags","summary":"","title":"Letsencrypt","type":"tags"},{"content":"","date":"16 May 2026","externalUrl":null,"permalink":"/tags/loki/","section":"Tags","summary":"","title":"Loki","type":"tags"},{"content":" Why # There is a category of problem that is worse than something being broken: something appearing to work while silently failing. No error. No alert. No log entry that says \u0026ldquo;this is wrong.\u0026rdquo; Just a system that looks healthy while doing the wrong thing — or nothing at all.\nThis week was about finding those problems. Not because something had crashed. Because I decided to look carefully at things I had assumed were working.\nWhat I found changed how I think about operating a self-hosted stack.\nFamily # From the outside, nothing changed this week. All services stayed online. No one noticed anything because nothing was visibly broken.\nThat is exactly the point.\nThe work of running a private infrastructure is mostly invisible. Not building new things — maintaining what exists. Verifying that the systems watching over your data are actually watching. That the backups running every night are running the right version. That the security tools blocking attackers are blocking the right addresses.\nThis kind of work has no visible result. It is the difference between a house that looks fine and a house that is fine.\nTech # Four separate systems turned out to be silently wrong.\nThe security scanner was watching the wrong addresses. The tool responsible for detecting and blocking malicious traffic had been analysing proxy addresses instead of real client IPs — for weeks. Every ban it issued hit the wrong target. A one-line configuration fix was all it took, but finding the problem required reading logs at three different layers simultaneously: what the web server logged, what the security tool parsed, and what it actually acted on.\nThe log pipeline was dropping everything without complaint. A filter in the log collector was written against a field that does not exist as a routing label in the log storage system. The result: every log entry was silently discarded. The pipeline showed no errors. The counters incremented. Nothing arrived. The fix was to remove the filter entirely and move filtering to the query layer where it belongs — but finding the root cause required stepping through each stage of the pipeline individually and measuring what entered and what left.\nThe backup tool was running an outdated version. The package manager had stopped tracking upstream releases. The installed version was a year and a half behind. The backups themselves were completing successfully, but improvements to database hook handling — directly relevant to how this stack dumps PostgreSQL and MariaDB — had accumulated in the meantime. Migration to a different installation method brought everything current. The first backup run after migration completed cleanly.\nThe container scanner had never sent a notification. A weekly security scan was running and writing results to a log file. The script was correctly placed, the scan was completing — but there was no alert on completion. The results existed only for someone who thought to look. Adding a push notification surfaced the first real scan result: over a hundred critical and high vulnerabilities across the running containers, most of them upstream dependencies waiting on fixes that do not yet exist.\nEach of these had something in common. None produced an error. None triggered an alert. None were visible without deliberate investigation. The monitoring stack reported everything healthy because the monitoring stack was itself part of what needed monitoring.\nProject # The work this week covered ground across several areas simultaneously: security tooling, observability pipelines, backup operations, and container hygiene. None of it was planned. It emerged from reading the daily digest carefully and following what it implied.\nOne structural pattern became clear: silence is not the same as correctness. A system that produces no errors is not necessarily a system that is working. Verification requires more than checking that a process is running — it requires checking that the process is producing the right output at every stage.\nThe practical change this week was adding notification to anything that runs unattended. Scans now push results on completion. Alerts now cover two thresholds instead of one for storage that grows continuously. The log pipeline now routes correctly, which means the alert templates that depend on it can finally be built.\nThe work that cannot be finished yet — vulnerabilities in containers that depend on upstream fixes — is at least now visible. Visible problems can be tracked. Silent ones cannot.\n","date":"16 May 2026","externalUrl":null,"permalink":"/notes/running-is-not-the-same-as-working/","section":"Notes","summary":"A week of discovering what was silently broken — and making failure visible.","title":"Running is not the same as working","type":"notes"},{"content":"","date":"16 May 2026","externalUrl":null,"permalink":"/tags/sovereignty/","section":"Tags","summary":"","title":"Sovereignty","type":"tags"},{"content":"","date":"16 May 2026","externalUrl":null,"permalink":"/tags/tailscale/","section":"Tags","summary":"","title":"Tailscale","type":"tags"},{"content":"","date":"16 May 2026","externalUrl":null,"permalink":"/tags/trivy/","section":"Tags","summary":"","title":"Trivy","type":"tags"},{"content":"","date":"16 May 2026","externalUrl":null,"permalink":"/tags/wireguard/","section":"Tags","summary":"","title":"Wireguard","type":"tags"},{"content":"","date":"15 May 2026","externalUrl":null,"permalink":"/tags/google-photos/","section":"Tags","summary":"","title":"Google-Photos","type":"tags"},{"content":" Why # The hardest part of leaving a cloud service is not the technical migration. It is the audit.\nBefore you can move your data, you need to know where it is. All of it. Photos spread across multiple accounts, on phones that have changed over the years, in folders on drives that were last opened years ago. Some of it duplicated, some of it unique, some of it unidentified until you look at it directly.\nThe audit is also where you discover what you would lose if something went wrong.\nThat is the question that shapes everything that follows: how do you move nearly half a terabyte of irreplaceable family photographs without accepting any meaningful risk of loss? The answer is: you do not start the migration until a complete, independent copy exists somewhere outside every service you are about to leave.\nFamily # The inventory covered four sources across three family members: years of photos and videos from Google accounts, from OneDrive, from old backups on an external drive that had been sitting in a drawer. When the numbers came together, the total was larger than expected — closer to eight hundred gigabytes of data on a single external drive, of which roughly half a terabyte was photos and videos that need a permanent home.\nThe Microsoft Family subscription got cancelled during this process. That was the right moment — the data was already safe, the decision was clean. Two accounts dropped to free storage tiers immediately. That adds a quiet deadline to the photo migration: new photos above the free tier limit will need a separate export before Part III, when the rest of the family joins the stack.\nNothing about any of this is visible to anyone else yet. The photos are still in Google Photos, still in OneDrive, still accessible the same way they have always been. The migration has not started. What this week produced is the precondition for migration: a verified, independent copy of everything, stored outside all commercial services, before a single original is touched.\nTech # The approach for this kind of data is to secure first, migrate second. An external drive with all the data went to off-site storage — not as the migration target, but as the safety copy. Only after that copy was verified did the planning for the actual migration begin.\nThe transfer itself taught one useful lesson: any rsync of hundreds of gigabytes will eventually be interrupted. A laptop crash mid-transfer is not a disaster if you resume with the right flags — the tool can verify what arrived and continue from where it stopped without retransmitting what is already there. Running large transfers in a persistent terminal session, detached from the local shell, is the correct habit.\nThe migration planning surfaced a less obvious question: which machine should run the import? The answer was not the one that seemed most convenient. The laptop handling the external drive is near end of life — loading it with a multi-day import process is the wrong choice. The better answer was to move the drive physically to the server and run the import locally. No network bottleneck, no dependency on a machine that might not finish the job.\nThe import itself is not started. The tooling has been researched, the deduplication approach is defined, the metadata handling for photos that lack embedded dates is understood. The waiting condition is stability: the migration starts after the network layer and the operational foundations are settled, not before.\nProject # This workstream has a built-in patience requirement that the others do not.\nThe photo migration cannot be rushed. There is a verification period after import before any source is deleted — weeks of actual use, not a checkbox. The decision to delete Google Photos or clear OneDrive will be a deliberate act, not a side effect of the migration completing. That decision requires confidence that nothing was lost, that the duplicates were handled correctly, that the metadata is intact.\nThe irreversibility is the point. Getting this right matters more than getting it done quickly.\n","date":"15 May 2026","externalUrl":null,"permalink":"/notes/half-a-terabyte-of-family-history/","section":"Notes","summary":"Before you can migrate your photos, you need to know where they all are. That turns out to be the harder problem.","title":"Half a terabyte of family history","type":"notes"},{"content":"","date":"15 May 2026","externalUrl":null,"permalink":"/tags/onedrive/","section":"Tags","summary":"","title":"Onedrive","type":"tags"},{"content":"","date":"15 May 2026","externalUrl":null,"permalink":"/tags/rsync/","section":"Tags","summary":"","title":"Rsync","type":"tags"},{"content":"","date":"12 May 2026","externalUrl":null,"permalink":"/tags/homestack/","section":"Tags","summary":"","title":"Homestack","type":"tags"},{"content":" Why # Part I ended with a working stack. Six services running behind a reverse proxy, backups going off-site every night, monitoring in place, family data safe.\nThat was the easy part.\nPart I had a clear definition of done: is the service running, is it secure, does it back up. Part II does not have that luxury. The question it asks is harder: does this actually work for the people who are supposed to use it? Does it replace what it was meant to replace? Can you trust it enough to delete the originals?\nThese are not technical questions. They are questions about use, about habit, about whether the infrastructure you built has earned its place in daily life.\nPart II is where a homelab either becomes a home — or stays a project.\nFamily # Part I was invisible to everyone else. Services went up, data moved, things got more secure. Nothing changed from the outside.\nPart II is where that changes. Photos — nearly half a terabyte of them, from phones and laptops and old drives going back years — need to move out of Google and into a system we control. Documents need a permanent home. Financial data needs a place to live that is not a spreadsheet.\nNone of this happens automatically. And none of it happens until the system has proven it can be trusted — not just technically, but practically. The photo migration will not start until the tools have been tested. The originals will not be deleted until the replacement has been used for weeks. Every step has a deliberate waiting period built in.\nThe family is not part of this phase yet. That is intentional. Part II is about making the stack work for one person before asking others to depend on it.\nTech # Part II started on the 11th of May with a roadmap of four workstreams. By the 16th it had nine.\nThat is not a failure of planning. It is what happens when you move from building to operating. The first week surfaced things that were invisible while construction was the focus: a security tool watching the wrong addresses, a log pipeline silently discarding everything, a container tunnel tool that had never had its identity provider properly connected. Each one was individually small. Together they formed a clear picture of the gap between a stack that runs and a stack that is ready.\nThe nine workstreams that emerged cover the ground that actually needs covering:\nReplacing the last external dependency in the network layer — the commercial tunnel service that routes all external traffic — with infrastructure running on a server in Europe under direct control. This is the piece that closes the gap between \u0026ldquo;mostly sovereign\u0026rdquo; and \u0026ldquo;actually sovereign.\u0026rdquo;\nMoving photos, documents, and files from commercial cloud storage to self-hosted alternatives. Not as a statement, but because the alternatives are now good enough and the commercial services charge more every year for data that is fundamentally yours.\nBuilding the financial layer — dashboards over real bank data, not estimates. The kind of overview that used to require expensive software or a financial advisor.\nGetting the operational foundation right: monitoring that actually alerts, backups that are actually tested, security scanning that actually reports. The work that is invisible when it works and catastrophic when it does not.\nAnd a public surface — notes, reflections, documentation — because building something this carefully and keeping it entirely private would be a waste.\nThe roadmap restructured itself three times in the first week. That is the correct behavior for a plan that is being tested against reality.\nProject # Part II has one exit criterion that matters more than the others: trust.\nNot technical correctness. Not feature completeness. The specific condition is this: does the person running this stack trust it enough to explain it to someone else?\nThat is a higher bar than it sounds. It requires that the monitoring is honest, that the backups have been verified, that the operational procedures exist in writing and not just in memory. It requires that nothing important is silently failing.\nPart I proved the stack could be built. Part II proves it can be lived in.\n","date":"12 May 2026","externalUrl":null,"permalink":"/notes/part-ii-making-it-yours/","section":"Notes","summary":"Part I ended with a working stack. Part II begins with a harder question: what does it mean to actually use it?","title":"Part II: Making it yours","type":"notes"},{"content":"","date":"11 May 2026","externalUrl":null,"permalink":"/categories/","section":"Categories","summary":"","title":"Categories","type":"categories"},{"content":"","date":"11 May 2026","externalUrl":null,"permalink":"/tags/foundations/","section":"Tags","summary":"","title":"Foundations","type":"tags"},{"content":"","date":"11 May 2026","externalUrl":null,"permalink":"/series/homestack-part-i/","section":"Series","summary":"","title":"HomeStack Part I","type":"series"},{"content":" Why # I started HomeStack because I was tired of the deal.\nThe deal that says: give us your photos, your documents, your family\u0026rsquo;s memories, and we\u0026rsquo;ll keep them safe. Trust us. We\u0026rsquo;ll change the terms when we feel like it, charge more when the market allows, and shut down the product when it stops being profitable. You don\u0026rsquo;t own any of this. You\u0026rsquo;re renting access to your own life.\nI wanted out. Not for ideological reasons — or not only for those reasons. I wanted to understand how it all worked. I wanted to build something real. And I wanted my family\u0026rsquo;s data to live somewhere I controlled, on hardware I owned, in a house we live in.\nThat impulse became nine phases and roughly a month of nightly and weekend tinkering.\nFamily # My partner has been patient in a way I don\u0026rsquo;t take for granted.\nFor weeks, evenings disappeared into terminal windows. Conversations were interrupted by the need to check a log or test a configuration. The system I was building was supposed to make things better for the family — and in the meantime, it was temporarily making things slightly worse for the persons I share my life with.\nShe tested the photo interface when I asked her to. She told me honestly when something was confusing. She didn\u0026rsquo;t pretend to be more interested in the technical details than she was, which was the right call. Her feedback shaped real decisions.\nThe infrastructure is for the family. That means it has to work for people who aren\u0026rsquo;t me. That constraint — complexity belongs to the builder, never to the user — turned out to be one of the most useful design principles I had.\nTech # Nine phases doesn\u0026rsquo;t capture it cleanly. The phases bled into each other. A decision made in phase two shaped what was possible in phase seven. A gap discovered in phase nine traced back to an assumption from phase one.\nBut the arc is clear enough in retrospect.\nThe first phases were about foundations: a server, a container runtime, a reverse proxy, a database, an identity layer. These are the pieces everything else depends on. Getting them right — really right, not just working — took longer than I expected. The difference between \u0026ldquo;installed\u0026rdquo; and \u0026ldquo;understood\u0026rdquo; is where most of the time went.\nThe middle phases were about services: file storage, a wiki, financial tracking, photo management. Each one taught something the previous ones hadn\u0026rsquo;t. Every new service is also a new authentication integration, a new backup scope, a new monitoring concern, a new thing that can break at 2am.\nThe final phases were about proving it. Security audit. Log aggregation. Alert rules. A bare-metal restore test on clean hardware, timed. Twenty-four minutes from first action to both critical services responding. That number matters more than any feature.\nBy the end, the stack had twenty-eight containers, three bridge networks, a custom certificate pipeline, central log aggregation, fourteen security alert rules, daily encrypted backups to off-site storage, and a measured recovery time.\nMore importantly: I understood most of it. Not just how it was configured, but why. That\u0026rsquo;s the part that took the most work and will last the longest.\nProject # A few things I learned that had nothing to do with technology.\nDocumentation is a forcing function. Writing down why you made a decision forces you to actually have a reason. Twice during the build, writing a decision record made me realize the decision I was about to document was wrong. The writing caught what the doing missed.\nThe gap between \u0026ldquo;works\u0026rdquo; and \u0026ldquo;proven to work\u0026rdquo; is where trust lives. A backup you\u0026rsquo;ve never restored is a hypothesis. A recovery time you\u0026rsquo;ve never measured is a guess. The phase I called Production Readiness was really the phase where I stopped hypothesizing and started proving.\nThe things that nearly went wrong were never the ones I worried about. An exposed database port I hadn\u0026rsquo;t noticed. A configuration variable whose name meant the opposite of what I thought. An alert structure that looked correct in every UI view but would never fire. Auditing finds the gap between what you think you built and what you actually built.\nComplexity has to live somewhere. If the system is simple for the people using it, the complexity didn\u0026rsquo;t disappear — it moved. It lives in the configuration, the documentation, the monitoring, the procedures. That\u0026rsquo;s the right place for it. Putting it there is the actual work.\nPart I is done. The infrastructure exists, runs, and is proven to be recoverable. The stack is in production.\nPart II is data migration, daily use, making it real. Part III is handing it to the family and stepping back. Onwards to new builds, Smart Home or private AI/LMM anyone?\nThis was just the beginning.\n","date":"11 May 2026","externalUrl":null,"permalink":"/notes/just-the-beginning/","section":"Notes","summary":"Nine phases. One month. What it actually means to build infrastructure for your family.","title":"Just the Beginning","type":"notes"},{"content":"","date":"11 May 2026","externalUrl":null,"permalink":"/categories/note/","section":"Categories","summary":"","title":"Note","type":"categories"},{"content":"","date":"11 May 2026","externalUrl":null,"permalink":"/tags/skills/","section":"Tags","summary":"","title":"Skills","type":"tags"},{"content":"","date":"10 May 2026","externalUrl":null,"permalink":"/tags/borgbackup/","section":"Tags","summary":"","title":"Borgbackup","type":"tags"},{"content":" Why # At some point you have to stop building and start proving.\nFor over a month, HomeStack had been a construction site. Every phase added something new — a database, a service, a monitoring layer. Each piece worked in isolation. The stack felt solid. But \u0026ldquo;feels solid\u0026rdquo; is not the same as \u0026ldquo;is solid,\u0026rdquo; and I knew the difference mattered before I handed this infrastructure to my family.\nProduction Readiness was the phase where I stopped adding and started auditing. The question changed from \u0026ldquo;does it work?\u0026rdquo; to \u0026ldquo;can I prove it works, and prove it stays working?\u0026rdquo;\nFamily # My partner and daughter don\u0026rsquo;t think about infrastructure. They think about whether their photos are there, whether they can log in, whether things just work. That\u0026rsquo;s the right way to think about it — and it\u0026rsquo;s exactly why I needed to be certain before they started depending on it.\nThe goal of this phase wasn\u0026rsquo;t features. It was trust. Not my trust in the system, but the kind of trust that holds when I\u0026rsquo;m not around to fix things.\nTech # I started with a security audit. Internal port scan, external scan from a separate VPS, HTTP vulnerability scan against all seven public-facing services.\nThe internal scan found PostgreSQL exposed on a host port — reachable from anywhere on the local network. Not intentional. Not acceptable. Removed immediately, all dependent services restarted healthy. The external scan showed only Cloudflare infrastructure. The Pi was invisible, exactly as designed.\nThe HTTP scanner against the public services returned two findings per service. Both were false positives introduced by the Cloudflare proxy layer. No real vulnerabilities.\nOne scan, one real finding, one immediate fix. That\u0026rsquo;s what audits are for.\nBefore this phase, 28 containers were running with no central log visibility. Individual container logs existed but were unqueryable as a whole. If something suspicious happened across multiple services simultaneously, I would have had no way to see it.\nLoki and Alloy closed that gap. Alloy collects logs from every Docker container and from the host journal. Loki stores and indexes them. Grafana queries them. Total RAM overhead: around 260MB for both services together.\nThen came the alert rules — fourteen security alerts covering every service. Failed login attempts, brute force patterns, HTTP error spikes. Each alert required careful query design: Grafana\u0026rsquo;s Loki alerts need an explicit reduce step between the time-range query and the threshold evaluation. Without it, the alert structure looks correct but silently never fires. I found several existing alerts in exactly that broken state. Fixed all of them.\nThe lesson: you can\u0026rsquo;t defend what you can\u0026rsquo;t see. And alerts that look configured but never fire are worse than no alerts — they give false confidence.\nTwo small incidents stand out.\nThe first: a configuration variable with a misleading name. I was trying to disable an admin panel. The variable name suggested \u0026ldquo;disable the token requirement.\u0026rdquo; What it actually meant was \u0026ldquo;open the panel without requiring any token at all.\u0026rdquo; The panel was briefly wide open. Closed immediately, but the lesson stayed: variable names lie. Always verify behavior, not just configuration.\nThe second: a service was showing an old authentication URL in its UI even though the configuration file had the correct new value. The configuration file wasn\u0026rsquo;t the source of truth — the database was. The service had stored the original value at first setup and never re-read the file for that field. Three layers to check: environment file, database, UI. Always all three.\nI had tested backups before. Partial restores, file-level verification. But I had never done a full bare-metal restore on completely clean hardware.\nI provisioned a fresh ARM64 cloud server. No pre-existing configuration. Installed the backup tooling, connected to the off-site repository, extracted the latest archive, restored the databases, started the services.\nFrom first action to both critical services responding: twenty-four minutes. That number is now documented. It\u0026rsquo;s not an estimate or a hope — it\u0026rsquo;s a measured recovery time on real hardware. The server stayed running as a permanent development and disaster recovery node.\nThe final piece was hardening everything that had been deferred. Password rotation across all services and databases. SSH access restricted to the management VPN only — local network SSH no longer works, which is exactly the point. Single sign-on validated end-to-end for every service. Session tokens short-lived. Admin interfaces closed or protected by an additional authentication layer.\nOne service update came mid-phase when I found critical security fixes in the release notes: authentication bypass and server-side request forgery. Updated immediately rather than waiting for the scheduled maintenance window. Some things don\u0026rsquo;t wait.\nProject # Production Readiness is the phase that separates infrastructure from a system you can actually trust.\nThe pattern I keep returning to: the things that nearly went wrong were never the things I was worried about. The exposed database port wasn\u0026rsquo;t on my risk list. The misleading variable name wasn\u0026rsquo;t in the documentation. The broken alert structure looked correct in every dashboard view.\nAuditing finds the gap between what you think you built and what you actually built. That gap is always smaller than you fear and always surprising in its specifics.\nOn the evening of May 10th, I renamed the server from its development hostname to its production name. A one-line command. Nine phases of work behind it.\nThe switch was flipped.\n","date":"10 May 2026","externalUrl":null,"permalink":"/notes/flipping-the-switch/","section":"Notes","summary":"Nine phases of building. One evening of proving it actually works.","title":"Flipping the Switch","type":"notes"},{"content":"","date":"10 May 2026","externalUrl":null,"permalink":"/projects/","section":"Projects","summary":"","title":"Projects","type":"projects"},{"content":"","date":"4 May 2026","externalUrl":null,"permalink":"/tags/gotify/","section":"Tags","summary":"","title":"Gotify","type":"tags"},{"content":"","date":"4 May 2026","externalUrl":null,"permalink":"/tags/hetzner/","section":"Tags","summary":"","title":"Hetzner","type":"tags"},{"content":" Why # There is a moment in every infrastructure project where the technical work is essentially done and a different kind of work begins. The services are running. The backups are configured. The monitoring is in place. But the system is still yours — accessible to you, understandable by you, designed around your assumptions about what is normal.\nMaking it ready for a family is something else. It requires that the URLs make sense without explanation. That authentication works for people who did not configure it. That when something breaks, there is a procedure for fixing it that does not depend on your being available. That the network distributes the right DNS server to every device without anyone having to think about it.\nPhase 8 was that transition. Two tracks running in parallel over four days: one focused on access and DNS, one focused on making the stack itself robust enough to trust with real data and real users.\nFamily # The URL migration was invisible to the family. All the services that had been running on development subdomains — photos, files, status, monitoring — were moved to their permanent addresses without downtime. From the family\u0026rsquo;s perspective, nothing changed. From the infrastructure\u0026rsquo;s perspective, six layers of configuration were updated in a single coordinated session: the reverse proxy, the tunnel, the authentication redirect URIs, the service-internal configurations, the DNS entries, and the local hosts file.\nThe DNS gap is the one thing that was not fully resolved. The Pi running AdGuard Home as a local DNS resolver means that internal services resolve correctly for devices that use the Pi as their DNS server. Getting every family device to use the Pi as DNS requires the router to distribute it. The current router does not allow that configuration.\nThe structural fix is a new router, arriving in July. Until then, the devices belonging to the family members who will use the services daily have a manual DNS entry pointing at the Pi. It is an inelegant solution. It works. The permanent solution is documented and scheduled.\nMFA was completed correctly this time. In an earlier phase, the policy was accidentally attached to the authentication flow itself rather than to a specific stage within the flow, which locked out all users including administrators. The recovery required a one-minute command-line token. This time the policy was attached at the stage level. The distinction is subtle in the interface and consequential in practice.\nTech # The Lab for the financial tool evaluation was cleaned up after every session — containers, volumes, networks, all removed. This is a discipline that sounds minor and is not. A Lab that accumulates state becomes a source of confusion. The principle is simple: the Lab is disposable. Treat it that way.\nCrowdSec had been silently broken for weeks. The intrusion detection system was running, logging looked normal, but Ubuntu 24.04 had changed the timestamp format in its system logs to ISO 8601. CrowdSec\u0026rsquo;s parser expected the older syslog format. Every SSH login, every blocked request, every authentication attempt — none of it was being parsed. The fix was switching to the journald acquisition source, which delivers structured logs without timestamp ambiguity. The lesson is that a security tool that appears to be working is not the same as one that is working.\nAlerting was added via a self-hosted push notification server. Five alert rules in the monitoring system: disk space above 80%, CPU sustained above 75%, temperature above 75 degrees, container restart detected, and certificate expiry within 30 days. Each one fires a push notification to a phone. The first time the disk space alert fired during a test, it felt like the system was alive in a different way than before — not just running, but watching.\nResource limits were added to all 28 containers based on measured usage rather than guesswork. One container using all available memory on a Raspberry Pi 5 can take down everything else. The limits are conservative relative to typical usage. The measurement step revealed an autovacuum spike in one database that looked like a runaway process and was not — two minutes of patience and a second measurement resolved what would otherwise have been an unnecessary intervention.\nDistroless container images caused a specific problem. Several services use images with no shell, no curl, no wget — a deliberate security choice by the image maintainers. Writing a health check for a container that has no tools requires either using the application\u0026rsquo;s own health endpoint directly or accepting that the container has no health check. The right answer depends on the image. The wrong answer is assuming all containers work the same way.\nThe off-site backup finally closed. Proton Drive had been the planned target since the beginning of the project. It was blocked throughout Phase 7 by an authentication CAPTCHA that never resolved. In Phase 8 it became clear this was structural — the underlying library had been officially deprecated and the API was being shut down. Hetzner Storage Box replaced it: a dedicated backup storage unit in Germany, connected directly via the backup tool\u0026rsquo;s native SSH support. No API, no rate limiting, no deprecation risk. The 3-2-1 backup strategy was finally complete.\nProject # Three Decision Records written in four days, covering network infrastructure choices that will govern the system for the next three to five years. The router replacement in July. The ARM64 cloud node for development and disaster recovery. The separate lightweight node for the tunnel gateway. Each decision documented with the alternatives considered, the reasoning, and the trade-offs accepted.\nOne checkbox that did not match reality. A task for configuring the router had been marked complete in the project tracking. It had never been executed — the router configuration turned out to be impossible on the current hardware, and the task had been closed without a note explaining why. The fix was trivial. The pattern it represents is not: documentation that reflects what was planned rather than what happened is documentation that cannot be trusted.\nThe performance baseline is the output of Phase 8 that will matter most later. 38% of available memory in active use. 11% of primary storage consumed. Machine learning processing for 100 photos taking seven minutes on ARM64 CPU inference. These numbers are the reference point for everything that comes next — the data migration, the family adoption, the long-term growth of the system. When something feels slow in six months, the baseline will say whether it always was.\nOne research thread ran alongside the technical work without producing any immediate changes.\nCloudflare fulfils two separate roles in the stack: DNS management for the domain, and the tunnel that makes services accessible from outside the house without opening ports on the home router. Both work well. Both are problems.\nThe tunnel terms of service prohibit video streaming and have a 100MB per item limit. For a photo and video library with tens of thousands of items, this is a real risk — not theoretical, but a documented grounds for account suspension. The company is American, which is a deliberate pragmatic exception to the European-first principle that governs the rest of the stack. And as long as DNS and tunnel are at the same provider, migrating either one increases the complexity of migrating the other.\nThe research identified a replacement candidate: Pangolin, an open-source identity-based access platform built on WireGuard. It can run on a small VPS. A lightweight client on the Pi makes an outgoing encrypted connection to the server — no open ports on the home router needed. Incoming requests arrive at the cloud server, pass through a reverse proxy and an authentication layer, and travel back to the Pi through the tunnel. The home IP address stays hidden. TLS is managed end-to-end. No third party sits in the middle.\nThe migration is not happening yet. Cloudflare Tunnel is stable and the migration carries real risk — particularly around the authentication redirect URIs that have already caused problems twice when URLs changed. The right moment is Part II, after a Lab validation on a temporary server confirms the architecture works as designed.\nThe backup DNS nameservers at the European registrar are already configured. When the migration happens, the DNS move can be made independently of the tunnel migration. The two roles that Cloudflare currently plays can be separated cleanly. That preparation was deliberate.\n","date":"4 May 2026","externalUrl":null,"permalink":"/notes/making-it-production-ready/","section":"Notes","summary":"On the difference between a stack that works and one that is ready for a family. URL migration across six layers without downtime, split-horizon DNS, a CrowdSec that had been silently broken for weeks, and three network architecture decisions that will govern the next five years.","title":"Making it production ready","type":"notes"},{"content":"","date":"4 May 2026","externalUrl":null,"permalink":"/tags/prometheus/","section":"Tags","summary":"","title":"Prometheus","type":"tags"},{"content":"","date":"4 May 2026","externalUrl":null,"permalink":"/tags/proton-drive/","section":"Tags","summary":"","title":"Proton-Drive","type":"tags"},{"content":"","date":"1 May 2026","externalUrl":null,"permalink":"/tags/docker/","section":"Tags","summary":"","title":"Docker","type":"tags"},{"content":"","date":"1 May 2026","externalUrl":null,"permalink":"/tags/postgresql/","section":"Tags","summary":"","title":"Postgresql","type":"tags"},{"content":"","date":"1 May 2026","externalUrl":null,"permalink":"/tags/raspberry-pi/","section":"Tags","summary":"","title":"Raspberry-Pi","type":"tags"},{"content":" Why # There is a specific kind of project confidence that accumulates as things start working. Each service deployed, each integration completed, each monitoring alert configured — the stack feels increasingly solid. The danger of that feeling is that it becomes easy to confuse \u0026ldquo;things are working\u0026rdquo; with \u0026ldquo;things will keep working.\u0026rdquo;\nBackup was not an afterthought in this project. BorgBackup was configured in Phase 0. PostgreSQL dumps were running daily. The borgmatic hooks were in place. But there is a difference between having a backup and having a tested, documented, externally executable recovery procedure. The first is a technical task. The second is a discipline.\nPhase 7 was the discipline.\nThe question it asked was not \u0026ldquo;is there a backup?\u0026rdquo; but \u0026ldquo;could someone else restore this system from the backup, following only the documentation, without calling me?\u0026rdquo;\nThe honest answer, before this phase, was no.\nFamily # Every service in the stack has a break-glass route — a way to log in when the authentication system itself is unavailable. Vaultwarden has an admin panel accessible without SSO. Seafile has a local account that works regardless of Authentik\u0026rsquo;s state. Grafana has a local admin. Immich has a local admin.\nOutline did not. There was no working authentication path that bypassed the OIDC flow. If Authentik went down, the wiki was unreachable.\nThe fix was straightforward once identified. The more important thing was the identification itself — going through every service, one by one, and asking: if Authentik is completely unavailable, can this service still be accessed? The answer was no for one service. It could have been no for others if the exercise had not been done.\nThis is the break-glass matrix. A table, one row per service, documenting the fallback route and where the credentials live. It exists for the scenario where I am not there to explain it.\nTech # The backup scope audit found eight gaps.\nThe most significant were not databases. Everyone audits databases. The gaps were in the files that sit alongside the databases — the Vaultwarden RSA key stored in the data directory, the PKI certificate authority private key, the Caddy CA chain, the Metabase application database that nobody had thought to add to the dump hooks. None of these would have been restored from a database dump alone. All of them would have been lost in a bare-metal recovery.\nThe fix was adding them explicitly to the backup scope. The lesson was that a backup strategy designed around \u0026ldquo;dump the databases\u0026rdquo; is incomplete for a stack where several services store critical state outside the database.\nMonitoring was added to make the backup visible. A small bash script runs after each borgmatic backup and writes a Unix timestamp to a file. Node Exporter reads the file. Prometheus scrapes Node Exporter. Grafana shows a panel: time since last successful backup. Green below 24 hours, orange below 48, red above. The pipeline from bash script to Grafana panel took an afternoon. The value is that backup failure is now something Grafana can alert on, not something discovered retroactively when a restore is needed.\nThe Authentik incident was instructive. During MFA policy configuration, a group binding was accidentally placed on the authentication flow itself rather than on a specific stage within the flow. This blocked the flow for all users — including administrators. There was no way to log in to Authentik to fix it. The recovery required a one-minute token generated from the command line, used immediately before expiry, to access the admin interface and remove the binding. The lesson: in Authentik, policies on flows block everyone. Policies on stages are targeted. The distinction is not obvious from the interface.\nProton Drive remained blocked throughout the phase. Multiple authentication attempts triggered an anti-bot verification that did not resolve. The off-site backup is the one gap that was not closed — local BorgBackup on the attached drive remains the only copy outside the primary database. This is a known risk, documented, with Hetzner Storage Box as the fallback option.\nProject # The most useful output of this phase was a document written for someone else.\nThe DR runbook in the wiki is not written for me. It is written for a technically competent person who has never seen this system before, who needs to restore it after something has gone wrong, and who cannot ask questions. It explains the architecture in one paragraph. It lists the services and their dependencies in order. It documents each restore step with exact commands. It includes the break-glass matrix and the secret inventory locations.\nWriting it required making explicit every assumption I had been carrying implicitly. Where are the backup keys? Off-site, secured with MFA, which requires a TOTP code from the same account. Is that circular? Slightly. The mitigation is that backup codes for the TOTP device are stored separately, also in the document.\nEvery system has this kind of dependency chain. Most systems never write it down. Writing it down makes the chain visible — and visible chains can be strengthened.\nThe restore simulation confirmed the backup was functional. Two databases restored into parallel test databases, row counts matched, test databases deleted. Recovery point objective measured at under 24 hours. These are numbers, not feelings.\nThe external validation — having someone else follow the runbook without guidance — remains open. That is the test that actually matters. It is planned for the next phase.\n","date":"1 May 2026","externalUrl":null,"permalink":"/notes/what-if-it-breaks/","section":"Notes","summary":"On backup gaps nobody noticed, a break-glass matrix for nine services, an Authentik misconfiguration that locked out every user including the admin, and writing a recovery document for someone who is not you.","title":"What if it breaks","type":"notes"},{"content":" Why # There is a point in every infrastructure project where the foundation stops being interesting and the services start to matter. The database is running. The reverse proxy is configured. Authentication works. And then the question becomes: what is this actually for?\nFor HomeStack the answer is specific. Files the family can access without Google. Photos that do not live on someone else\u0026rsquo;s server. A financial overview that belongs to us — not to a bank\u0026rsquo;s export format or a SaaS subscription we pay for indefinitely.\nThis phase was about building those three things. Each one represents a category of data that most families have quietly surrendered to Big Tech without a clear moment of decision. Getting them back required making explicit choices about where data lives, who can access it, and what happens to it when a service stops existing.\nFamily # Immich was the one that landed. A photo platform with a mobile app that looks and feels like Google Photos — the same infinite scroll, the same face detection, the same \u0026ldquo;on this day\u0026rdquo; memories — but running on a server in the home office. I uploaded ten test photos during setup. My partner walked past while I was doing it and asked what I was looking at. I showed her. The reaction was different from anything before. Not \u0026ldquo;what is it\u0026rdquo; but recognition. This is what we use every day. This could replace that.\nSeafile was quieter. A file sync client that works. Documents, folders, shared libraries. The family will use it without knowing much about what it is — which is exactly the goal. Complexity belongs to the builder, not the user.\nMetabase is something my partner will probably never open unprompted. A financial dashboard, linked to a custom database, showing spending by category and net worth over time. It exists because I wanted to understand where our money goes without exporting CSV files from a bank portal every month. Whether it becomes a household tool depends on whether the data in it becomes trustworthy over time. That takes months, not a week.\nTech # Each service taught something different.\nSeafile required a second database engine. The unified PostgreSQL strategy had one documented exception already — Uptime Kuma using SQLite. Seafile CE requires a MySQL-compatible database and supports nothing else. MariaDB became the second exception. The pattern held: name it, justify it, document it, move on. What matters is that the backup strategy accounts for it — a mysqldump hook alongside the existing pg_dump hooks, tested before the service was considered done.\nImmich required its own PostgreSQL instance with vector extensions for machine learning embeddings. The decision to give it a separate container rather than adding extensions to the shared database was straightforward — vector workloads are categorically different from relational queries, and the risk of destabilising the shared instance was not worth the operational simplicity. The harder problem was TLS.\nCaddy\u0026rsquo;s tls internal does not use the OpenSSL Root CA generated in an earlier phase. It generates its own certificate authority — a short-lived intermediate hierarchy that no other service knows about. When Immich tried to reach Authentik over HTTPS for the OIDC discovery endpoint, the TLS handshake failed. The fix required extracting Caddy\u0026rsquo;s CA chain via its admin API, combining it with the system certificate store, and mounting the result into the Immich container alongside a Node.js-specific environment variable. Node.js 24 does not read from the system certificate store automatically — it uses a compiled-in bundle. This is not documented prominently. It is the kind of thing you find out by reading error logs carefully.\nThe financial stack started with a rejected tool. Firefly III is well-maintained, widely used, and failed one test: it is not a native OIDC client. Integrating it with Authentik would require a middleware proxy container — one extra failure point, one more thing to maintain, and a workaround rather than a proper integration. Every public-facing service in this stack needs to be a native OIDC client. That is a principle, not a preference. Firefly was evaluated in the Lab, found wanting on that single criterion, and discarded.\nWhat replaced it was a custom PostgreSQL schema with Metabase as the visualisation layer. The data model started as an MVP with eleven entities and grew, through two rounds of redesign, to fifty. Polymorphic ownership — a single owner entity that can represent a person, a partnership, a household, or a business activity. Validity periods on every record, so historical data can be reconstructed. A symmetry principle discovered during Lab testing: assets, liabilities, and receivables should all be modelled the same way, as a definition entity plus a time series of valuations. That insight was not in the original design. It emerged from running the schema against real data.\nProject # Five days. Three services live on Dev. Seafile, Immich, and a financial stack with a database schema that took longer to design than to deploy.\nTwo recurring patterns worth naming.\nThe first: credentials in chat. Three times during this week, a secret appeared in a chat window — a database password, an API key, a token — because I pasted a configuration file without masking it first. Each time the secret was rotated immediately. Each time the lesson was the same: use sed to mask values before pasting anything that might contain credentials. This is not a difficult habit to build. It requires deciding in advance that the rule applies even when you are moving fast.\nThe second: the SanDisk. The backup drive had been physically attached to the Pi since Phase 0. It had never been added to /etc/fstab. This meant that after every reboot, the drive was not mounted, and the backup would have run silently against a missing path. The fix was a single line in fstab with a UUID and a nofail flag. It took five minutes. The oversight had been present for weeks.\nBoth patterns point at the same thing. Operational discipline is not about the hard problems. It is about the small things that are easy to defer because they are not urgent. Until they are.\n","date":"27 April 2026","externalUrl":null,"permalink":"/notes/filling-the-stack/","section":"Notes","summary":"One week, three services: file storage, photo management, and a financial administration stack built from scratch. On pragmatic exceptions, a data model that grew to fifty entities, and a backup drive that had never been in fstab.","title":"Filling the stack","type":"notes"},{"content":"","date":"27 April 2026","externalUrl":null,"permalink":"/tags/mariadb/","section":"Tags","summary":"","title":"Mariadb","type":"tags"},{"content":"","date":"27 April 2026","externalUrl":null,"permalink":"/tags/metabase/","section":"Tags","summary":"","title":"Metabase","type":"tags"},{"content":"","date":"26 April 2026","externalUrl":null,"permalink":"/tags/firefly/","section":"Tags","summary":"","title":"Firefly","type":"tags"},{"content":"","date":"26 April 2026","externalUrl":null,"permalink":"/tags/infrastructure/","section":"Tags","summary":"","title":"Infrastructure","type":"tags"},{"content":"","date":"26 April 2026","externalUrl":null,"permalink":"/tags/redis/","section":"Tags","summary":"","title":"Redis","type":"tags"},{"content":" Why # There is a version of this project where documentation is an afterthought — something you write after the infrastructure is stable, when there is time. That version produces systems that work until the person who built them is unavailable, and then quietly stops working.\nHomeStack was always going to need a wiki. Not for external readers, but for the family. For the day when my partner needs to find something and I am not there to explain where it is. For the day when a child asks what the server in the office actually does. For the day when someone needs to restore a backup and the documentation is the difference between a procedure and a guess.\nThere is a parallel question about financial data. Every bank transaction I have ever made is stored in a database I do not control, in a format I cannot export cleanly, subject to terms I did not negotiate. For most people that is an invisible arrangement. I had started to find it uncomfortable — not because anything had gone wrong, but because I had no alternative. This phase was the beginning of building one.\nFamily # The wiki went live, accessible from outside the house, login via the same account used for everything else on the stack. I showed my partner. The reaction was different from the password manager — less \u0026ldquo;hm\u0026rdquo; and more genuine interest. A place to put things. Documents, notes, shared information. Something that feels like shared infrastructure rather than a technical experiment.\nThe honest answer is that Outline was mostly empty. Three spaces, fourteen collections, placeholder titles. The structure was there. The content was not. A wiki without content is a very organised empty room.\nBut the room exists now. That is enough for this phase.\nTech # Before the tools: a word on environments. HomeStack runs on three separate stages. The Dev environment is a Raspberry Pi in my home office — the real server, where everything gets built and tested with real configuration but no family data yet. The Lab is a temporary cloud server I rent by the hour for experiments that might break things — isolated, disposable, no consequences if something goes wrong. Prod is where the family lives, eventually. The financial tool evaluation happened entirely in the Lab. Whatever conclusions came out of it would inform what gets built on Dev.\nThe URL migration was supposed to be straightforward. All external services had been running on my self labeled \u0026lsquo;development\u0026rsquo; node. Now that the wiki and password manager were live externally, the OIDC configuration needed to follow. Change the redirect URIs, update the environment variables, reload the containers.\nWhat actually happened: the URL existed in six different places. The Authentik provider redirect URI. The service environment variables. The Caddy configuration. The Cloudflare tunnel. The Docker extra_hosts. And — the one I did not anticipate — the sso_users table in the Vaultwarden database, where SSO identifiers are stored as strings. Changing the URL broke Vaultwarden logins for all users because the stored identifiers no longer matched the new authority URL.\nThe fix required a direct SQL UPDATE on the database, followed by deleting and recreating all Vaultwarden users via the admin panel. It worked. The lesson was that OIDC is not a configuration layer — it is a dependency chain, and URL changes propagate in ways that are not always visible until something breaks.\nThe financial tool evaluation ran in parallel. Firefly III was the leading candidate — well-maintained, feature-rich, widely used in the self-hosting community. It failed on one test: it has its own OAuth server but is not a native OIDC client. Integrating it with Authentik would require oauth2-proxy as a middleware container. One extra container, one extra failure point, one more thing to maintain — and a workaround rather than a proper integration. Every public-facing service in this stack needs to be a native OIDC client. Firefly is not. That was enough.\nThe chosen route — a custom PostgreSQL schema with Metabase as the visualisation layer — is more work. It is also the only option that gives complete control over the data model, supports forecasting without workarounds, and integrates cleanly with Authentik. The data model started as a practical schema and grew into something more considered: polymorphic ownership, validity periods, explicit reliability attributes, a Rules as Code approach for fiscal logic. Forty entities on paper. Eleven for the first implementation.\nProject # Two tracks running simultaneously is a different kind of complexity than one track with problems. The wiki track was mostly execution — deploy, configure, migrate, test. The financial track was mostly thinking — evaluate, reject, design, scope. Both finished in the same week.\nThe Lab was cleaned up completely after the Firefly evaluation. All containers, volumes, and networks removed. This matters more than it sounds. A Lab that accumulates state becomes a source of confusion — you stop knowing what is running, what is a test, what is real. Cleanup is not housekeeping. It is part of the discipline.\nOne observation from this phase: the moment you have a wiki, you start to notice everything that is not documented. The decision records, the implementation plans, the project logs — all of that was already there. But the procedures. The runbooks. The \u0026ldquo;here is what to do if the server stops responding at 2am\u0026rdquo; documents. Those were still missing.\nThey are still missing. That is a known gap, not a forgotten one.\n","date":"26 April 2026","externalUrl":null,"permalink":"/notes/the-wiki-and-the-ledger/","section":"Notes","summary":"On documentation as infrastructure, the fragility of OIDC under URL migration, why Firefly III failed a single architectural test, and the beginning of a financial data model that grew more ambitious than expected.","title":"The wiki and the ledger","type":"notes"},{"content":"","date":"26 April 2026","externalUrl":null,"permalink":"/tags/vaultwarden/","section":"Tags","summary":"","title":"Vaultwarden","type":"tags"},{"content":" Why # There is a particular kind of professional blindness that comes from spending years advising organisations on IT without doing the technical work yourself. You know what good looks like. You can evaluate an architecture, ask the right questions in a steering committee, identify when a team is overcomplicating something. But you cannot sit down and configure it. The distance between knowing and doing is real, and it is easy to mistake familiarity with competence.\nHomeStack was always partly about closing that gap. Not to prove something, but because the gap bothered me. I had spent years in IT advisory — programmes with hundreds of people, strict compliance requirements, enterprise governance — without ever being the person who actually writes the Compose file or debugs the TLS handshake. This project was a deliberate return to the hands.\nThe question was: how do you track that honestly?\nFamily # This one is invisible to the family. They do not see the spreadsheet or the framework. They see whether things work, whether the apps are fast, whether login is easy. The learning infrastructure exists entirely for me.\nThough there is something to be said for building in a way that forces you to understand what you are doing. When something breaks at an inconvenient moment — and it will — the person who understands the system can fix it. The person who copied a tutorial cannot.\nTech # Two frameworks, introduced at the same time.\nThe first is SFIA — the Skills Framework for the Information Age. An international standard that defines competency levels across IT disciplines, from Linux administration to cryptography to network architecture. HomeStack uses twenty of them. Each skill is defined at three levels: what you can do at L1 (awareness), L2 (working independently), and L3 (full practitioner). The levels above that exist in the framework but are not the target here.\nThe honest starting point was humbling. Most skills sat at L1 to L1.5. Not because the concepts were unfamiliar — they were not — but because there is a difference between knowing that CrowdSec exists and having configured it, debugged it, and understood why it failed. Version 1.0 of the tracker was written in April 2026 as HomeStack moved from foundation to first services. It was mostly a record of starting points.\nVersion 2.0 came two weeks later, after several phases of actual building. The numbers moved. Not dramatically, but measurably. Database administration from L1.5 toward L2 after designing a polymorphic schema and debugging a PostgreSQL permissions error. Network architecture toward L2 after coordinating a URL migration across six different configuration locations. Identity and access management after understanding, at the database level, how Authentik actually stores role assignments.\nThe second framework is Bloom\u0026rsquo;s Taxonomy. Less formal, more personal. Six levels of learning depth: remembering facts, understanding concepts, applying them in practice, analysing when things go wrong, evaluating design trade-offs, creating something new. At the end of each phase, a short reflection: what did I just remember, understand, apply, analyse, evaluate, create?\nThe combination works because they measure different things. SFIA measures where you are. Bloom\u0026rsquo;s measures how deeply you engaged with what you just did. You can complete a phase at Bloom\u0026rsquo;s L3 — applied the thing, it worked — without really understanding why. The L4 and L5 questions force you to go back and look.\nProject # The Dunning-Kruger check is the most useful part.\nEvery skill entry in the tracker includes a note about where I might be overestimating myself. Database administration: I designed a fifty-entity schema. But I have not done a restore test. I have not profiled query performance on realistic data volumes. The schema works in Dev with seed data. Whether it holds under real use is not yet known. The tracker says L2.5, not L3, for a reason.\nThis matters more than it might seem. An IT consultant who advises large organisations knows, professionally, that most failures come not from the hard problems but from the things people assumed were solved. Backup strategies that were never tested. Security configurations that were documented but not verified. Monitoring that was set up but whose alerts nobody checked.\nThe tracker is a small mechanism for applying that professional knowledge to my own work. For asking, after every phase: what did I say I understood, and what would actually break if I had to rely on it?\nThe answer is often instructive.\n","date":"20 April 2026","externalUrl":null,"permalink":"/notes/learning-out-loud/","section":"Notes","summary":"On tracking your own learning while building — two frameworks, one honest question, and why a consultant who manages IT programmes for a living needed a structured way to admit what he didn’t know.","title":"Learning out loud","type":"notes"},{"content":"","date":"20 April 2026","externalUrl":null,"permalink":"/tags/node-exporter/","section":"Tags","summary":"","title":"Node-Exporter","type":"tags"},{"content":" Why # There is an inherent tension in building privacy infrastructure and then connecting it to the internet. The entire premise of HomeStack is that your data stays yours — that no company sits between you and your family\u0026rsquo;s files, photos, and passwords. And then you spend a weekend configuring Cloudflare to relay traffic to your server.\nThis is not hypocrisy. It is a trade-off, and trade-offs need to be named.\nThe alternative to a tunnel service is opening ports on your home router — publishing your home IP address, managing firewall rules, accepting that every port you open is a surface that needs defending. For a family server with no dedicated security team, that is a worse trade-off. Cloudflare sees the domain names. They do not see the content, because TLS terminates on your side. You accept the metadata exposure in exchange for not exposing your home network.\nI wrote a decision record for it. I still think it was the right call.\nFamily # The moment Vaultwarden loaded on my phone over mobile data — not on the home network, not via a local IP, but from the actual internet — felt different from anything that had come before. The server was no longer a project in my home office. It was infrastructure.\nI showed my partner. The password manager now works from anywhere. The reaction was more interested than before. Less \u0026ldquo;what is it\u0026rdquo; and more \u0026ldquo;so I can use this when I\u0026rsquo;m not home?\u0026rdquo; Yes. Exactly that.\nThat question — can I use this when I\u0026rsquo;m not home — is the real acceptance test. Not a benchmark, not a security audit. Just: does it work when the person who built it isn\u0026rsquo;t in the room to fix it?\nTech # Phase 2 has two separate access paths, and keeping them separate was a deliberate architectural choice. Cloudflare Tunnel handles user-facing services: Vaultwarden and Authentik, reachable at their public URLs. Tailscale handles administration: SSH access to the Pi over a WireGuard mesh, visible only to devices I control. One path for the family. One path for me.\nThe Root CA came first. A ten-year certificate authority, private key stored in Vaultwarden and nowhere else reachable from the network. The key is what makes E2E encryption possible — it is what allows me to eventually tell Cloudflare to verify the origin certificate rather than trust blindly. In this phase, that step was deferred. noTLSVerify: true is a documented debt, not a forgotten shortcut.\nThe tunnel had a problem. The first version had two connectors — one from a package install I had removed, one from the Docker container I had replaced it with. Cloudflare was distributing traffic between them. The old connector could not handle requests. The fix was to delete the tunnel entirely and start over. The lesson was that cleanup in infrastructure is not optional. Ghosts of old configurations do not disappear; they just fail silently until they fail loudly.\nGrafana was the final piece. Node Exporter, Prometheus, Grafana — three services that exist only to tell you what the other services are doing. CPU temperature, memory, disk usage, container uptime. The Pi runs warm but well within limits. I now know this with numbers, not intuition.\nProject # Three days. One token accidentally pasted into a chat window — tunnel deleted, new token generated, lesson learned about where credentials end up when you\u0026rsquo;re moving fast. A Prometheus container that crashed on first start because the data directory was owned by root. A Grafana browser tab that wouldn\u0026rsquo;t load because the hosts file on the laptop was still pointing at an old VPN address from a different project entirely.\nNone of these were serious problems. All of them were the kind of problem that doesn\u0026rsquo;t appear in tutorials — the accumulated friction of real environments, where old configuration follows you around like luggage you forgot to unpack.\nMonitoring is always the last thing people build and the first thing they wish they had built earlier. I understand why. It produces no visible output for users. It generates no features. It just sits there, quietly collecting numbers, until the moment when those numbers are the only thing standing between you and a three-hour debugging session. Phase 2 is done. The door is open. The cameras are on.\n","date":"20 April 2026","externalUrl":null,"permalink":"/notes/opening-the-door-carefully/","section":"Notes","summary":"On the tension between privacy infrastructure and connecting it to the internet, the first time the server worked from outside the house, and why monitoring is always the last thing you build and the first thing you wish you’d built earlier.","title":"Opening the door — carefully","type":"notes"},{"content":"","date":"20 April 2026","externalUrl":null,"permalink":"/tags/sfia/","section":"Tags","summary":"","title":"Sfia","type":"tags"},{"content":"I work as consultant. By day, I help governments and public institutions navigate the complexity of technology — policy, governance, the hard questions about what it means for public organisations to be sovereign over their own systems.\nBy night, I build one.\nthornbush.nl is where I think out loud about that work. Not the professional kind — the personal kind. The kind where you assemble a server on a kitchen table, make mistakes that cost you an evening, and learn something that no certification course would have taught you.\nWhat I build # HomeStack is a self-hosted infrastructure stack running on a Raspberry Pi in our home. It replaces Google Photos, cloud storage, a password manager, a wiki, and a handful of other services that used to live in someone else\u0026rsquo;s data centre. Everything encrypted, everything backed up, everything documented well enough that it could be handed to someone else if it had to be.\nWhat makes it interesting is that I run it alone. Strategist and lead architect when deciding what to build and why. Project manager when breaking it into phases and tracking what\u0026rsquo;s done. Platform and DevOps engineer when wiring containers together. Security and identity engineer when hardening the stack and managing access. Infrastructure engineer when the backups fail at 3am. And end user — the person who actually has to live with every decision I made in the other roles.\nIt started as a cost-saving exercise. It became something more interesting: a practical education in the systems that underpin modern digital life, built at a scale where every decision is visible and every mistake is instructive.\nWhy thornbush # A thornbush is unglamorous infrastructure. It doesn\u0026rsquo;t tower. It doesn\u0026rsquo;t impress. But it holds its ground, it\u0026rsquo;s hard to uproot, and things tend to grow around it.\nThat\u0026rsquo;s roughly what I\u0026rsquo;m going for.\nWhat you\u0026rsquo;ll find here # The moment you rely on something you built yourself — for passwords, photos, files, identity — it becomes production. And production has consequences.\nThese notes are about what those consequences actually look like. Not the polished retrospective where everything worked out, but the decision made at 11pm that turned into a two-hour debug session. The configuration variable whose name meant the opposite of what it said. The backup that had never been restored until the day it needed to be.\nIf you work in digital government and think about sovereignty at scale, you\u0026rsquo;ll find a smaller version of the same problems here. If you\u0026rsquo;re considering running your own infrastructure, you\u0026rsquo;ll find an honest account of what it takes. If you\u0026rsquo;re neither — you\u0026rsquo;re probably in the wrong place, and that\u0026rsquo;s fine too.\nI write for people who build things and want to understand why they work, not just that they do.\n","date":"18 April 2026","externalUrl":null,"permalink":"/about/","section":"Built for a family. Running in our home. Enterprise thinking. Learning by doing. Documented honestly.","summary":"I work as consultant. By day, I help governments and public institutions navigate the complexity of technology — policy, governance, the hard questions about what it means for public organisations to be sovereign over their own systems.\nBy night, I build one.\nthornbush.nl is where I think out loud about that work. Not the professional kind — the personal kind. The kind where you assemble a server on a kitchen table, make mistakes that cost you an evening, and learn something that no certification course would have taught you.\n","title":"About","type":"page"},{"content":"","date":"18 April 2026","externalUrl":null,"permalink":"/tags/fail2ban/","section":"Tags","summary":"","title":"Fail2ban","type":"tags"},{"content":"","date":"18 April 2026","externalUrl":null,"permalink":"/tags/nextcloud/","section":"Tags","summary":"","title":"Nextcloud","type":"tags"},{"content":"","date":"18 April 2026","externalUrl":null,"permalink":"/tags/proton-mail/","section":"Tags","summary":"","title":"Proton-Mail","type":"tags"},{"content":"","date":"18 April 2026","externalUrl":null,"permalink":"/tags/sqlite/","section":"Tags","summary":"","title":"Sqlite","type":"tags"},{"content":" Why # Every project has assumptions. Most of them are never written down. They live in the builder\u0026rsquo;s head, applied inconsistently, invisible to anyone else — and sometimes invisible to the builder too. A decision made in week one shapes what is possible in week ten, but without documentation, the connection is never made explicit. You just find yourself constrained in ways you cannot fully explain.\nHomeStack started with a strategic framework before a single service was running. Ten principles, six pillars, four goals. Written down, argued through, ordered by priority. The document was called the constitution — the thing everything else would be tested against.\nVersion 1.0 was written in early April 2026. It had fourteen principles and thirteen pillars. It was thorough in the way that early project documents often are: comprehensive, a little redundant, trying to cover every case before the cases had actually occurred.\nVersion 2.0, written two weeks later on April 18th, cut it in half. Ten principles, six pillars. Not because the thinking had changed, but because the early version had confounded principles with procedures. A principle is a value — something that holds regardless of how the technology changes. A procedure is how you implement it today. Mixing the two produces a document that becomes outdated the moment anything changes and that nobody reads.\nThe revision was also about honesty. Some of the original fourteen principles were aspirational rather than commitments. Version 2.0 kept only what could actually be tested. If a decision could not be evaluated against a principle, the principle was either too vague or not really a principle.\nFamily # The constitution is not a document the family will ever read. It exists for one person — the builder — as a check against drift. The question it answers is not \u0026ldquo;what do I want to build\u0026rdquo; but \u0026ldquo;how do I know if I am building the wrong thing.\u0026rdquo;\nPrinciple one is the most important one for the family: usability is the highest priority. Complexity belongs to the builder, not the user. If a technically better solution is harder to use, the technique loses. This sounds obvious. It is surprisingly easy to violate when you are deep in a problem and the elegant solution requires the user to understand something they should not have to understand.\nPrinciple four is the one that matters when things go wrong: recoverability. A backup that only the builder can restore is not a backup. The documentation must be clear enough for a family member, or an outside expert, to follow without help. This is harder than it sounds. It requires writing for a reader who does not share your assumptions — which is a different kind of discipline than writing for yourself.\nTech # Three documents govern HomeStack, and all three were established on April 18th — the same day as the strategic framework revision.\nThe first is the constitution itself: why and what. Principles, goals, the values that do not change when the technology does.\nThe second is the architecture document: how the system is designed to work, the decisions that shaped it, and the reasoning behind those decisions. It sits between principle and practice. A strategic principle says \u0026ldquo;data must be recoverable without the builder.\u0026rdquo; The architecture document says which database engine is used, why PostgreSQL was chosen over alternatives, what the backup strategy looks like in practice, and what exceptions exist and why. Without it, the gap between principle and practice is invisible — you know what you want and you know what you have, but you cannot reconstruct why the system is built the way it is, which means you cannot change it intelligently.\nThe architecture document started on April 18th and will be revised continuously. An architecture document that never changes is either describing a system that never changes — unlikely — or it has been abandoned as a living reference and become a historical artefact.\nThe third document is the baseline: a snapshot of the actual running state on a specific date. Every service, every version, every open risk. Not aspirational — actual. The value of a baseline is that it makes drift visible. When something breaks six weeks later, the baseline is the reference point. What changed? When? Why? Without it, troubleshooting is archaeology.\nThe first baseline covered what existed at the time: Ubuntu Server 24.04, Docker with three bridge networks, Caddy as the reverse proxy, PostgreSQL as the primary database, SSH hardening, UFW, Fail2Ban, AIDE, BorgBackup. No external services yet. No SSO. No monitoring beyond Uptime Kuma. A short document — deliberately. A baseline that tries to describe everything becomes a burden to maintain. A baseline that describes the actual current state, updated after each significant change, becomes a tool.\nProject # Three documents, one day, before most of the stack existed.\nThe instinct to write the framework first rather than last is worth examining. It is not obviously correct. You could argue that you should build first and extract principles from what you actually did. That approach produces principles grounded in reality but tends to produce post-hoc rationalisations — stories that justify what happened rather than tests that would have changed behaviour.\nWriting the framework first, then revising it when it proved too abstract, produced something different. The first version exposed the assumptions. The revision made them honest. The result was a document that could actually be used to make decisions — not just to describe them after the fact.\nThe architecture document and the baseline are the complement. The framework says what matters. The architecture says how it is built and why. The baseline says what exists. Together they answer a question that most projects never ask clearly: does what we have match what we said we were building?\nFor HomeStack on April 18th, the answer was: partially. The foundation was sound. The services were not yet built. The principles were written. The practice was ahead of them.\nThat gap is not a problem. It is a plan.\n","date":"18 April 2026","externalUrl":null,"permalink":"/notes/the-constitution/","section":"Notes","summary":"On writing a strategic framework before anything works, revising it when it becomes honest, and why three documents together — constitution, architecture, and baseline — are the difference between a project and a system.","title":"The constitution","type":"notes"},{"content":" Why # Before a single service was running, I had a database strategy document. A folder structure decision record. A Git governance policy. A backup philosophy. And a growing sense that I was doing the exact thing I spend my professional life warning clients about: confusing documentation with progress.\nThere is a legitimate reason for this, and an embarrassing one. The legitimate reason is that decisions made at the foundation are expensive to undo. Choosing the wrong database engine in week one means migrating everything in week ten. The embarrassing reason is that writing documents feels productive without the risk of anything actually breaking.\nEventually I accepted the contradiction and leaned into it. The documents would serve a real purpose — not as governance theatre, but as a forcing function. Every architectural choice would be argued, not assumed. Every exception would be named and justified. If I couldn\u0026rsquo;t explain why, I couldn\u0026rsquo;t proceed.\nThat discipline turned out to matter more than I expected.\nFamily # The server was running. Nothing visible had changed in the house. My partner hadn\u0026rsquo;t noticed yet — or was being polite.\nThe first thing I wanted to show was a password manager. Not because it was technically impressive, but because it was immediately useful: one place for all the passwords the family had been scattering across browsers, sticky notes, and memory. A shared vault. Something real.\nIt took longer than expected. But when it finally worked — HTTPS, no browser warnings, a proper login — I called my partner over. The reaction was cautious but genuine. What is it? A password manager. For all of us? Yes. And it\u0026rsquo;s running on that thing in your office? Yes. Hm.\nThat was enough.\nTech # The core architectural decision of this phase was straightforward and has held ever since: one database engine for everything. PostgreSQL, everywhere, always. No exceptions — except the two exceptions, both documented.\nUptime Kuma doesn\u0026rsquo;t support PostgreSQL. It uses SQLite. The pragmatic choice was to accept the exception, name it, and move on. Seafile — chosen over Nextcloud after a benchmark that made Nextcloud look embarrassing — requires a MySQL-compatible database. MariaDB became the second exception. Both are isolated. Neither contaminates the rest of the stack.\nThe larger lesson was about the difference between principles and rules. A rule says PostgreSQL always. A principle says: be consistent, be recoverable, be honest about trade-offs. Uptime Kuma with SQLite serves the principle. It violates the rule. I wrote a decision record for it anyway — which forced me to articulate why the exception was justified instead of just letting it slide.\nSMTP was harder. Getting Authentik to send email through Proton Mail required mounting certificates into Alpine containers, debugging Django\u0026rsquo;s TLS verification, discovering that the Docker Compose entrypoint field does not behave the way you assume, and spending an evening on a problem that a large organisation would have assigned to a specialist. Eventually it worked. The test email arrived. It felt disproportionately satisfying.\nProject # Seven days. Vaultwarden, Caddy with a self-signed Root CA, Authentik with a full upgrade path from 2024 to 2026 in one session, CrowdSec at the network edge, Trivy for container scanning, BorgBackup extended to cover the new stack, and a cron framework to tie it together.\nThe Authentik upgrade deserves a note. The version I had installed was more than two years behind the current release. Database migrations require going through every major version in sequence — no jumping. So I did: twelve upgrade steps, each one a docker compose pull \u0026amp;\u0026amp; down \u0026amp;\u0026amp; up, each one verified in the browser before proceeding. It took an afternoon. It was tedious and completely correct.\nCrowdSec asked a question I keep returning to. Installation took under an hour. The firewall bouncer was active. The home network was whitelisted. Fail2Ban was already running. Within a day of setup, the stack had more active threat detection than many of the organisations I advise professionally.\nI don\u0026rsquo;t think this reflects well on those organisations. I think it reflects how low the baseline is, and how much of enterprise security theatre consists of complexity that protects budgets more than systems.\nThe foundation was closed. Everything that came next would build on something solid.\n","date":"18 April 2026","externalUrl":null,"permalink":"/notes/the-foundation/","section":"Notes","summary":"Seven days building the base stack — PostgreSQL, Vaultwarden, Authentik, CrowdSec, BorgBackup — and the question of why large organisations can’t do what one person can do on a Saturday afternoon.","title":"The foundation, or: why I wrote more documents than code","type":"notes"},{"content":"","date":"18 April 2026","externalUrl":null,"permalink":"/tags/uptime-kuma/","section":"Tags","summary":"","title":"Uptime-Kuma","type":"tags"},{"content":" Why # There is a specific kind of decision that only works if you don\u0026rsquo;t think about it too long. Buying the hardware was that decision. Once the Raspberry Pi was ordered, there was no way back. The project was real.\nThat didn\u0026rsquo;t stop me from overthinking everything else. Before a single cable was connected, I had started a strategic framework document. A project plan. Principles. A governance structure. Iteration after iteration of documents describing a system that didn\u0026rsquo;t exist yet. Too much detail, too early, for something that was still just a cardboard box on the doorstep. Looking back, it was displacement activity — the kind of preparation that feels like progress but is really just a way of postponing the moment when something could actually go wrong.\nEventually I stopped writing and started building.\nFamily # Suddenly I was spending more evenings in my home office. Not working — at least not in the usual sense. My partner noticed. A homeserver? Why? The response was somewhere between scepticism, mild disinterest, and — I\u0026rsquo;d like to think — a quiet kind of pride. Hard to tell.\nThe timing was not accidental. Around the same time, I inherited a vinyl record collection. A new turntable arrived. While records played in the background, I quietly let it be known that we would soon need to have a conversation about all those gigabytes of photos sitting in Google and Microsoft cloud storage. I chose my moment carefully.\nTech # The architecture existed long before the hardware did. I had researched open source components, compared options, made decisions — all in documents, all theoretical. The ambition was considerable: two Raspberry Pis (one for development, one for production), a VPS for a lab environment, external access, SSL, TLS, a self-hosted wiki to document everything. Three environments. Proper separation of concerns. I was designing an enterprise-grade setup for a small family.\nNothing was actually running yet.\nProject # The hardware arrived. Wrong case — the first lesson in the gap between specification and reality. Ubuntu installation followed, with its own surprises. NVMe boot on a Pi 5 is not as straightforward as it sounds. Partitioning, initramfs, chroot — problems I hadn\u0026rsquo;t anticipated, solved one by one. It brought back memories of teenage evenings spent deep in the Windows boot menu, staring at blue screens of death, repartitioning drives, and wondering whether the machine would ever start again. Some things don\u0026rsquo;t change.\nThen something unexpected happened: it just worked. SSH hardening. Firewall. Fail2Ban. BorgBackup. In a professional context, getting these things properly configured across a large organisation is a multi-year programme with consultants and compliance frameworks and steering committees. Here, on a Saturday afternoon, it was done. Tested. Backed up.\nI found myself asking a question I\u0026rsquo;ve asked many times in boardrooms, but never quite like this: why is it so hard to get the basics right at scale, when the basics themselves are not that hard?\nThe server got warm. I checked the temperature. I learned what Docker actually does, not just what the diagrams say it does. Phase 0 was closed.\n","date":"12 April 2026","externalUrl":null,"permalink":"/notes/starting-before-youre-ready/","section":"Notes","summary":"On buying hardware before you’re ready, over-documenting before a single cable is connected, and the unexpected satisfaction of getting the basics right on a Saturday afternoon.","title":"Starting before you're ready","type":"notes"},{"content":"","date":"12 April 2026","externalUrl":null,"permalink":"/tags/ubuntu-server/","section":"Tags","summary":"","title":"Ubuntu-Server","type":"tags"},{"content":"","date":"1 April 2026","externalUrl":null,"permalink":"/tags/big-tech/","section":"Tags","summary":"","title":"Big-Tech","type":"tags"},{"content":"","date":"1 April 2026","externalUrl":null,"permalink":"/tags/open-source/","section":"Tags","summary":"","title":"Open-Source","type":"tags"},{"content":"","date":"1 April 2026","externalUrl":null,"permalink":"/tags/privacy/","section":"Tags","summary":"","title":"Privacy","type":"tags"},{"content":" Why # I used to build computers. In my teens, I spent my hard-earned paperboy money and weekends selecting components, assembling hardware, and troubleshooting driver conflicts. There was something satisfying about understanding the machine from the ground up — every part chosen deliberately, every problem yours to solve. My first real smartphone had a custom ROM installed within the week.\nThen life happened. A happy family. A career in IT advisory and management. Less time for real technical work and skill building, more convenience. I handed my digital life — and that of my family — to Big Tech, a growing list of vendor-locked smart devices, and subscriptions I stopped questioning. For a long time, that was fine. It only ached a little.\nA few years ago I started noticing the cracks. Not dramatic failures — just a slow accumulation of things that felt wrong. Photos I couldn\u0026rsquo;t export cleanly. Documents locked in formats I didn\u0026rsquo;t choose. Services designed to keep you in, not let you out. Terms that changed, prices that rose, platforms that quietly disappeared. A growing sense that I was a tenant in my own digital life, paying rent to landlords I\u0026rsquo;d never chosen.\nMy sense of privacy became more important too. Every device around me was collecting data on my every movement. I knew, but didn\u0026rsquo;t act. Somewhere out there, a detailed digital avatar of me exists — available to parties I\u0026rsquo;ve never met, for purposes I\u0026rsquo;ve never agreed to. I know for a fact that I don\u0026rsquo;t own it.\nThen we lost close family in the generation before us. I experienced firsthand what impact an undocumented and non-transferable digital legacy can have on the people left behind. Suddenly the question of continuity felt real. What happens to our family\u0026rsquo;s photos, documents, and memories if a company shuts down — or if I\u0026rsquo;m no longer around to manage it? Who holds the keys?\nEverything added up. It was time for a real change.\nThe broader shift in the world has changed the European digital climate too. New windows of opportunity have opened up: companies with privacy as a genuine value proposition, affordable VPS infrastructure for consumers, open source products of growing quality, and — more importantly — strong communities behind them.\nThese shifts made something possible that wasn\u0026rsquo;t before. But possibility alone doesn\u0026rsquo;t build anything. I also needed principles to build on.\nOpen formats — because data should outlast the software that created it. Privacy by design — because privacy isn\u0026rsquo;t a feature you add later, it\u0026rsquo;s a decision you make at the start. Security by design — because you don\u0026rsquo;t bolt on security after the fact. Archiving by design — because digital continuity for your family begins with how you store data, not with how you search for it years later when something goes wrong.\nThese were things I believed in professionally but rarely got to apply. Here, they are simply how I build.\nThere\u0026rsquo;s a professional angle as well. In my professional life I advise and manage IT organisations with thousands of employees, millions of automated transactions, and strict compliance requirements. Every project demands full teams: decision boards, enterprise architects, developers of all kinds, infrastructure and security specialists, and layers of stakeholders. Projects always struggle to fit the bigger picture. There is little feedback loop between strategy, architecture, and implementation. Organisations are usually too large to close those gaps.\nHomeStack is my attempt to do what large organisations rarely manage: build something where strategy, architecture, and implementation are genuinely aligned — where every decision traces back to a clear purpose, and where the person who sets the vision is also the one who writes the code, configures the infrastructure, and lives with the consequences.\nAI tools have made this possible in a way it wasn\u0026rsquo;t before. Not just by making me faster, but by giving me access to the depth of knowledge that a full professional IT team would bring — architecture review, security analysis, documentation, troubleshooting — available when I need it, at the pace of a solo builder. What organisations spend millions trying to coordinate, I can now do for my family on a Sunday afternoon.\nSo I started building again. My first project build is HomeStack — a self-managed home infrastructure running on a Raspberry Pi 5. It replaces multi-cloud storage and introduces photo and file storage, a family wiki, financial dashboards, a shared password vault, and more — with open source software, on hardware I own, with some European VPS infrastructure in between, backed up to storage I control.\nMy partner doesn\u0026rsquo;t use a Linux terminal. My daughter is mobile only by birth — though I am teaching her to use a mouse. Our digital life needs to work for them, not just for me. HomeStack isn\u0026rsquo;t a personal project that happens to serve a family — it\u0026rsquo;s a family project that happens to be built by one person, with continuity and control as the core design principle. My family should be able to access their data regardless of what any tech company decides to do next — and ideally, regardless of what happens to me. Every architectural decision is tested against one question: will this still work when I\u0026rsquo;m not in the room?\nThese notes are where I think out loud. Not tutorials. Not polished guides. Just honest documentation of what I built, why I built it, and what I learned — and occasionally got wrong — along the way.\n","date":"1 April 2026","externalUrl":null,"permalink":"/notes/why-i-built-a-server/","section":"Notes","summary":"On digital sovereignty, family continuity, and why I started building again after years of handing my digital life to Big Tech.","title":"Why I built a server","type":"notes"}]