Media
Plex and Jellyfin over the same library, with Sonarr, Radarr and Lidarr doing acquisition, SABnzbd fetching, and a request front-end so nobody has to ask me for anything.
One server, one laptop, and a repository of Ansible that keeps both of them honest. This is what I run for myself — partly because I like owning my own data, and partly because twenty years of doing this professionally left me unable to stop.
Everything below is what I actually run. Where something is aging, mismatched, or a compromise I have made on purpose, I have said so. The interesting part of a homelab is rarely the parts list.
A single tower named memory-alpha, which replaced a predecessor called deep-thought. Hostnames here come from science fiction and always have.
Two of those entries are scar tissue. The HBA replaced a cheap ASMedia SATA card with two dead ports, one of which faulted every drive attached to it and cost me two months of running a pool degraded while I blamed the wrong component. The power supply replaced a 500 W unit with too few SATA leads, which had forced a nest of splitters and the brown-outs that came with them. Both were false economies.
The operating system is disposable on purpose. Nothing irreplaceable lives on the root filesystem, so a total loss of the OS disk means a rebuild and a converge.
Everything that matters is on ZFS, in three pools:
Mirrors throughout, never RAIDZ. Mirrors resilver faster and give better IOPS for a pool serving containers and a database, but the reason that actually decides it is growth: I can grow a pool two drives at a time. On a household budget, incremental beats efficient.
Every drive in the primary pools is CMR. The backup pool's larger mirror is SMR, which I took on knowingly — shingled drives stall for minutes during garbage collection and would be unacceptable anywhere in the write path, but a replication target writes in bursts and idles between them. The home dataset is ZFS-native-encrypted. That is what makes the off-site copy safe to keep.
The oldest drives in the array have around 70,000 powered-on hours, roughly eight years. They're all SMART-clean today. They won't be forever, and they were bought as a batch, so they will age out together.
Forty-one containers, which resolve to about twenty actual services once you discount the databases and cache sidecars each one drags along. Traefik sits in front of everything and handles certificates automatically, so adding a service is a config change and nothing more.
Plex and Jellyfin over the same library, with Sonarr, Radarr and Lidarr doing acquisition, SABnzbd fetching, and a request front-end so nobody has to ask me for anything.
Paperless for everything that arrives on paper, SiYuan as a block-based wiki, and a self-hosted library for ebooks, comics and the scanned manuals that no metadata service has ever heard of.
Nextcloud for file sync and tasks, a genealogy server, a personal-finance app, and an RSS reader that is the last piece of the pre-algorithmic web I refuse to give up.
Vaultwarden, a WireGuard endpoint with split DNS, synced shell history, a dashboard, and Watchtower keeping images current. Portainer for the times I would rather click around than type.
I don't publish the URLs. Nothing is exposed unless it needs to be, and the management interfaces sit behind the VPN. A public list of what someone self-hosts is only useful to the wrong people.
A ThinkPad P14s running Fedora Workstation, 58 GB of RAM, and a single NVMe carrying btrfs
on LUKS with compress=zstd:1. Snapshots hourly and daily via btrbk,
which is also what the backup job ships. Incus for local containers, on a btrfs subvolume so
clones are copy-on-write and instant.
btrfs is here for a reason, and it has charged me for it. It has cost me a month of intermittent thirty-second desktop freezes caused by transaction-commit stalls, which I eventually traced to background updates landing a ten-gigabyte write burst on resume. I stayed on it anyway, because snapshots, compression and cheap container clones are worth more to me than the occasional stall, and because there is no in-place conversion out of it — migrating means backing up, reformatting and restoring.
One Ansible repository does two jobs from one set of roles: bring a fresh macOS or Linux desktop up after an OS install, and provision headless boxes and VMs. Everything is pushed from the workstation, the only machine here holding secrets. It has run since December 2020 and has absorbed a separate homelab repo along the way.
git clone https://codeberg.org/bradfrank/dotfiles.git ~/dotfiles
cd ~/dotfiles && ./setup
Secrets come from 1Password at the point of use, never from disk. Decisions that were actually contested get written up as architecture decision records, so that when I come back to this in two years I can see why the losing option lost.
The rule I keep relearning: once a file is managed, editing it on the host isn't a shortcut. It's a change with a delayed-action deletion attached, and the next converge will quietly discard it at a moment unrelated to anything you were doing.
A real 3-2-1, because a backup you have never restored from is only a rumour.
Encrypted datasets go off-site as raw sends, so the remote holds ciphertext and has never had the key. That only holds if you never load the key on the far end, ever, for any reason.
The local backup pool is set to failmode=continue. That is a direct lesson: when
its predecessor enclosure died, a scrub against a pool with no disks held a global lock for
thirty-four days and took the whole host with it. Returning errors to callers beats blocking them
forever.
Boring technology, chosen once and left alone. Reference disks by stable ID and never by
/dev/sdX. Prefer the distribution's package over a vendor's installer. Let backups
pull rather than push. Keep the monitoring quiet enough that an alert still means something,
because an alarm that fires daily for eight months has trained you to ignore the one channel that
matters.
And write it down — including the parts you got wrong, with the date you were wrong on. I have got more out of that than out of any single fix in it.