109 lines
5.2 KiB
Markdown
109 lines
5.2 KiB
Markdown
---
|
|
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/<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`
|