- qB 5.x's 204 login breaks Readarr's retired client at runtime; 4.6.7 answers legacy 200+Ok. Pin recorded in the unit and documented. - Prowlarr download client created via schema template; all five clients test 200 through the podman gateway. - PBKDF2 gotcha: qB 5.x conf rewrite left a hash 4.6.7 rejects; fresh rewrite of the same line restored login. - E2E: torrent through the Panama tunnel at ~17 MB/s, completed into Finished Torrents, deleted with data.
7.1 KiB
type, description, tags, timestamp
| type | description | tags | timestamp | |||||||
|---|---|---|---|---|---|---|---|---|---|---|
| reference | FrankBook-Pro — the Mac mini running the *arr stack + qBittorrent inside a podman machine VM, gluetun-gated |
|
2026-09-01 |
FrankBook-Pro
FrankBook-Pro (192.168.0.112, macOS x86_64, Intel) runs the *arr automation
stack and qBittorrent inside a podman machine VM (Fedora CoreOS-style
core user). Seven quadlet units live in frankbook-pro/<svc>/quadlet/:
gluetun, qbittorrent, prowlarr, sonarr, radarr, lidarr, readarr.
Why a VM, and why inside it
- macOS podman runs containers inside a VM; quadlet units are installed in the
VM (
/home/core/.config/containers/systemd/) viapodman machine ssh. /Volumes/COMPLETE(review disk) and/Volumes/INCOMPLETE(in-progress disk) are virtiofs-mounted into the VM, so qBittorrent writes straight to the same disks the human review workflow uses.- Grab-only stack: the arrs never auto-import; nothing writes to the entropy
volume. Completed files land in
/Volumes/COMPLETE/Finished Torrents.
WireGuard gate (gluetun) — ACTIVE
qBittorrent downloads through gluetun (netns share); the arrs run without it.
Provisioned 2026-09-01 with a second Proton WireGuard config (server
PA-12; the downloaded .conf lives in ~/Downloads/FrankBook-Pro-PA-12.conf
on Dankware). One config = one keypair — reusing Dankclaw's would bounce the
server-side endpoint and kill SearXNG. The Seattle server the plan originally
assumed is equally valid; only endpoint + server pubkey must match the
chosen config. Egress verified from inside the VM: curl ifconfig.me shows
the Proton PA exit (never the residential IP), ~19 MB/s sustained on a live
torrent.
/home/core/Containers/gluetun/env (0600, inside the VM):
VPN_SERVICE_PROVIDER=custom
VPN_TYPE=wireguard
WIREGUARD_PRIVATE_KEY=<from the Proton .conf>
WIREGUARD_ADDRESSES=<from the Proton .conf>
WIREGUARD_PUBLIC_KEY=<that server's pubkey>
WIREGUARD_ENDPOINT_IP=51.179.177.2
WIREGUARD_ENDPOINT_PORT=51820
WIREGUARD_ALLOWED_IPS=0.0.0.0/0,::/0
WIREGUARD_PERSISTENT_KEEPALIVE_INTERVAL=25s
The private key is hashed into the VM env file and never enters the repo.
NAT-PMP inbound forwarding is available on Proton (gluetun supports it via
FIREWALL_INPUT_PORTS + NATPMP=true) — deliberately deferred: the e2e
gate passes outbound-only, and swarm peers needing an inbound port is a
seeding-era concern, not a grab-only one.
Deploy flow
Same deployer as every host: ./scripts/deploy.sh frankbook-pro --service <svc> from Dankware. The Mac-side handler (deploy_frankbook_stack in
scripts/deploy-remote.sh) pipes unit files + a seed script through
podman machine ssh bash -s, seeds qBittorrent's first-boot config once
(marker file qbit-seeded), restarts the selected unit inside the VM, and
health-checks its published port on Mac loopback.
LAN reachability
gvproxy forwards published ports to Mac loopback only. LaunchAgents
(local.fwd.* in ~/Library/LaunchAgents) run socat forwarders binding the
LAN IP (192.168.0.112) for arr UIs (9696/8989/7878/8686/8787) and the qB
WebUI (8080). The two 6881 tcp+udp agents were retired: gvproxy binds a
wildcard *:6881/udp listener (dual-stack; Go sets SO_REUSEADDR on TCP but
not UDP), so the socat-specific bind collides at every boot — delete the
agents; swarm inbound (if ever needed) is the Proton NAT-PMP path, not the
LAN one. Note macOS's application firewall still filters gvproxy inbound
from non-local sources (stealth mode drops unsolicited packets), so
cross-host reachability of 8080 from other LAN boxes may need
socketfilterfw allowlisting of gvproxy — Mac-local use and swarm egress
are unaffected.
qBittorrent runtime + wiring (2026-09-01)
WebUI\Password_PBKDF2is a PBKDF2@ByteArray(salt:hash)(PBKDF2-HMAC-SHA512, 100k iterations, 64 bytes) — qB ≥ 4.2 ignores plaintext. The plaintext lives in/home/core/Containers/qbittorrent/env(mode 600, VM-local) for the arr wiring. The first seed wrote the hash under the legacyWebUI\Passwordkey (silently ignored → every client gotUnauthenticated); the live conf was patched andscripts/deploy-remote.shfixed to write the_PBKDF2key. Gotcha (live, 2026-09-01): after qB 5.x ran, its conf rewrite left a hash line 4.6.7 rejects (invalid credentialsfor every login, including the arrs); rewriting the same@ByteArrayline fresh (same password, 100k iterations) restored login. Any future version flip: regenerate the line.HostHeaderValidation=false+ServerDomains=*: the socat forwarder preserves the LANHostheader, which would otherwise be rejected.- Save-path convention:
Session\DefaultSavePath=/Volumes/COMPLETE/ Finished Torrents,Session\TempPath=/Volumes/INCOMPLETE/incomplete(two-disk layout: partials on INCOMPLETE, qB moves on completion). qB 5.2 API adds with a category do not inherit the category save path (no auto-TMM), so the default itself points atFinished Torrents: every grab lands there regardless of client behavior; human review moves files onward; nothing writes to the entropy volume. - Categories seeded:
Finished Torrents,lidarr,radarr,readarr,tv-sonarr(all →Finished Torrents). - Download clients (gateway
10.88.0.1:8080, useradmin): all five test green against live qB — sonarr (tv-sonarr), radarr, lidarr, readarr (rows pre-created in the prior session; passwords re-pushed via API), and prowlarr (created from the/downloadclient/schematemplate — a hand-minimal body 400s in Prowlarr's create-time test). Readarr's EOL validator (last release 2023) rejects qB ≥ 5's204empty login success as "Authentication failure" — that kills runtime auth too, not just API creates; the fix was pinning qB itself (below), after which readarr tests 200 like the rest. - qB pinned to 4.6.7 (
Image=lscr.io/linuxserver/qbittorrent:4.6.7, notlatest):latestresolved to 5.x, whose204login breaks Readarr's frozen client; 4.6.7 answers the legacy200+"Ok."that every client accepts. Pinned infrankbook-pro/qbittorrent/quadlet/qbittorrent.container. - Prowlarr Applications push to sonarr/radarr/lidarr (
fullSync, gateway ports). Readarr deliberately omitted: prowlarr's indexer-push test to readarr's/api/v1/indexer/test500s (EOL schema drift). LegacyProwlarr-*indexer rows carried in the migrated dankserver DBs pointed at the unresolvable hostnameprowlarr:9696and were deleted; the current*(Prowlarr)entries test OK. - E2E proven (2026-09-01, on 4.6.7): added a legal test torrent via the
API with category
Finished Torrents— downloaded through the tunnel (~17 MB/s), qB moved it INCOMPLETE → COMPLETE into/Volumes/COMPLETE/Finished Torrents, then deleted with data.
Citations
- Plan:
local://podman-standardization-arr-migration-plan.md(session 2026-09-01) - Units:
frankbook-pro/*/quadlet/*.container, seamtests/frankbook_quadlet.bats - Handler:
deploy_frankbook_stack,scripts/deploy-remote.sh