--- type: reference description: FrankBook-Pro — the Mac mini running the *arr stack + qBittorrent inside a podman machine VM, gluetun-gated tags: [frankbook-pro, mac, arr, qbittorrent, gluetun, wireguard, podman-machine] timestamp: 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//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/`) via `podman 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) qBittorrent downloads through gluetun (netns share); the arrs run without it. Until `/home/core/Containers/gluetun/env` contains the WireGuard credentials (a second Proton WireGuard config for the Mac — running two hosts on Dankclaw's config would bounce the server-side endpoint and kill SearXNG), `deploy_frankbook_stack` **skips** gluetun and qbittorrent with instructions and deploys the five arrs anyway. The qB WebUI port stays unpublished by design; the e2e torrent test waits on the credentials. ### Mac provisioning (2026-09-01 — one dashboard action, then mine) The endpoint is a **ProtonVPN Seattle WireGuard server**, not a self-administered box: RDAP says `149.102.254.77` is CDNEXT-CG-SEA (Datacamp Limited, Proton's Seattle hosting partner) and Dankclaw's own tunnel v6 `2a07:b944::2:2` sits in CH-PROTONVPN-20160719. There is no peer-registration step on any server of ours — Dankclaw's credentials are a dashboard-generated Proton WG config pasted into gluetun's `custom` profile, and the Mac needs exactly the same thing, generated fresh: 1. In the Proton dashboard, create a second WireGuard config (e.g. named `frankbook`) on the Seattle server and download the `.conf`. One config = one keypair; reusing Dankclaw's would make the server bounce the endpoint between the two hosts. 2. Hand the values over (the file itself or its fields — the private key never enters the repo): - `PrivateKey` → `WIREGUARD_PRIVATE_KEY` - `Address` (v4 + v6, e.g. `10.2.0.3/32, 2a07:b944::2:3/128`) → `WIREGUARD_ADDRESSES` - `PublicKey` → `WIREGUARD_PUBLIC_KEY` (Seattle server key: `utqNH4P+C0fA1wTgIUaIfhm1b7ai0iEGvXyiw4KC3Fs=`, same as Dankclaw's) - `Endpoint` = `149.102.254.77:51820`; gluetun ignores the `.conf` DNS line. Then `/home/core/Containers/gluetun/env` (0600) inside the VM: VPN_SERVICE_PROVIDER=custom VPN_TYPE=wireguard WIREGUARD_PRIVATE_KEY= WIREGUARD_ADDRESSES= WIREGUARD_PUBLIC_KEY=utqNH4P+C0fA1wTgIUaIfhm1b7ai0iEGvXyiw4KC3Fs= WIREGUARD_ENDPOINT_IP=149.102.254.77 WIREGUARD_ENDPOINT_PORT=51820 WIREGUARD_ALLOWED_IPS=0.0.0.0/0,::/0 WIREGUARD_PERSISTENT_KEEPALIVE_INTERVAL=25s Deploy with `./scripts/deploy.sh frankbook-pro --service gluetun --service qbittorrent`, then verify egress from the VM (`podman exec gluetun curl -s ifconfig.me` must NOT show the residential IP) before declaring the BitTorrent port usable. ## Deploy flow Same deployer as every host: `./scripts/deploy.sh frankbook-pro --service ` 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), the qB WebUI (8080, inert until the tunnel is up), and the BitTorrent port 6881 tcp+udp. ## qBittorrent seed (first boot, inside the VM) - `WebUI\Password` is 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 Prowlarr wiring. - `HostHeaderValidation=false` + `ServerDomains=*`: the socat forwarder preserves the LAN `Host` header, which would otherwise be rejected. - `categories.json` pre-creates `Finished Torrents`, `lidarr`, `radarr`, `tv-sonarr` with save_path `/Volumes/COMPLETE/Finished Torrents`. - `Session\DefaultSavePath=/Volumes/COMPLETE`, `Session\TempPath=/Volumes/INCOMPLETE/incomplete` (two-disk layout). # Citations - Plan: `local://podman-standardization-arr-migration-plan.md` (session 2026-09-01) - Units: `frankbook-pro/*/quadlet/*.container`, seam `tests/frankbook_quadlet.bats` - Handler: `deploy_frankbook_stack`, `scripts/deploy-remote.sh`