Files
serverAppConfigs/serverAppConfigs-docs/Dankserver/ARR-Stack.md
T

199 lines
11 KiB
Markdown

---
type: reference
title: *arr Stack
description: The *arr automation stack (Prowlarr, Sonarr, Radarr, Lidarr, Readarr, qBittorrent) — FrankBook-Pro quadlets and the Dankserver compose deployment (reactivated 2026-09-04): 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. The stack runs in two places: **FrankBook-Pro** — the Mac mini
that fronts this household's downloads — as quadlet units inside its podman
machine (the documented wiring below), and on **Dankserver** as a compose
stack behind six Caddy vhosts (reactivated 2026-09-04; see below). 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.
## Dankserver compose deployment (reactivated 2026-09-04)
The original Dankserver compose stack (`dankserver/compose.yaml`,
`/opt/<svc>/config` data roots) was committed 2026-08-29 but **never booted**:
the config dirs were created root-owned (`root:root 755`), and every app
crashed at logger init (`UnauthorizedAccessException: Access to the path
'/config/Sentry' is denied`) before binding any port — which read as a dead
port, not a boot crash, until `podman logs <svc>` was checked.
Fix and restart (2026-09-04): `sudo chown -R 1000:1000
/opt/{prowlarr,qbittorrent,radarr,sonarr,lidarr,readarr}/config`, then
`podman-compose -f dankserver/compose.yaml up -d` for the six services. All
six now serve 200 on their ports and through the Caddy vhosts.
### Rootless identity model (verified, do not "fix" it)
- 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, and the arr stack. This is why PUID=0
services write as `dank` and why data roots are owned `1000:1000`.
- **Never add `userns_mode: host` to compose services here.** 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.
- 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.
### Differences from the FrankBook-Pro deployment
- **No gluetun on Dankserver:** this qBittorrent's torrent egress leaves via
the residential IP (the FrankBook qB is the VPN-gated one). Route
privacy-sensitive grabs through FrankBook-Pro.
- **Empty config:** the Dankserver arrs have no indexers, no qB download
clients, and no quality profiles configured — the Chain wiring section
below describes FrankBook-Pro. Configure test-first per that section if
wiring this stack up.
- **Six vhosts:** `prowlarr/sonarr/radarr/lidarr/readarr/qbittorrent
.franksdank.cloud` are exempt from the Anubis chain (own auth) with a
documented exemption reason per the guard policy.
- Homepage: Sonarr sits in the user section; Prowlarr/Radarr/Readarr/Lidarr/
qBittorrent sit in admin.
## Historical note
The compose file briefly carried `userns_mode: host` on all six services
(2026-09-04, reverted same day in `e454159`) — an incorrect fix for the boot
crash that podman-compose 1.5.0 could not apply anyway (pod/userns conflict
above). The real fix was the chown; see the identity model section.
## 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. FrankBook-Pro's stack is reached directly by IP:port on the LAN
(`http://<frankbook-pro>:8989` etc.); the Dankserver stack additionally has
six TLS vhosts (`<svc>.franksdank.cloud`) that terminate on Caddy on Dankclaw
and route to Dankserver's published ports.
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 (`Applications` table):
four Application rows (sonarr/radarr/lidarr/readarr) now carry each arr's
real baseUrl+apiKey with `SyncLevel=FullSync`. Before this, the table was
empty and every sync attempt threw `NullConfig` in `GetIndexerMappings()` —
visible in `podman 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=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