homelab

x 0.95 · purpose 0.15 · t 1 yr · scope 0.90

from 2025-09

Linux · virtualization · Docker · PKI

The homelab began as a way to learn Linux by using it for something real. It now runs the services I rely on, this site among them. The interesting part is its shape: a network cut into zones by trust, compute kept apart from storage, and every workload given the isolation it needs and no more.

vlans
7
hypervisors + nas
3 + 1
vms · lxcs
7 · 16

zones, not a flat network

10 zones (7 of them VLANs) against each other, from the router's rules: 28 of 90 ordered pairs are open, each for named purposes; every other pair is denied by default. internet and storage may start nothing. Left and right arrows read one zone at a time.

data
frommay reachforrulesopened to
off-site relayserviceslogs + metrics, web2named hosts
dmz entryinternetdns, web2named hosts
dmz entryoff-site relaytunnel2named hosts
dmz entrydmz bridgeapi1named hosts
dmz entrydmz webgame, the site2named hosts
dmz entryserviceslogs + metrics, app2named hosts
dmz bridgeinternetdns1named hosts
dmz bridgeserviceslogs + metrics, app, web4named hosts
dmz webinternetdns, web3named hosts
dmz webserviceslogs + metrics, web2named hosts
clientsinternetanything1the whole zone
clientsdmz entryssh1named hosts
clientsdmz bridgessh1named hosts
clientsdmz webssh1named hosts
clientsservicesssh, web2the whole zone
clientsmanagementweb1named hosts
servicesinternetweb, tunnel, mail, file sync9the whole zone
servicesoff-site relaytunnel1named hosts
servicesdmz entryssh1named hosts
servicesdmz webfile sync, ssh2named hosts
servicesmanagementssh1named hosts
servicesstoragefile shares2the whole zone
managementinternetoff-site copy, tunnel, mail, web4named hosts
managementservicesalerts, check-ins, logs + metrics, backups5the whole zone
managementstoragefile shares1named hosts
admin vpnclientsssh1named hosts
admin vpnservicesssh, web2named hosts
admin vpnmanagementadmin1named hosts
every zone against every other: what may start a connection to what, and for what.

Seven VLANs and a VPN overlay divide the network by trust. Three DMZ zones hold everything the internet can touch: an entry that ends TLS, a bridge that proxies a few narrow APIs inward, and a web zone for public apps. Clients, the phones and laptops, reach the internal reverse proxy and the internet, and admin devices a little more. Services hold everything internal. Management holds the hypervisors and the NAS, and admin devices reach it over the VPN. Storage has no gateway at all.

Between zones the default is deny, and every deny is logged. What is open is opened for a purpose, and almost always from named hosts rather than a whole zone. Nothing on the internet may start a connection in. Names and logins follow the same lines: each zone resolves only the names it needs, and a machine accepts logins only for its own zone.

a request for this page

A request for this page: visitor to cache (https), cache to relay (https, on a cache miss), relay to entry (the same stream, through the tunnel), entry to web (the site port only); the page returns the same way. visitor: asks for this page. cdn cache: answers from cache when it can, even when home is down. off-site relay: passes the encrypted stream on by name; holds no keys and no state. dmz entry: keeps the tunnel to the relay open (it dials out); tls ends here; proxies to the site. dmz web: a read-only container serves the built files. From inside, observability pushes hourly telemetry into the web zone; the web zone may send only logs + metrics and web back. Left and right arrows step a pulse through the path.

data
hopwherewhat it does
visitorout thereasks for this page
cdn cacheout thereanswers from cache when it can, even when home is down
off-site relayoff-sitepasses the encrypted stream on by name; holds no keys and no state
dmz entryhome, dmzkeeps the tunnel to the relay open (it dials out); tls ends here; proxies to the site
dmz webhome, dmza read-only container serves the built files
observabilityhome, serviceshourly: telemetry, pushed in with a key that can only write to one directory
dmz web → the labhomelogs + metrics, web; nothing else
out there, off-site, then home: each hop does one thing and holds nothing it doesn't need.

A cache in front answers most requests, and keeps answering when home is down. On a miss the request goes to a small rented server off-site, which passes the encrypted stream on by name without holding any keys. It reaches home through a tunnel that the DMZ entry keeps open from the inside: the entry dials out, so the router never has to let anything in. TLS ends at the entry, which may reach the web zone only on the ports its apps serve. There a read-only container serves the built files.

The web zone can’t start much either. Into the lab it may only send its logs and metrics and fetch code through the internal proxy. The numbers on the front page travel the other way: once an hour the observability side pushes them in, with a key that can only write to one directory.

compute here, storage there

