Mechanical identity rename across the knowledge base, AGENTS.md, README, the
hermes config example, and homepage services.json. No behavior change; served
aliases on the LLM endpoints change with the deploy of commit 69f87c8.
8.3 KiB
type: reference title: *arr Stack description: The *arr automation stack (Prowlarr, Sonarr, Radarr, Lidarr, Readarr, qBittorrent) on FrankBook-Pro — topology, wiring, auth posture, and gotchas. tags: [arr-stack, prowlarr, sonarr, radarr, lidarr, readarr, qbittorrent, frankbook-pro] timestamp: 2026-09-03T00:00:00Z
*arr Stack
The *arr suite is a collection of automated media management tools for Usenet and BitTorrent. The stack runs on FrankBook-Pro — the Mac mini that fronts this household's downloads — as quadlet units inside its podman machine, not on Dankserver. It provides automatic downloading and library management that Copyparty alone does not cover: quality profile enforcement, series/movie discovery, metadata enrichment, and automated file organization.
The core chain is: Prowlarr (indexer API aggregator) → Sonarr/Radarr/Lidarr/Readarr (media-specific managers) → qBittorrent (download client, sharing the Gluetun WireGuard tunnel netns) → Jellyfin (media server scan → auto-refresh).
Service Overview
| Service | Role | Image | Port | Min RAM |
|---|---|---|---|---|
| Prowlarr | Indexer management | lscr.io/linuxserver/prowlarr:latest |
9696 | 256 MB |
| Radarr | Movie management | lscr.io/linuxserver/radarr:latest |
7878 | 512 MB |
| Sonarr | TV show management | lscr.io/linuxserver/sonarr:latest |
8989 | 512 MB |
| Lidarr | Music management | lscr.io/linuxserver/lidarr:latest |
8686 | 256 MB |
| Readarr | Ebook/audiobook management | lscr.io/linuxserver/readarr:amd64-1.0.980 (pinned — LSIO ships no untagged latest for readarr) |
8787 | 256 MB |
| qBittorrent | Torrent download client | lscr.io/linuxserver/qbittorrent:4.6.7 (pinned; see qBittorrent) |
8080 (published by the gluetun unit) | 512 MB |
Jackett and Whisparr were evaluated as optional extras but never deployed (no unit, no vhost, no live container).
Deployment shape (current)
Each service is a quadlet .container unit in this repo under
frankbook-pro/<svc>/quadlet/, installed inside the podman machine at
/home/core/.config/containers/systemd/<svc>.service by the frankbook-pro
handler in scripts/deploy-remote.sh. Every unit runs with
PUID=0 PGID=0 TZ=America/Los_Angeles UMASK_SET=022, mounts its config root at
/Volumes/COMPLETE/<svc>-data:/config, publishes its API port on the host, and
runs Restart=always with TimeoutStartSec=900.
qBittorrent is special: it shares the Gluetun container's network namespace
(Network=gluetun.container) so torrent egress never touches the residential
IP. A netns-sharer publishes no ports of its own — qB's WebUI (8080) and
BitTorrent port (6881 TCP+UDP) are published on the gluetun unit instead.
Historical design-era compose (retired)
The original design deployed the stack on Dankserver via
dankserver/compose.yaml with /opt/<svc>/config data roots and
TZ=America/New_York. That layout is retired; dankserver/compose.yaml is
kept as reference only. Reality (unit files above) wins: data roots are the
Mac's /Volumes/COMPLETE (completed media) and /Volumes/INCOMPLETE
(in-flight downloads) volumes, mounted into qB at identical paths, and every
unit runs TZ=America/Los_Angeles.
Access / auth posture
There is no Caddy vhost for any arr app — the *arr stack is exempt by
construction from the Anubis guard chain (its own auth). The stack is reached
directly by IP:port on the LAN (http://<frankbook-pro>:8989 etc.).
Auth-config history (verified live 2026-08-29): all five arrs shipped with
AuthenticationMethod=None plus AuthenticationRequired=Enabled. On the
v1 (.NET) apps that combo is self-contradictory — UI Save is permanently
disabled and any settings save throws DryIoc.ScopedItemException inside
AuthorizationMiddleware (500 sprawl on every page after restart). The valid
representation of "no auth" in v1 is absence of the <AuthenticationRequired>
key, not the literal string Disabled — readarr's config (key absent) booted
clean while its three siblings (key=Disabled) 500-sprawled, which is how it
was caught. Fix applied live: key deleted on sonarr/radarr/lidarr/prowlarr,
containers restarted, all five verified serving. Posture = zero-auth arrs on
LAN and WAN; the Anubis wall guards homepage/search/hermes/prometheus/romm/files
but not the arrs — first-account-wins is the current race condition if that
ever flips to External auth (needs an IdP first; auth method choice remains an
operator decision).
Chain wiring (verified live 2026-08-30)
The download chain is wired and test-first verified: indexers → Prowlarr → per-arr qBittorrent clients (category = app name) → import.
- qB webUI auth is ON (
admin+ generated password; verify before writing it into any config — it was generated at first boot, not a default). - Per-arr QBittorrent download clients exist on sonarr/radarr/lidarr (enabled) and readarr (parked: its qB proxy fails auth live even with correct creds — known defect of the abandoned upstream; do not enable until the image changes). Each was tested before enabling; failures stay parked with a reason, never enabled blind.
- Prowlarr runs v2.5.2 where apps are first-class rows (
Applicationstable): four Application rows (sonarr/radarr/lidarr/readarr) now carry each arr's real baseUrl+apiKey withSyncLevel=FullSync. Before this, the table was empty and every sync attempt threwNullConfiginGetIndexerMappings()— visible inpodman logs prowlarr, not in any UI. - Indexers are test-before-enable: EZTV and 1337x stay disabled with reason "blocked by CloudFlare Protection" (this host's egress ASN is CF-blocked at those trackers); Nyaa.si, sukebei, RuTor, Byrutor, YTS passed live tests and are enabled. A failed test = parked with reason, never enabled blind.
- Prowlarr v2 sync model: indexers stay in Prowlarr; arrs search through it and hand off to their own qB download client (category routing). Mappings materialize at grab time — zero mappings right after wiring is expected, not a fault.
Disk layout (current)
/Volumes/COMPLETE <- completed-media volume (Mac volume)
├── sonarr-data:/config <- per-app config roots, one per unit
├── radarr-data:/config
├── lidarr-data:/config
├── readarr-data:/config
├── qbittorrent-data:/config
└── <movie/tv/music/books roots> <- arr import roots live here
/Volumes/INCOMPLETE <- qB in-flight downloads (same path inside qB)
qB mounts both volumes at their identical host paths
(Volume=/Volumes/COMPLETE:/Volumes/COMPLETE,
Volume=/Volumes/INCOMPLETE:/Volumes/INCOMPLETE), so a category's download path
is the same string on every container that touches it — no remapping between
download and import.
Gotchas
- Timezone: every unit runs
TZ=America/Los_Angeles; Sonarr's scheduler is timezone-sensitive — keep them uniform. - File permissions:
UMASK_SET=022on qBittorrent; arr apps run PUID=0 so they can read/move qB downloads. - Network conflicts: *arr apps use many ports. On the machine VM, only the API ports (8989/7878/8686/8787/9696) and gluetun's published 8080 + 6881 are host-published; netns-sharers (qB) publish none of their own.
- Prowlarr API key rotation: If rotated, update it in every arr app (
Applicationstable rows carry the real keys). - qBittorrent WebUI password: generated at first boot, not a default — persist it via the PBKDF2 conf recipe in qBittorrent before any restart.
- Readarr stability: abandoned upstream (retired May 2026); its qB download client is parked pending a successor image. Do not rely on it for mission-critical collections.
Best Practices
- Use tags to route content to specific download clients or categories.
- Enable the Blocklist in arr apps to prevent re-downloading failed torrents.
- Set download limits in qBittorrent to avoid bandwidth saturation.
- Back up arr configs regularly (they are small SQLite DBs + JSON) — each lives at
/Volumes/COMPLETE/<svc>-data/config. - Monitor Prowlarr indexer health — broken indexers hide new content.
- Start with default quality profiles. Add custom formats gradually.