For years, my home lab ran on a patchwork of port forwards, dynamic DNS, and good intentions. It worked — mostly — but every exposed port was a liability, and I knew it. This is the story of how I tore it all down and rebuilt on a zero-trust foundation.
Why Zero Trust?
The traditional model assumes that anything inside your network is safe. Zero trust flips that entirely: verify everything, trust nothing. Every request is authenticated, every connection is encrypted, and no service is reachable unless explicitly permitted.
For a home lab, this might sound excessive. But consider what's running: Nextcloud with personal files, Vaultwarden with every password, Grafana with full infrastructure telemetry. These are worth protecting.
The threat model for a home lab isn't nation-state actors. It's misconfigured services, leaked credentials, and the slow accumulation of technical debt. — Personal notes, 2025
The Stack
After evaluating several options, I settled on Tailscale for mesh VPN and Nginx Proxy Manager for internal reverse proxying. Here's why:
- Tailscale handles device authentication via your identity provider — no PKI to manage
- WireGuard under the hood means excellent performance with minimal overhead
- NPM provides a clean UI for managing SSL certs and proxy hosts
- The two integrate cleanly: NPM listens on the Tailscale interface only
Installation
Start with Tailscale. On any Debian-based system, it's a single command:
curl -fsSL https://tailscale.com/install.sh | sh
sudo tailscale up --advertise-routes=192.168.1.0/24
The --advertise-routes flag is key — it lets other Tailscale nodes reach
your entire local subnet, not just the device running Tailscale.
Nginx Proxy Manager via Docker
services:
npm:
image: jc21/nginx-proxy-manager:latest
restart: unless-stopped
ports:
- "100.x.x.x:80:80" # Tailscale IP only
- "100.x.x.x:443:443"
- "100.x.x.x:81:81" # Admin UI
volumes:
- ./data:/data
- ./letsencrypt:/etc/letsencrypt
Note the bind to 100.x.x.x — your Tailscale IP. NPM will only
be accessible via the VPN. No public exposure whatsoever.
Results
After migration: zero open ports on the router, all services behind authentication, SSL everywhere courtesy of Let's Encrypt via DNS challenge, and access from any device on the Tailnet — phone, laptop, a friend's machine with a quick invite.
The setup took an afternoon. The peace of mind has been permanent. If you're running any services worth protecting, I can't recommend this approach strongly enough.