Flip the homepage Sonarr card from the user category to admin and repoint its link at the LAN-direct port (192.168.0.112:8989). Retire the unguarded public vhost sonarr.franksdank.cloud (direct reverse_proxy, no auth) and its post-auth @sonarr handler from the Caddyfile; drop the Pi-hole addn-hosts A record with it. No public Porkbun record ever existed (NXDOMAIN at the zone), so after this there is no WAN path to Sonarr: users request TV via Seerr (guarded), admins reach Sonarr's own UI from the LAN only. Fixes the seerr/sonarr mix-up from 19b2589/e0bade6.
190 lines
11 KiB
Markdown
190 lines
11 KiB
Markdown
---
|
|
type: reference
|
|
title: *arr Stack
|
|
description: The *arr automation stack (Prowlarr, Sonarr, Radarr, Lidarr, Readarr, qBittorrent) — FrankBook-Pro only, every container on the gluetun WireGuard netns (all egress VPN): topology, wiring, auth posture, and gotchas.
|
|
tags: [arr-stack, prowlarr, sonarr, radarr, lidarr, readarr, qbittorrent, frankbook-pro, dankserver]
|
|
timestamp: 2026-09-04T00:00:00Z
|
|
---
|
|
|
|
# *arr Stack
|
|
|
|
The *arr suite is a collection of automated media management tools for Usenet
|
|
and BitTorrent. It runs in exactly one place: **FrankBook-Pro** — the Mac mini
|
|
that fronts this household's downloads — as quadlet units inside its podman
|
|
machine, with every container (the five arrs AND qBittorrent) sharing the
|
|
[[Gluetun]] WireGuard tunnel's network namespace so **all egress exits
|
|
through the VPN**. A short-lived Dankserver compose copy was removed on
|
|
2026-09-04 (see below). The stack 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.
|
|
|
|
## Dankserver compose copy (removed 2026-09-04)
|
|
|
|
A copy of the stack lived in `dankserver/compose.yaml` (`/opt/<svc>/config`
|
|
data roots) from 2026-08-20 to 2026-09-04 and never ran healthy: the config
|
|
dirs were created root-owned (`root:root 755`), so every app died at logger
|
|
init (`UnauthorizedAccessException: Access to the path '/config/Sentry' is
|
|
denied`) before binding any port — which read as dead ports, not a boot
|
|
crash, until `podman logs <svc>` was checked. After a one-day revival it was
|
|
removed by operator decision: **FrankBook-Pro is the sole *arr deployment.**
|
|
Config roots moved to `~/.AGENTTRASH/20260904-dankserver-arr-teardown/` on
|
|
Dankserver (recoverable until purged).
|
|
|
|
### Rootless identity model on Dankserver (verified, keep for reference)
|
|
|
|
- On Dankserver's podman 5.7.0 rootless, a container's default user namespace
|
|
maps **container root (PUID=0) → host uid 1000 (dank)** and container uid
|
|
*N* → host `100000 + N - 1`. Verified via `/proc/<pid>/uid_map`
|
|
(`0 1000 1` / `1 100000 65536`) across plex, tautulli, jellyfin,
|
|
calibre-web, copyparty, romm. This is why PUID=0 services write as `dank`
|
|
and why data roots are owned `1000:1000` on that host.
|
|
- **Never add `userns_mode: host` to a podman-compose service.**
|
|
podman-compose 1.5.0 runs every compose service inside a pod, and podman
|
|
rejects the combination (`--userns and --pod cannot be set together`) —
|
|
the stack then fails to recreate with no recourse. The default mapping
|
|
already gives the fleet identity; PUID=0 + `1000:1000`-owned data roots is
|
|
the whole recipe. (The compose file briefly carried `userns_mode: host` on
|
|
all six arr services on 2026-09-04 — reverted in `e454159`, same day.)
|
|
- qBittorrent's first boot (PUID=0, empty config) prints a one-time WebUI
|
|
admin password in `podman logs qbittorrent` — persist it via the PBKDF2
|
|
recipe in [[qBittorrent]] before restarting the container.
|
|
|
|
## Access / auth posture
|
|
|
|
No *arr app sits behind the Anubis guard chain — the stack is exempt by
|
|
construction (its own auth), with an exemption comment in the Caddyfile per
|
|
vhost. Five TLS vhosts (`<svc>.franksdank.cloud`) terminate on Caddy on
|
|
Dankclaw and route to FrankBook-Pro's published ports
|
|
(`192.168.0.112:<port>`, all exposed by the gluetun unit since the netns
|
|
consolidation); the same ports are reachable directly on the LAN. Sonarr is
|
|
the exception: internal-only by construction — no vhost, no public DNS record;
|
|
admins reach it at `http://192.168.0.112:8989` from the LAN only (retired
|
|
2026-09-04; users request TV through [[Seerr]] instead).
|
|
|
|
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). Sonarr is exempt from even that exposure since 2026-09-04:
|
|
with no vhost and no public DNS record, its zero-auth UI has no WAN path at all.
|
|
|
|
## 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; retest needed
|
|
after the 2026-09-04 netns move). All four clients were re-pointed to
|
|
**loopback** (`127.0.0.1:8080`, same netns) on 2026-09-04 when the arrs
|
|
joined gluetun's netns — the old `10.88.0.1:8080` gateway hack routes
|
|
into the VPN tunnel (AllowedIPs=0.0.0.0/0) and is dead from inside the
|
|
netns. Verified live: `podman exec sonarr curl` reaches qB with 200, and
|
|
a real qB login from inside the netns returns 200.
|
|
- Prowlarr runs v2.5.2 where apps are first-class rows (`Applications`
|
|
table): four Application rows (sonarr/radarr/lidarr/readarr) carried each
|
|
arr's real baseUrl+apiKey with `SyncLevel=FullSync` as of 2026-08-30.
|
|
**Status 2026-09-04: the table is EMPTY again** (live API check — 8 rows,
|
|
all Cardigann/Torznab, zero Application rows; lost with the dankserver
|
|
config migration). Prowlarr sync is broken until the four rows are
|
|
rebuilt with baseUrl `127.0.0.1:<arr port>` (same netns).
|
|
- Indexers are **test-before-enable**: EZTV and 1337x stay disabled with
|
|
reason "blocked by CloudFlare Protection" (this host's egress ASN was
|
|
CF-blocked at those trackers). **2026-09-04: arr egress moved onto the
|
|
ProtonVPN tunnel** — the parked reason may no longer hold; retest before
|
|
enabling. 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=022` on 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 (`Applications` table 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
|
|
|
|
1. Use tags to route content to specific download clients or categories.
|
|
2. Enable the Blocklist in arr apps to prevent re-downloading failed torrents.
|
|
3. Set download limits in qBittorrent to avoid bandwidth saturation.
|
|
4. Back up arr configs regularly (they are small SQLite DBs + JSON) — each lives at `/Volumes/COMPLETE/<svc>-data/config`.
|
|
5. Monitor Prowlarr indexer health — broken indexers hide new content.
|
|
6. Start with default quality profiles. Add custom formats gradually.
|
|
|
|
## See Also
|
|
|
|
- [[Sonarr]] · [[Radarr]] · [[Lidarr]] · [[Readarr]] · [[Prowlarr]] · [[qBittorrent]] — per-service pages
|
|
- [[Jellyfin]] — media server that consumes *arr downloads
|
|
- [[Copyparty]] — alternative file viewer
|