Last updated 7/5/2026
I’ve always enjoyed giving a bit of whimsy to my computer names. Recently, I’ve settled on naming them after characters from Patrick Rothfuss’ Kingkiller Chronicles Every machine in my house is named after a character from Patrick Rothfuss’s Kingkiller Chronicle. My main compute node is is elodin, the NAS is alder, the media box is felurian, and the lowly Raspberry Pi that was the original homelab node is kvothe.
The guts of the lab are a 2-node Proxmox cluster with a raspberry pi running as a QDevice to maintain quorum. Elodin is the beefiest box running:
- Intel(R) i7-14700K
- 256 GB RAM
- A sliger 4U case
- 6 TB NVMe
- 40 TB ZFS pool on spinny HDDs
- 2 GPUs (one passed through for Hackintosh, one for remote gaming rig)
Most of the compute runs on elodin as a mix of VMs and LXC containers. My current setup:
- grafana and influx LXCs for dashboarding and alerting
- tailscale LXC for subnet VPN, which allows me to connect via tailscale to the full internal network
- docker LXC for running various docker nodes, sitting on top of portainer
- pocketid LXC for security key login
- home-assistant, running on a raspberry pi with a custom hat for an RF bridge
- audiobookshelf LXC, storing podcasts
- traefik LXC, running network routing
- cloudflared LXC, running the cloudflare daemon for punching Cloudflare tunnels into the network
- ansible LXC for running cluster actions (provisioning nodes/LXCs, etc)
- kilvin, an Ubuntu VM for dev
- various locked down agent boxes for running
claude --dangerously-skip-permissions - auri, a Hackintosh VM
- bast, a Windows VM with full GPU passthrough, connected to via Parsec
- alder, a simple NAS LXC which has ZFS directories mount pointed in and shares them via SMB/NFS
- emby LXC, for serving media (with a dedicated GPU for transcoding)
- openclaw LXC, a locked down openclaw instance
GitOps & Backup
Important config, ansible playbooks, home-assistant definitions and more, are all stored in a monorepo. This also includes portainer stack definitions. This allows me to track changes across the fleet and easily roll them back (either from git or from backup). Not everything important is GitOps’ed; some things (for example, traefik routing) are still local to that node.
Backup is done in 4 passes:
- All VMs/LXCs have their root disk backed up to PBS running on elodin, in a redundant ZFS Pool
- Important proxmox config is written directly to git via ansible, to support GitOps
- The NAS is backed up via restic, encrypted in the cloud
- Proxmox itself is backed up to PBS
Network Layer
Internet
|
Cloudflare (tunnel + Access)
|
UniFi ─── Traefik (*.services.home, TLS)
| |
┌────┴────┬─────────┼───────────┬─────────┐
Elodin Alder Felurian Kvothe Bast
(Proxmox) (NAS) (Emby) (Home Asst.) (gaming VM)
The network runs on top of a Ubiquiti Dream Machine. Internally, nodes are given a .home URL (for example, elodin.home). All traffic to *.services.home is routed to Traefik by the router; traefik then routes these to the appropriate internal service. Separately, Cloudflare DNS router *.internal.336.rocks to Traefik’s private IP (192.168.1.100). This, along with Let’s Encrypt certs set up at the Traefik level allow for https access to internal services through either domain.
A tailscale node exports the full subnet, which allows for VPN access to the entire network.
Cloudflare Tunnels are used for giving limited external access to 3rd parties. These are punched through via a cloudflared LXC.
http:
routers:
today_router:
rule: "Host(`today.services.home`) || Host(`today.internal.336.rocks`)"
service: today
entryPoints: ["websecure"]
tls: {}
services:
today:
loadBalancer:
servers:
- url: "http://docker.home:8787"
serversTransport: insecure
entryPoints:
web:
address: ":80"
http:
redirections:
entryPoint:
to: websecure
scheme: https
permanent: true
websecure:
address: ":443"
http:
tls:
certResolver: cloudflare
domains:
- main: "internal.336.rocks"
sans:
- "*.internal.336.rocks"
providers:
file:
directory: "/etc/traefik/conf"
watch: true
certificatesResolvers:
cloudflare:
acme:
email: myemail@gmail.com
storage: /etc/traefik/acme.json
caServer: https://acme-v02.api.letsencrypt.org/directory # prod (default)
# caServer: https://acme-staging-v02.api.letsencrypt.org/directory # staging
dnsChallenge:
provider: cloudflare
resolvers:
- "1.1.1.1:53"
- "8.8.8.8:53"
delayBeforeCheck: 300
log:
level: INFO
Smart Home
Home Assistant runs on a raspberry pi. All automations and scripts are run via on top of appdaemon (instead of defined in yaml), which makes testing and reasoning about the system much simpler.