Mechanical identity rename across the knowledge base, AGENTS.md, README, the
hermes config example, and homepage services.json. No behavior change; served
aliases on the LLM endpoints change with the deploy of commit 69f87c8.
5.2 KiB
type, title, description, tags, timestamp
| type | title | description | tags | timestamp | ||||
|---|---|---|---|---|---|---|---|---|
| reference | qBittorrent | qBittorrent download client for the *arr stack — pinned 4.6.7 on FrankBook-Pro, shares the Gluetun WireGuard netns, PBKDF2 WebUI credential recipe. |
|
2026-09-03T00:00:00Z |
qBittorrent
qBittorrent is the torrent download client for the *arr stack. The stack runs on FrankBook-Pro (the Mac mini) as quadlet units inside its podman machine — not on Dankserver. It receives download requests from Sonarr, Radarr, Lidarr, and Readarr via category tagging.
Host: FrankBook-Pro (podman machine) — Access: WebUI on port 8080,
published by the Gluetun unit because qBittorrent shares that container's
network namespace (a netns-sharer publishes no ports of its own).
Facts
| Item | Value |
|---|---|
| Image | lscr.io/linuxserver/qbittorrent:4.6.7 — pinned, see the pin rationale below |
| Network | Network=gluetun.container (torrent egress exits via the WireGuard/ProtonVPN tunnel) |
| Ports | 8080 (WebUI) and 6881 TCP+UDP published on the gluetun unit |
| Env | PUID=0, PGID=0, TZ=America/Los_Angeles, UMASK_SET=022 |
| Volumes | /Volumes/COMPLETE/qbittorrent-data:/config, plus /Volumes/COMPLETE and /Volumes/INCOMPLETE mounted at identical paths |
| Auth | Web UI username/password (admin + generated password); LAN bypass not used |
Why the 4.6.7 pin exists (2026-09-01)
Readarr's abandoned qBittorrent client rejects qB ≥ 5's 204 empty-body login
success as Authentication failure — a runtime break, not just an API-create
issue. The fleet pins lscr.io/linuxserver/qbittorrent:4.6.7 while Readarr is
in the stack. Never unpin to latest while Readarr is in the fleet.
Second trap on any version flip: qB 5.x's shutdown conf rewrite leaves a
WebUI\Password_PBKDF2=@ByteArray(...) line that 4.6.7 rejects — every login
then returns "invalid credentials" (the arrs included). Fix = rewrite the same
conf line with the same password while qB is stopped.
Persistent WebUI credentials (verified 2026-08-30)
qBittorrent 5 mints a new temporary password at every start unless a
password is stored in qBittorrent.conf. That rotation silently breaks every
arr download client after each reboot. The Web-API has no password endpoint
any more (/api/v2/app/setPassword was removed), and the linuxserver image
has no WEBUI_AUTH handling — so persistence must be written to the conf
directly, in qb's own salt:hash format (src/base/utils/password.cpp:
PBKDF2-HMAC-SHA512, 100 000 iterations, 16-byte salt = 4×uint32, then
base64(salt) + ":" + base64(hash) as the raw value):
import base64, hashlib, os
salt = os.urandom(16)
h = hashlib.pbkdf2_hmac("sha512", password.encode(), salt, 100000, 64)
val = (base64.b64encode(salt) + b":" + base64.b64encode(h)).decode()
# with the container STOPPED, in [Preferences]:
# WebUI\Username=admin
# WebUI\Password_PBKDF2=<val>
Then podman start qbittorrent and confirm login survives a
podman restart — the temp-password rotation stops the moment stored
credentials verify. The chosen value lives host-local in /home/dank/.qbpass
(mode 600, owner dank) — never in git; every arr download client and
Prowlarr reference it. (The classic @ByteArray(salt+hash) form is WRONG
for qb5: login 401s on it; verify() base64-decodes the two halves separately.)
Deployment (current)
Quadlet unit qbittorrent.container from this repo
(frankbook-pro/qbittorrent/quadlet/), installed inside the podman machine at
/home/core/.config/containers/systemd/qbittorrent.service by the
frankbook-pro handler in scripts/deploy-remote.sh:
[Container]
ContainerName=qbittorrent
Image=lscr.io/linuxserver/qbittorrent:4.6.7
Network=gluetun.container
Environment=PUID=0
Environment=PGID=0
Environment=TZ=America/Los_Angeles
Environment=UMASK_SET=022
Volume=/Volumes/COMPLETE/qbittorrent-data:/config
Volume=/Volumes/COMPLETE:/Volumes/COMPLETE
Volume=/Volumes/INCOMPLETE:/Volumes/INCOMPLETE
[Service]
TimeoutStartSec=900
Restart=always
Gotchas (verified live)
- Temporary-password rotation on every boot is the default state of an untouched qb5 — see the persistence recipe above; without it, all arr download clients silently fail queue adds ("Couldn't add release … to download queue" in the arr logs) after any restart.
- API login from
curlneeds aReferer: http://<host>:<port>/header (CSRF protection) or POSTs get rejected even with a valid SID. - Cookie-name quirk by version: qB 5.x names its WebUI session cookie
QBT_SID_<port>; 4.6.7 uses plainSID. Any automation must parse the cookie generically (e.g.grep -oE '[A-Za-z_]*SID[A-Za-z0-9_]*=[^;[:space:]]*') instead of hard-coding a port-suffixed name, or it fails with 403 cascades that never reach qB as failed logins. - Egress verification for this stack must run inside the gluetun container
(
podman exec gluetun wget -qO- https://ipinfo.io/json); running the same probe one ssh-context out returns the residential IP — a false leak alarm. - Ensure umask is set to
022so downloaded files are readable by arr apps.