Beyond Perfection: How a Developer Built a Resilient Self-Hosting Stack with NixOS and Tailscale
Share this article
For many developers, self-hosting begins as a quest for control and privacy but often devolves into an endless cycle of over-engineering. Matthew Booe, in a detailed blog post on CodeCaptured.com, chronicles his shift from perfectionism to pragmatism. By defining clear goals—like data ownership, security, and family-friendly usability—he built a robust setup that has run flawlessly for six months. His story isn't just about tools; it's a testament to how disciplined constraints foster real-world resilience in personal infrastructure.
The Core Philosophy: Prioritizing Practicality
Booe's journey started with self-reflection. He abandoned sprawling Docker and Ansible experiments in favor of a focused approach centered on:
- Data Control: Ensuring personal information isn't hostage to corporate decisions (e.g., avoiding 'Darth Vader' shutdowns).
- Security First: Minimizing public exposure of services.
- Usability: Making the system accessible to non-technical family and friends.
Crucially, he set 'anti-requirements': no complex orchestration (e.g., Kubernetes) or high-cost hardware. This kept the stack lean and maintainable.
The Tech Stack: NixOS, ZFS, and Tailscale
Booe’s setup leverages battle-tested open-source tools, chosen for their synergy:
- NixOS: As the foundation, it uses declarative configuration for everything from firewall rules to services. This enables reproducible setups and easy rollbacks. For instance, enabling SilverBullet (a note-taking app) requires just a few lines of code:
services.silverbullet = {
enable = true;
port = 3000;
dataDir = "/var/lib/silverbullet";
};
All configurations live in a Git repo, allowing version control and reuse across machines.
ZFS: For data integrity, Booe uses ZFS in a RAIDZ2 pool with four 10TB drives, ensuring two-drive fault tolerance. Snapshots provide quick recovery from mishaps—like accidental SSH lockouts.
Tailscale & Headscale: To avoid public exposure, Tailscale’s mesh VPN connects devices securely. Booe self-hosts the backend with Headscale for independence from vendor changes. As he notes:
"Tailscale improves security but adds friction for users—everyone must install its client. It’s the trade-off for keeping services off the public internet."
Authentication and Architecture: Solving the Hard Problems
Booe integrated Authelia (for OpenID Connect/OAuth) and LLDAP (for LDAP-backed user management) to handle single sign-on. This lightweight duo secures services behind Nginx reverse proxies, though setup was complex:
- For services lacking OIDC support, Nginx routes requests through Authelia.
- An admin account bypasses Authelia per service for emergency access—a critical failsafe.
His architecture, themed around Star Wars planets, reflects thoughtful segmentation:
- Taris (VPS): Hosts public-facing essentials like Headscale, Authelia, and a blog.
- Kuat (Main Server): Runs TrueNAS-managed NixOS VMs (Bespin for services, Alderaan for testing).
- Tython & Coruscant: Appliance-like devices for Home Assistant and Matrix/Element, ensuring critical services stay isolated.
Key Challenges and Ingenious Fixes
Booe tackled common pain points with elegant solutions:
- User-Friendly Access: Flame provides a simple 'start page' dashboard for bookmarking services, easing navigation for non-technical users.
- VPN Conflicts: To resolve Android/Windows VPN limitations, he combined Tailscale exit nodes with Gluetun (for ProtonVPN), routing traffic through containerized endpoints. His Nix config optimizes this, though battery drain and latency remain trade-offs.
- DNS & SSL: Internal services use an
internal.subdomain with DNS-01 Let’s Encrypt validation, while public services rely on HTTP-01—streamlining certificate management.
Why This Matters for Developers
Booe’s setup underscores a broader trend: developers are reclaiming autonomy from cloud giants. By prioritizing 'good enough,' he achieved a maintainable system that balances security, cost, and usability. For engineers, it’s a blueprint emphasizing:
- Infrastructure as Code: NixOS ensures consistency and disaster recovery.
- Vendor Independence: Self-hosting core services like authentication and storage mitigates risks of third-party outages or policy shifts.
- Practical Security: Layered defenses (ZFS, Tailscale, Authelia) reduce attack surfaces without overcomplicating.
Looking ahead, Booe eyes incremental improvements—like exploring Syncthing for backups or refining monitoring. His journey proves that in self-hosting, progress beats perfection, empowering developers to build resilient, personal tech ecosystems one solved problem at a time. For deeper insights, explore his full post and curated resources on CodeCaptured.com.