3 hypervisors and a NAS, one cluster. hypervisor a (general): 6 guests; hypervisor b (media + dmz): 4 guests; hypervisor c (always-on infra): 13 guests; the NAS runs none and keeps the bulk data and the replicas. 23 guests: 7 VMs, 16 LXCs. An LXC is the default; a VM when the guest needs its own kernel: everything in the DMZ, a device passed through, a host for many container stacks. Every member sits on the trunk (every VLAN) and on a storage network of its own with no gateway. Copies: 06:00, replicas, pulled by the nas; 06:30, a copy, pulled; 23:00–06:00, off-site copy, sent; sundays 03:00, cold copy, pulled. Left and right arrows step through the guests.

data
machineguestzonewhyworkload
hypervisor avmdmz bridgein the dmz: its own kernelapi bridge
hypervisor avmserviceshosts many container stacksapps + files
hypervisor alxcservicesthe defaultapps + files
hypervisor alxcservicesthe defaultgit + ci
hypervisor alxcservicesthe defaultgit + ci
hypervisor alxcservicesthe defaultgit + ci
hypervisor bvmdmz entryin the dmz: its own kernelpublic entry
hypervisor bvmdmz webin the dmz: its own kernelpublic apps (this site)
hypervisor bvmdmz webin the dmz: its own kernelpublic apps
hypervisor bvmservicesa device passed throughmedia
hypervisor cvmserviceshosts many container stacksobservability
hypervisor clxcservicesthe defaultaccess + identity
hypervisor clxcservicesthe defaultaccess + identity
hypervisor clxcservicesthe defaultaccess + identity
hypervisor clxcservicesthe defaultaccess + identity
hypervisor clxcservicesthe defaultaccess + identity
hypervisor clxcservicesthe defaultaccess + identity
hypervisor clxcservicesthe defaultaccess + identity
hypervisor clxcservicesthe defaultaccess + identity
hypervisor clxcservicesthe defaultapps + files
hypervisor clxcservicesthe defaultbackups
hypervisor clxcservicesthe defaultbackups
hypervisor clxcservicesthe defaultobservability
nas——bulk storage; pool: bulk + replicasno guests
06:00copy—replicas, pulled by the nashypervisor a, hypervisor c → nas
06:30copy—a copy, pullednas → hypervisor b
23:00–06:00copy—off-site copy, sentnas → off-site
sundays 03:00copy—cold copy, pullednas → cold copy device
three hypervisors run every guest; the nas runs none and keeps the copies.

Each hypervisor has a job: one for general workloads, one for media and the DMZ, and one for the always-on infrastructure everything else leans on: access and identity, backups and observability. The NAS runs no guests. It is a member of the cluster but holds no vote, so the three hypervisors make the quorum on their own. Storage traffic has a link and a VLAN of its own. App data lives next to the apps, and copies move toward the NAS, pulled by the side that keeps them, before leaving for off-site and cold storage.

A guest is an LXC by default: light, quick to make, sharing the host’s kernel. It becomes a VM only when it needs a kernel of its own: everything in the DMZ, the guest with a device passed through to it, and the hosts that run many container stacks. That leaves seven VMs and sixteen LXCs.

operated, not just installed

checks up
99.97%
storage errors
0
alert rules
26

The copy chain on a 24-hour day: daily 05:00, snapshots (kept 7–14 days (some up to 3 months)); daily 06:00, replicas (kept 30 days / 12 months / 2 years); nightly 23:00–06:00, off-site (kept rolling); sundays 03:00, cold copy (kept rolling). Each copy is pulled by the side that receives it, and every step checks in; a missed check-in raises an alert. Under the day, the alert coverage: 26 rules in 6 groups (silent pipelines, containers, storage health, memory, cpu, clock, ssh logins, tls expiry), an independent watchdog every 2 minutes, and critical alerts to a phone. A real schedule, drawn schematically.

data
whenwhatkept
daily 05:00snapshots of every important dataset7–14 days (some up to 3 months)
daily 06:00replicas pulled to a separate, read-only store30 days / 12 months / 2 years
nightly 23:00–06:00off-site copy of the newest replicas; stops itself at 06:00 and resumes the next nightrolling
sundays 03:00cold copy: a small device wakes itself on a timer, pulls, verifies the data, reports and powers offrolling
always26 alert rules (as of 2026-10-10): silent pipelines (a machine stops sending metrics or logs, a stale data feed, a failed system unit); containers (CPU hog, restart loop, out of memory, log spam); storage health (disks, storage pools, SMART, temperatures); memory, cpu, clock (memory, CPU and clock); ssh logins (failed SSH logins); tls expiry (public TLS certificate expiry)metrics, logs and check history 30 days
every 2 minan independent watchdog checks the monitoring itself and alerts directly if it is down; critical alerts also reach my phone—
every copy checks in, so a step that doesn't run gets noticed.

Copies follow a fixed daily rhythm: snapshots at five, read-only replicas pulled at six, an off-site copy that runs overnight and stops itself in the morning, and a weekly cold copy that wakes, verifies and powers back off. Copies at home are pulled by the side that keeps them, so a source can’t change or delete its own backups. Twenty-six alert rules cover the quieter failures, from a machine that stops reporting to a certificate about to expire, and a separate watchdog keeps an eye on the monitoring itself.