└─$ fastfetch
This is the infrastructure behind shephard.cc — a homelab that has grown from a stack of spare parts into two routed networks, a domain-joined family device fleet, highly-available DNS, full observability, and backups that power their own storage on and off. Everything below is running right now.
└─$ ip route show
Network & edge
Two routed segments, three router platforms, no open ports.
CGNAT lands on the UniFi gateway, which runs the primary
10.0.0.0/16 — around thirty devices migrated off an old
flat /24 — and directly serves the core boxes: the Debian server, the
Frigate NVR, Home Assistant, and the house WiFi. From there, a Netgear
GS316EP breaks the network out to a FortiGate 60D,
which fronts its own NATed 192.168.1.0/24.
# topology
╔═════════════════════════╗
║ internet · CGNAT ║
╚════════════╤════════════╝
│
┌────────────┴────────────┐
│ unifi gateway │
│ 10.0.0.0/16 │
└──┬──────────────────────┘
├─ the-shephards · debian · 10.0.1.1 · raid 1 · restic · docker
├─ home assistant · smart-home hub
├─ wifi · phones + family devices
│
└─ netgear gs316ep
│ wan1 · 10.0.1.6
┌─────┴───────────────────┐
│ fortigate 60d │
│ 192.168.1.0/24 │
└──┬──────────────────────┘
├─ arch desktop · jetkvm attached
├─ raspberry pi · pi-hole (ha node)
│
└─ windows server 2025 · hyper-v + ad ds
├─ media vm · debian · isolated vpn
├─ pi-hole vm · ha pair with the pi
├─ local-ai vm
├─ opnsense vm · sandbox network
└─ test vms · whatever's next
Behind the FortiGate live the Arch desktop, the physical half of the Pi-hole pair, and Windows Server 2025 — domain controller for the family's devices and Hyper-V host for the VM farm: a VPN-isolated Debian VM for legally sourced media, a Pi-hole VM, RHEL, a local-AI box, test VMs, and OPNsense, which runs its own sandbox network for routing experiments on a quad-port Intel i350-T4.
Because everything sits behind CGNAT, nothing is port-forwarded. Remote access is a Tailscale mesh — the Debian server advertises both subnets, and Tailscale runs in the background on the phone so ad blocking follows it out of the house — plus a JetKVM on the main desktop for true hardware-level access from any browser.
└─$ cat /etc/hosts
Compute
Real metal where it matters, virtual machines for everything else.
the-shephards
Debian · 10.0.1.1
The workhorse. mdadm RAID 1 storage at /mnt/Raid_1,
Timeshift btrfs snapshots, systemd timers for backups and NAS
power, and Tailscale subnet routing for both networks. This is the
station the household relies most heavily on. Serving up media
with Jellyfin, pictures with Immich, surveillance with Frigate NVR
makes this machine's uptime important for the family to enjoy
services they would normally pay a cloud provider for.
windows-server
Windows Server 2025 · Hyper-V + AD DS
Domain controller for the family's laptops and Windows devices, Hyper-V host for the whole VM farm, and home of the restic REST server for backups.
raspberry-pi(s)
bare metal · Pi-hole + Home Assistant
2 Raspberry Pis perform mission-critical tasks for the household. One runs Pi-hole, which is the household DNS server and ad-blocker. The other is running Home Assistant OS which makes smart home devices simple enough for the kids to use.
└─$ dig +short shephard.cc
DNS, in layers
The part of the lab that must never go down — so it can't depend on any one box.
Ad-blocking and internal resolution run on a
keepalived-managed HA Pi-hole pair: one virtual, on
the Windows Server farm, and one physical, on a Raspberry Pi — with
nebula-sync keeping the Pi-hole v6 configuration
identical between them. Either half of the lab can fall over
completely and the house keeps resolving.
DNS records are added by a one-shot setdns script that
hits the UniFi and Pi-hole v6 APIs simultaneously which makes adding
new DNS records as simple as typing the name you want it to resolve.
Tailscale is set up to run quietly in the background on the phone, so the Pi-holes keep filtering ads even away from home.
└─$ net ads info
Identity — two Active Directories
One in production, one being rebuilt the hard way.
The production directory is Active Directory Domain Services on Windows Server 2025: the family's laptops and Windows devices are domain-joined, with real accounts and real policy — enterprise identity, scaled down to a household.
Running alongside it as a test project is a
Samba AD domain, ad.shephard.cc —
Although not in use, it serves as a great learning tool for AD
management through Linux and offers full-featured Active
Directory/Group Policy that can be managed from a Windows device.
└─$ ls
Services
Fronted by Nginx Proxy Manager with a wildcard
*.shephard.cc certificate via Cloudflare DNS — every
service gets a real name and real TLS.
The supporting cast — mysql, a letsencrypt store, and the data volumes
— rounds out the compose files. Docker's default address pools are
pinned to 10.20.0.0/16 in daemon.json —
learned the hard way after a container network landed on top of the
FortiGate segment.
└─$ curl -s prometheus:9090/api/v1/targets | jq '.data.activeTargets | length'
Observability & security
If it isn't graphed, alerted, and audited, it isn't done.
Prometheus + Grafana scrape the whole fleet:
node_exporter on the Linux boxes,
windows_exporter on the server,
pihole-exporter for DNS, and Home Assistant's built-in
Prometheus integration for the smart-home side — all pulled into a
custom-built dashboard.
# grafana → prometheus scrape jobs up arch-desktop up debian-server up windows-server up pihole up homeassistant up prometheus
On the security side, a Wazuh SIEM runs as a
single-node Docker Compose stack behind NPM, with agents on the Debian
server and on Arch — the latter built from source, because Arch — and
tuned ossec.conf rules to keep the false positives quiet.
Scrutiny watches SMART data on the storage server, so
disks get replaced before they get interesting.
└─$ systemctl list-timers | grep -i nas
Backups: restic + a NAS that turns itself off
The favorite piece of engineering in the lab — 3-2-1 with a power bill in mind.
Backups run on restic from the Debian server to a restic REST server on Windows Server 2025. The twist: the repository lives on a drive that is powered off outside the backup window. A smart plug controlled through Home Assistant's REST API brings the storage up on schedule, and systemd timers orchestrate the whole nightly cycle:
19:00 NAS_Power_On.timer → Home Assistant flips the smart plug; disks spin up 19:0x restic-backup → pre-flight check against rest-server /config, power-cycle retry logic if the target is absent 19:xx uptime-kuma push → success heartbeat (silence = an alert) 02:00 NAS_Power_Off.timer → storage goes dark until tomorrow
On the Windows side, the REST server runs as an NSSM service launched
entirely from C:\, set to manual start so a boot-time
scheduled task owns the choreography: power the NAS on, wait for the
repo drive to appear, start the service, power the NAS back off.
Testing confirmed rest-server keeps running happily after
its storage disappears underneath it — the drive only has to exist at
process start. A PowerShell watchdog watches service events
(7034/7036) and pushes to Uptime Kuma if anything falls over. Local
safety nets round it out: Timeshift btrfs snapshots on Debian and
mdadm RAID 1 under the primary data.
└─$ esphome logs salt-monitor.yaml
Smart home & hardware
Where the lab leaves the rack.
water softener monitor
ESP32-S3 N16R8 · ESPHome
Measures the salt level in the water softener and reports into Home Assistant — Alert is sent as a notification to phone.
leak-response pump
Arduino
An automated water pump that switches on the moment water is detected — flood control that doesn't wait for a human to notice.
wled everywhere
WLED · ESP32s + Raspberry Pis
Several strip lights around the house driven by ESP32s and Raspberry Pis — including a custom Python script to control lights for a mini rack.
lighting logic
motion sensors · smart buttons
Stair lights come on with motion and time out after a couple of minutes of stillness; programmable push buttons act as dimmer and power toggle for lights too awkward to reach.
└─$ hyprctl monitors
The workstation
The desk the lab is run from.
Daily driver is Arch Linux with Hyprland, topped by a custom QuickShell bar written in QML — deep purple, JetBrains Mono, dynamic app launchers driven from a JSON config. (The bar across the top of this page is its web impersonation.) The stack underneath: Kitty, Neovim, zsh with oh-my-zsh, and a cliphist / wl-clipboard / rofi-wayland clipboard pipeline.
Three monitors are input-switched with ddcutil, so one
keystroke steals a screen from another machine. A
JetKVM sits on the box for true hardware-level access
— BIOS and all — from any browser through JetKVM cloud. For downtime
there's a Sunshine → Moonlight streaming path to the living-room TV.
└─$ git status
On the bench
A homelab is never finished; it's just between incidents.
On branch homelab Changes in progress: modified: identity/samba-ad # ad.shephard.cc — parallel test domain modified: automation/ansible # bootstrap plays under evaluation modified: network/opnsense-sandbox # isolated routing experiments Untracked files: new: labs/rhel/kickstart # automated provisioning practice new: vms/local-ai # model serving experiments nothing is ever fully committed in a homelab