From 3626c7f40d905d2b55cad8d4f1d35b1af219720c Mon Sep 17 00:00:00 2001 From: Frank Date: Sun, 30 Aug 2026 00:38:09 -0700 Subject: [PATCH] docs(arr-chain): Prowlarr feed contract cracked, qB PBKDF2 persistence recipe, chain proof --- serverAppConfigs-docs/Dankserver/prowlarr.md | 72 ++++++++++++++++--- .../Dankserver/qbittorrent.md | 46 ++++++++++-- serverAppConfigs-docs/log.md | 33 +++++++++ 3 files changed, 134 insertions(+), 17 deletions(-) diff --git a/serverAppConfigs-docs/Dankserver/prowlarr.md b/serverAppConfigs-docs/Dankserver/prowlarr.md index 27841bb..47cf940 100644 --- a/serverAppConfigs-docs/Dankserver/prowlarr.md +++ b/serverAppConfigs-docs/Dankserver/prowlarr.md @@ -1,6 +1,8 @@ # Prowlarr -Prowlarr is the indexer management layer for the *arr stack. It aggregates indexers (torrent and Usenet) and exposes a unified API that Sonarr, Radarr, Lidarr, and Readarr consume. +Prowlarr is the indexer management layer for the *arr stack. It hosts the +indexer definitions and exposes them as Torznab feeds and downloads; +Sonarr, Radarr, Lidarr, and Readarr query those feeds and receive results. **Host:** Dankserver — **Hostname:** `prowlarr.dankserver.local` — **Docs:** https://wiki.servarr.com/prowlarr @@ -11,14 +13,35 @@ Prowlarr is the indexer management layer for the *arr stack. It aggregates index | Image | `lscr.io/linuxserver/prowlarr:latest` | | Port | 9696 (host) → 9696 (container) | | Min RAM | 256 MB | -| Auth | API key (Settings → General) | +| Auth | Forms (web UI) + API key (`/api/v1/...` and feed routes) | -## Configuration +## Live wiring (verified end-to-end 2026-08-30) -1. Add indexers: Settings → Indexers → Add. -2. Test each indexer with the **Test** button. -3. Assign tags (e.g., `movies`, `tv`, `music`) to indexers for routing. -4. Add download client: Settings → Download Clients → Add qBittorrent. +Indexer queries flow **through** Prowlarr; a grab hands off to the querying +app's own qBittorrent download client. Feeds are per-indexer: + +``` +http://prowlarr:9696/{indexerId}/api?apikey={GLOBAL_KEY}&t=caps|search|tvsearch|movie|music|book&... +http://prowlarr:9696/{indexerId}/download?link=...&file=... (torrent handoff) +``` + +| App | Indexer row | Prowlarr id | Categories | Status | +|---|---|---|---|---| +| Radarr | Prowlarr-YTS | 7 | [2000] | ✅ grabbed + imported 2160p Dark Knight 2026-08-30 | +| Sonarr | Prowlarr-Nyaa | 4 | [5000] | ✅ connection validated (202) | +| Lidarr | Prowlarr-Nyaa | 4 | [3000] | ✅ connection validated (202) | +| Readarr | Prowlarr-Byrutor | 3 | [7000] | indexer valid; download client parked | + +The global API key is in `config.xml` (``); per-application keys are +only used by Prowlarr's own sync calls, NOT by the feeds. The arr download +clients authenticate to qBittorrent with the permanent WebUI password stored +in `/home/dank/.qbpass` (mode 600) on Dankserver. + +**Readarr caveat:** Readarr is abandoned upstream (last release 0.4.x); its +qBittorrent client cannot authenticate against qB 5 (`Authentication +failure` on the connection test while Sonarr/Lidarr/Radarr pass with the +same credentials). The books pipeline is parked pending a Readarr successor; +the indexer row itself is healthy. ## Docker Compose @@ -40,11 +63,38 @@ prowlarr: networks: [appnet] ``` -## Gotchas +## Gotchas (all verified live 2026-08-30) -- Prowlarr database grows with indexer data. Set up periodic vacuum/backup. -- Indexer sync has a 15–60 minute delay. Search results may lag. -- Rotate API key: update it in every arr app. +- **The feed route is `/{indexerId}/api`.** There is no `/torznab/{id}/feed` + — that path (and any other unmatched path) hits the Forms-auth catch-all + and gets `302 → /login?returnUrl=…`. An arr following the redirect parses + the login HTML and fails with a cryptic + `'/' is an unexpected token … Line 54` XML error that looks like an auth + problem. It is a path typo. Source: `NewznabController` + (`[HttpGet("{id:int}/api")]` + absolute + `/api/v1/indexer/{id}/newznab`). +- **The arr's Torznab joiner is `TrimEnd(baseUrl,'/') + apiPath` with NO + separator.** `baseUrl="…/7/" + apiPath="api"` silently becomes `…/7api`. + Either keep the leading slash on `apiPath` (`"/api"`) or end the baseUrl + with `/api`. +- Categories in the indexer row must be a subset of what the feed's `caps` + advertises; extras log "does not support the following categories" and + some feeds reject them. +- The v1 API collection is `/api/v1/applications` (not `/api/v1/app`); + GET responses carry `fields: []` — real settings values live in + `prowlarr.db` → `Applications.Settings` JSON (read-only inspection). +- Instance name/`InstanceName=Prowlarr` in `config.xml` does NOT prefix the + API/feed routes on this build (they answer at root; the `/Prowlarr/...` + prefix 302s to the SPA). +- **Application auto-sync cannot manage these rows** (they carry + `SyncLevel=2`): `POST /api/v1/applications/test` fails with + `Unable to cast object of type 'NzbDrone.Core.Thing…'` — Prowlarr v1 + cannot deserialize Radarr 6.3's newer response types. The manual Torznab + rows above are therefore the real integration; sync neither duplicates + nor clobbers them. +- Prowlarr runs `AuthenticationMethod=Forms` + `AuthenticationRequired=Enabled` + healthily — the DryIoc crash combo was `None`+`Enabled` only (see + [[radarr]] auth notes). ## See Also diff --git a/serverAppConfigs-docs/Dankserver/qbittorrent.md b/serverAppConfigs-docs/Dankserver/qbittorrent.md index 9cb60e2..2bcc661 100644 --- a/serverAppConfigs-docs/Dankserver/qbittorrent.md +++ b/serverAppConfigs-docs/Dankserver/qbittorrent.md @@ -15,10 +15,39 @@ qBittorrent is the torrent download client for the *arr stack on Dankserver. It ## Configuration -1. Change the default Web UI password (Settings → Web UI). -2. Enable "No auth mode for LAN" for arr app connectivity (Settings → Web UI → uncheck "HTTP authentication required for clients"). -3. Create download categories: `movies`, `tv`, `music`, `books`. -4. Set max active downloads: Settings → Downloads (recommended: 5 global, 3 per category). +1. Keep Web UI authentication ON (LAN bypass not needed — the arr apps + authenticate with the API) and give them a permanent password. +2. Create download categories per app (`radarr`, `sonarr`, `lidarr`, + `readarr`): the arr download clients route category-per-app, and Prowlarr + feeds hand grabs to each app's own client. +3. Set max active downloads: Settings → Downloads (recommended: 5 global, + 3 per category). + +## Persistent WebUI credentials (verified 2026-08-30) + +qBittorrent 5 mints a **new temporary password at every start** unless a +password is stored in `qBittorrent.conf`. That rotation silently breaks every +arr download client after each reboot. The Web-API has no password endpoint +any more (`/api/v2/app/setPassword` was removed), and the linuxserver image +has no `WEBUI_AUTH` handling — so persistence must be written to the conf +directly, in qb's own `salt:hash` format (`src/base/utils/password.cpp`: +PBKDF2-HMAC-SHA512, 100 000 iterations, 16-byte salt = 4×uint32, then +`base64(salt) + ":" + base64(hash)` as the raw value): + +```python +import base64, hashlib, os +salt = os.urandom(16) +h = hashlib.pbkdf2_hmac("sha512", password.encode(), salt, 100000, 64) +val = (base64.b64encode(salt) + b":" + base64.b64encode(h)).decode() +# with the container STOPPED, in [Preferences]: +# WebUI\Username=admin +# WebUI\Password_PBKDF2= +``` + +Then `podman start qbittorrent` and confirm login survives a +`podman restart` — the temp-password rotation stops the moment stored +credentials verify. (The classic `@ByteArray(salt+hash)` form is WRONG for +qb5: login 401s on it; verify() base64-decodes the two halves separately.) ## Docker Compose @@ -41,9 +70,14 @@ qbittorrent: networks: [appnet] ``` -## Gotchas +## Gotchas (verified live) -- qBittorrent Web UI password changes on first run (check `config/qBittorrent.conf`). +- Temporary-password rotation on every boot is the default state of an + untouched qb5 — see the persistence recipe above; without it, all arr + download clients silently fail queue adds ("Couldn't add release … to + download queue" in the arr logs) after any restart. +- API login from `curl` needs a `Referer: http://:/` header + (CSRF protection) or POSTs get rejected even with a valid SID. - Ensure umask is set to `022` so downloaded files are readable by arr apps. - Monitor bandwidth limits to avoid saturating the network. diff --git a/serverAppConfigs-docs/log.md b/serverAppConfigs-docs/log.md index 4c84f79..7f13e52 100644 --- a/serverAppConfigs-docs/log.md +++ b/serverAppConfigs-docs/log.md @@ -11,6 +11,39 @@ timestamp: 2026-09-14 # Bundle Change Log +## 2026-08-30 (late) — download chain proven end to end; qB credentials persisted +- **Cracked the arr↔Prowlarr feed contract**: route is `/{indexerId}/api` + (Prowlarr `NewznabController`; absolute `/api/v1/indexer/{id}/newznab`), + auth = the Prowlarr **global** key. The previously hand-rolled + `/torznab/{id}/feed` paths were Forms-auth catch-alls returning + `302 → /login` — which the arrs XML-parsed as "unexpected token '/'". + A source-verified librarian answer settled it in one shot. +- **Re-pointed all four arr indexer rows** (Radarr→YTS id7, + Sonarr/Lidarr→Nyaa id4, Readarr→Byrutor id3) via each app's own API; + every PUT passed the app's live connection validator (202); RSS enabled. +- **First real grab**: `MoviesSearch` → 3 YTS releases → *The Dark Knight + (2008) 2160p* (7.5 GiB) → qBittorrent 100 % → **imported** + (`hasFile: true`, 8,078,103,833 B at `/movies/The Dark Knight (2008)`, + hardlinked from the shared `/mnt/entropy` filesystem), queue empty. +- **Prowlarr Application auto-sync found broken by version skew** + (`Unable to cast object of type 'NzbDrone.Core.Thing…'` against Radarr + 6.3) — the manual rows are the integration; documented. +- **qBittorrent permanent credentials installed**: the WebUI temp password + rotated on every boot (it had silently broken the arr clients once this + session). qb5 removed the API password endpoint and the lscr image has + no env support — wrote `WebUI\Password_PBKDF2` (source-verified + `base64(salt):base64(PBKDF2-HMAC-SHA512/100k)` form) into the conf with + the container stopped; login survives `podman restart` (204). All arr + download clients updated to it; value kept host-local in + `/home/dank/.qbpass` (0600), never in git. +- **Readarr parked with reason**: abandoned upstream; its qB client cannot + authenticate against qB 5 while three sibling apps pass with identical + credentials. Indexer row healthy; books pipeline awaits a successor. +- **Docs**: rewrote `Dankserver/prowlarr.md` (live wiring + six verified + gotchas incl. the joiner bug and the 302-masquerading-as-auth failure) + and `Dankserver/qbittorrent.md` (persistent-credential recipe, Referer + CSRF note). + ## 2026-08-29 (late) — guarded-host sign-in fixed end to end - **Diagnosed** both user symptoms: `Invalid next URL` = the flow being entered with an absolute cross-host `next=` (open-redirect guard rejects at completion); phone "hostname could not be found" = the public DNS zone had **no `auth` A record** (added via Porkbun API, `auth A 71.227.227.172 TTL 300`). - **Disproved meta-header routing** live (full meta-header set still 404s; matching `Host` alone answers). The 2026.8 embedded outpost routes solely on the original `Host` vs each proxy provider's `external_host`.