Structural repair: - 13 pages were the same document twice (each exactly 2x its HEAD size), a second frontmatter block whose closing fence had been glued onto a body line by a frontmatter rewrite that re-read its own output. Un-doubled by cutting at the second frontmatter and keeping the copy whose body is a superset; the orphan census reports 0 lost tokens against HEAD. - log.md: one entry per date, bare `## YYYY-MM-DD` headings, newest first — 66 dated headings merged into 34, titles demoted to bold leads, every content line verified present. The file had been descending at the head and ascending at the tail. Ownership moves: - New `LLM/frank-medium.md` is the locator for the retired Dankserver endpoint: era windows quoted from each era page's own banner, no numbers restated, and the two unresolved date conflicts recorded instead of silently resolved. `frank-archon.md` links to it instead of restating the pre-rename window. - The four Pipeline-Parallelism stubs (frontmatter only, no body) are gone; `Multi-Node Runtimes.md` owns runtime construction, launch, mixed-vendor verdicts and cross-split spec decode, and the four links that pointed at the stubs were repointed at it or at the drafter page. - Authentik's three stub pages fold into `Authentik.md`, with the process detail and the outpost reference split out so the parent stays under the length hint. Verified corrections (host census + live probe, 2026-10-19): - The MXFP4 checkpoint two pages called the "on-disk rollback" is gone: /home/dank/models/ holds StillDeadcode, rad and tpl.jinja. Stated once, on the era page that owns that payload; the swap page now links to it. - frank-medium-radiance-mxfp4: the 4.24/7 accept rate belongs to the DFlash2 arm measured on the FP8 target, not to the MXFP4 era; the 3-family soak run census is kept once (155 requests) instead of twice (~120 and 155). - Fleet shapes re-confirmed against the live endpoints before touching any page: 3x200000 fp8 KV, 2x200704, 2x262144. Index rows are regenerated, not hand-carved. Net -1,849 vault lines.
120 lines
6.1 KiB
Markdown
120 lines
6.1 KiB
Markdown
---
|
|
type: reference
|
|
title: "*arr Stack"
|
|
description: "The *arr automation stack on FrankBook-Pro, every container on the VPN netns: topology, wiring, and gotchas."
|
|
tags: [arr-stack, prowlarr, sonarr, radarr, lidarr, readarr, qbittorrent, frankbook-pro, dankserver]
|
|
timestamp: 2026-09-04T00:00:00Z
|
|
---
|
|
|
|
# *arr Stack
|
|
|
|
The *arr automation stack runs on **FrankBook-Pro** (the Mac mini) as quadlets
|
|
inside its podman machine; all egress rides the gluetun WireGuard netns. The
|
|
per-service pages ([[Prowlarr]], [[Sonarr]], [[Radarr]], [[Lidarr]],
|
|
[[Readarr]], [[qBittorrent]]) carry deployment facts; this page holds the
|
|
cross-cutting API and auth-posture procedures.
|
|
|
|
## API version split (memorize before any *arr HTTP call)
|
|
|
|
- Sonarr/Radarr: `/api/v3/…`; Lidarr/Readarr/Prowlarr: `/api/v1/…`.
|
|
- Prowlarr is port **9696** — 8090 is Jackett.
|
|
- **Empty body = endpoint absent**, not a failure: probe endpoints by status
|
|
code first; v1 has no `/api/v1/profile` endpoint at all.
|
|
- `PUT /downloadclient` and `PUT /indexer/{id}` take a SINGLE resource object
|
|
(GET it, patch `settings`, PUT the whole object back). An array body fails
|
|
with `Path: $ | BytePositionInLine: 1`.
|
|
- API keys live in each container's config:
|
|
`podman exec <svc> grep -o "<ApiKey>[^<]*" /config/config.xml | cut -d">" -f2`.
|
|
They are local-only secrets — they stop being secret the moment a vhost
|
|
serves the API unauthenticated.
|
|
|
|
## Schema-first probing (validators are free documentation)
|
|
|
|
Send the FULL schema template object with fields filled; v1 validators reject
|
|
partials, and each error names the next required field — peel validators one
|
|
live call at a time instead of guessing payload shapes:
|
|
|
|
- `'Fields' must not be empty` → send a full schema copy, not `fields:[]`.
|
|
- `'Base Url' must not be empty` when keys were camelCase → **PascalCase is
|
|
required** (`BaseUrl`, `ApiKey`) — schema keys, not the JSON wire keys.
|
|
- `DefaultMetadataProfileId must be > 0` → fetch real ids from
|
|
`GET /api/v1/metadataprofile` (rows like `(1,'Standard')`);
|
|
`GET /api/v1/qualitydefinition` returns the quality CATALOG — ids ≠
|
|
profiles.
|
|
- `targetType null` → configContract not registered in that build (this
|
|
Prowlarr build has no Prowlarr-plugin indexer; integration is
|
|
Torznab-family only).
|
|
- `testingPackageId` in a PUT body downgrades validation failures to
|
|
warnings.
|
|
- `syncLevel` is enum `ApplicationSyncLevel` — omit it or use the int; a
|
|
string is rejected.
|
|
|
|
**Verification rules:** `POST /downloadclient` returns the COLLECTION, not
|
|
the created object — verify via GET. Test endpoints return verdicts in the
|
|
BODY at HTTP 200 (`{}` = pass, a list = fail) — judge from bodies, not
|
|
status codes. Command POSTs (`MoviesSearch`, `ApplicationSync`) run
|
|
server-side and respond only when the work finishes: curl `-m` timeouts
|
|
(HTTP 000) during a search are NOT failures — poll queue/history afterward
|
|
instead of re-firing; warm small commands (`RefreshMonitoredDownloads`)
|
|
answer in ~20 ms, so a hang means live work in progress, not a dead API.
|
|
|
|
**DB as arbiter:** when endpoint shapes are opaque, stop the container and
|
|
edit `/opt/prowlarr/config/prowlarr.db` with `sudo python3` sqlite directly,
|
|
then start. The indexers table columns are
|
|
Id/Name/Implementation/Settings/ConfigContract/Enable/Priority/Added — the
|
|
enable flag column is `Enable` (not `EnableRss`). Prowlarr's real application
|
|
settings values live in `prowlarr.db` → `Applications.Settings` JSON (the
|
|
`/api/v1/applications` GET responses carry `fields: []`).
|
|
|
|
## Auth posture probe (ground truth is behavior, not config flags)
|
|
|
|
`AuthenticationMethod=None` + `AuthenticationRequired=Enabled` in
|
|
`config.xml` is ambiguous on paper; on the wire it means a login screen with
|
|
**zero users** — first-account-wins.
|
|
|
|
1. **Confirm which host runs the service before probing** (`podman ps` on
|
|
the target, not the box you ssh'd into first — the arrs live on
|
|
FrankBook-Pro).
|
|
2. Probe an API endpoint that bypasses the SPA shell, locally and through
|
|
any vhost: `curl -s -o /dev/null -w "%{http_code}"
|
|
http://<host>:<port>/api/v3/system/status`. **SPA roots (`/`) always
|
|
serve a 200 shell — never conclude "open" or "gated" from `/`.**
|
|
401 = gated; 200 + JSON = API fully open (anyone on the net can drive it
|
|
with curl).
|
|
3. For config truth, dump the whole file
|
|
(`podman exec <svc> cat /config/config.xml`), not a piped
|
|
`grep | sed -n 2p`: **`sed -n Np` exits 0 on zero matches**, so the
|
|
pipeline hides a miss and you conclude "empty field" when the grep itself
|
|
failed.
|
|
4. Decision framing: when posture = gated-with-zero-users, present it as a
|
|
decision menu (None behind the front-door wall vs External/authentikarr),
|
|
not a silent change — first-account-wins means whoever logs in first owns
|
|
the instance.
|
|
|
|
## The `None` + `Enabled` auth-config trap (v1 .NET apps)
|
|
|
|
`<AuthenticationMethod>None</AuthenticationMethod>` +
|
|
`<AuthenticationRequired>Enabled</AuthenticationRequired>` is
|
|
self-contradictory: the UI Save is permanently disabled, and any save throws
|
|
`DryIoc.ScopedItemException` in `AuthorizationMiddleware` → 500 on every
|
|
page after restart. The valid no-auth representation is **absence of the
|
|
`<AuthenticationRequired>` key**, not the literal string `Disabled`. Fix =
|
|
delete the key from `/config/config.xml`
|
|
(`sed -i "/<AuthenticationRequired>/d"`), restart the container. Tell-tale:
|
|
one v1 app boots clean while siblings 500-sprawl → diff their config.xml
|
|
auth blocks; the healthy one shows the correct shape. (Prowlarr runs
|
|
`Forms` + `Enabled` healthily — the crash combo is `None`+`Enabled` only.)
|
|
|
|
General rules that saved the session these came from: container
|
|
`State=running` ≠ app serving — read `podman logs --tail 12 <c>` before
|
|
theorizing; when a UI gate blocks saving, go under it (these apps keep
|
|
plaintext XML config on disk — read/edit via `podman exec`).
|
|
|
|
## See Also
|
|
|
|
- [[Prowlarr]] — indexer feeds and the v2 sync model
|
|
- [[Sonarr]] · [[Radarr]] · [[Lidarr]] · [[Readarr]] — the managers
|
|
- [[qBittorrent]] — download client, 4.6.7 pin, E2E verification
|
|
- [[FrankBook-Pro]] — the host and its podman machine
|
|
- [[Homepage Status Probes]] — how the e2e gate treats this sleeping host
|