● active2021

Homelab

What started as a gaming desktop running Plex has grown into a two-machine homelab with a full AI stack, self-hosted CI/CD, and more services than I care to admit.

UbuntuDockerKomodoGiteaSWAGAutheliaGrafanaLokiInfluxDBOllamaLibreChatPiHoleWireguardZFS

highlights

  • Two physical machines — mimir (main workloads) and heimdall (dedicated DNS)
  • RTX 3080 Ti powers Whisper, Ollama (small coding models), Plex transcoding, and Frigate — LibreChat routes general-purpose chat to external APIs
  • 96TB raw storage in ZFS RAIDZ2 across 6× 16TB IronWolf Pro drives on mimir
  • Gitea Actions CI/CD builds Docker images and triggers Komodo deploys via webhook
  • Monitoring pipeline — Promtail → Loki → Grafana and Telegraf → InfluxDB with SMART and GPU metrics

Overview

Started in summer 2021 by converting my old gaming desktop into an Ubuntu server. The real reasons were Plex — Netflix was getting expensive — and Home Assistant, because cloud-based smart home platforms were too slow and too dependent on someone else’s uptime. Everything else followed from there. In October 2024 everything migrated to a dedicated build (mimir) and the hobby became infrastructure.

Homelab History

  1. 2021Gaming desktop → Ubuntu server · Docker, Plex, HomeKit via Homebridge, Transmission
  2. 2022SWAG reverse proxy + Authelia 2FA · PiHole DNS · Wireguard VPN · two hardware incidents
  3. 2023Full monitoring stack — Loki, Grafana, InfluxDB, Telegraf with SMART + GPU metrics · Samba NFS
  4. 2024Dedicated mimir build · AMD Ryzen 9 7900 · 64GB RAM · RTX 3080 Ti · 6× 16TB ZFS RAIDZ2 · AI stack

Stack

Two physical machines: mimir (AMD Ryzen 9 7900, 64GB RAM, RTX 3080 Ti — main workloads, ZFS RAIDZ2 across 6× 16TB IronWolf Pro) and heimdall (dedicated DNS, runs PiHole).

Almost everything runs as Docker containers managed by Komodo. The exception is the bootstrap stack — SWAG, Authelia, Gitea, and Komodo itself — which is started manually to avoid a circular dependency: Komodo can’t manage the thing that starts Komodo.

SWAG handles reverse proxying and TLS termination. Authelia sits in front of everything that doesn’t need to be public, providing 2FA. LAN-only services are accessible over Wireguard VPN.

CI/CD

All personal projects are self-hosted on Gitea and deployed through a pipeline I own end to end: push to main, Gitea Actions runs CI (lint, type check, build), builds a Docker image, pushes it to the internal registry, then fires a webhook to Komodo which pulls and redeploys the container.

Monitoring

Two pipelines feed Grafana dashboards:

  • Promtail → Loki → Grafana — log aggregation from containers, SWAG/Nginx access logs, and Authelia
  • Telegraf → InfluxDB → Grafana — system metrics, disk SMART data, and GPU stats via nvidia-smi

PiHole query stats and network metrics from an Omada exporter also land in Grafana. Uptime Kuma handles service availability checks — Grafana pulls the up/down status and owns all alerting, routing notifications through ntfy.

AI Stack

The RTX 3080 Ti handles the workloads it’s actually suited for — Ollama for local inference on smaller coding models, Whisper for GPU-accelerated speech-to-text, Frigate object detection. For general-purpose chat, LibreChat routes to external APIs; the card isn’t big enough to run anything useful there.

War Stories

The Nvidia Incident (December 2022)

Tried to add hardware acceleration for Frigate NVR. Installing Nvidia drivers broke the kernel badly enough that the machine wouldn’t boot. Attempts to repair from an older kernel entry failed — eventually gave up and reinstalled Ubuntu from a USB drive.

The main data drive was still NTFS from its previous life as a Windows gaming PC. After the reinstall, testdisk couldn’t find a readable partition. No dice. Years of docker-compose config, media metadata — gone.

Some config survived on the boot SSD’s SSH home directory and in the version-controlled home-server repo. That was the last time anything important lived on an NTFS drive.

The PiHole Chicken-and-Egg (November 2022)

Disabled systemd-resolved to free up port 53 for PiHole. Worked fine until PiHole wasn’t running — at which point the server had no DNS and couldn’t resolve anything, including the addresses it needed to pull the PiHole container. The fix was moving DNS off the main server entirely, which eventually motivated splitting heimdall out as a dedicated DNS node.

learnings

  • Reformatting data drives isn't optional when converting a machine to Linux — NTFS drives that "just work" can become unreadable after a reinstall
  • The bootstrap paradox is real — some things (reverse proxy, auth, Gitea, Komodo) have to start before the orchestrator can manage them, so you need a hand-started stack that lives outside the system it controls
  • Monitoring is most valuable right before you need it — SMART alerts surfaced degrading drives before they failed
(END)q back