The Weekend That Changed Everything
I knew Plex existed. I’d used it casually — point it at a folder, it plays on the TV. Fine.
Then a friend mentioned Sonarr and Radarr. "You tell it what shows you want, it finds them, downloads them, names them, puts them where Plex expects them."
I went down the rabbit hole that weekend. Prowlarr for indexers. Bazarr for subtitles. Overseerr for requests. qBittorrent as the downloader. The *Arr stack, or as I like to call it "The pirate stack" :)) — an entire automated pipeline where the only manual step is "I want to watch this" and maybe you don’t even need to do that much. Just add the shows to the watchlist in Plex and it gets handled.
Six months later, the stack runs on a GTX 1060 in a separate physical machine, mounts media via NFS from a ZFS pool on another node, and serves Plex to two households.
The Architecture (Recap)
Infra Node (Proxmox + ZFS)
└── /tank/media (RAID-Z) ← NFS export
Smart Node (Debian 12 bare metal, GTX 1060)
├── Docker + Portainer
│ ├── qBittorrent → downloads to /mnt/temp (local NVMe)
│ ├── Prowlarr → indexers (public + private)
│ ├── Sonarr → TV automation
│ ├── Radarr → Movie automation
│ ├── Bazarr → Subtitle automation
│ ├── Overseerr → Request portal (me + family)
│ └── Plex → Streaming (GTX 1060 NVENC with Plex Pass)
│
└── NFS mount: /tank/media from Infra Node
Key constraint: The *Arr stack runs on Smart Node. Media library lives on Infra Node’s ZFS. Smart Node mounts /tank/media via NFS. All *Arr writes go over the network.
The Hardlink Dilemma (And Why It Doesn’t Work For Me)
How it should work: qBittorrent downloads to /mnt/temp. Sonarr/Radarr import via hardlink — same inode, zero disk space, instant. File stays in qBittorrent for seeding. Library gets a reference. Everyone wins.
Why it doesn’t work for me: The *Arr stack’s "hardlink" import option requires source and destination on the same filesystem. My setup:
qBittorrent downloads → /mnt/temp (Smart Node's local NVMe)
Library → /tank/media (Infra Node's ZFS, mounted via NFS)
Different filesystems = no hardlinks. The *Arr stack detects this and falls back to copy + delete. Which means:
- Read from NVMe
- Write over NFS to ZFS
- Delete from NVMe
- Double I/O, double time, double wear
The workaround I’d use if I could: Move qBittorrent downloads to a ZFS dataset on Infra Node, mount it on Smart Node. Then hardlinks work. But that means NFS writes during download — which I avoided for reliability.
What I actually do: Copy + delete. Manual cleanup when /mnt/temp fills up. Not elegant. Honest.
What I’d Change
| Thing | Current | Would Change |
|---|---|---|
| Hardlinks | Copy+delete over NFS | Move qBittorrent to ZFS dataset on Infra Node, mount on Smart Node → true hardlinks |
| Deletion | Manual cleanup | Automated: *Arr "delete after import" + qBittorrent "remove on seed ratio" |
| NVMe wear | Downloads + copy = 2x writes | Hardlinks = 1x write |
| NFS reliability | Occasional hiccups | Local ZFS mount (VirtIO-FS) if Smart Node ran Proxmox |
The Honest Summary
The stack works. Automated, reliable, serves two households. Family member requests a show, it appears on Plex. I barely touch it.
The compromises are real:
- No hardlinks = double I/O, manual cleanup
- NFS over network = occasional permission hiccups, latency on library scans
Would I do it again? Yes. The alternative — manually downloading, renaming, organizing, subtitle hunting — is the stone age. The *Arr stack is the kind of automation that makes you wonder how you lived without it.