Files
serverAppConfigs/serverAppConfigs-docs/Infrastructure/FrankBook-Pro.md
T

5.2 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
frankbook-pro
mac
arr
qbittorrent
gluetun
wireguard
podman-machine
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/) 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=<from the Proton .conf>
WIREGUARD_ADDRESSES=<from the Proton .conf>
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 <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), 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