--- type: reference title: qBittorrent description: qBittorrent download client for the *arr stack — pinned 4.6.7 on FrankBook-Pro, shares the Gluetun WireGuard netns, PBKDF2 WebUI credential recipe. tags: [qbittorrent, arr-stack, frankbook-pro, gluetun] timestamp: 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): ```python 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= ``` 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`: ```ini [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 `curl` needs a `Referer: http://:/` 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_`; 4.6.7 uses plain `SID`. 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 `022` so downloaded files are readable by arr apps. ## See Also - [[ARR-Stack]] — full *arr stack documentation - [[Gluetun]] — the WireGuard tunnel this container shares