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.
Making 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.
Phase 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.
Family#
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’s perspective, nothing changed. From the infrastructure’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.
The 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.
The 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.
MFA 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.
Tech#
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.
CrowdSec 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’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.
Alerting 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.
Resource 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.
Distroless 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’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.
The 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’s native SSH support. No API, no rate limiting, no deprecation risk. The 3-2-1 backup strategy was finally complete.
Project#
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.
One 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.
The 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.
One research thread ran alongside the technical work without producing any immediate changes.
Cloudflare 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.
The 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.
The 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.
The 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.
The 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.