qbit_manage¶
qbit_manage · Wiki · TRaSH: 3rd-party tools
qbit_manage is a housekeeping tool for qBittorrent. It runs on a schedule, talks to qBittorrent's Web API and can:
- set categories from the save path, or from the tracker a torrent came from,
- tag torrents by tracker, and tag ones with tracker errors, stalled downloads, or no hardlinks left in the library,
- apply share limits (ratio / seed time) per group of tags or categories,
- remove unregistered torrents and orphaned files (both off here),
- and, since v4, give you a web UI to edit the config and run commands on demand.
Container¶
From the stack compose:
qbit_manage:
container_name: qbit_manage
image: ghcr.io/stuffanthings/qbit_manage:v4.14.0 # pinned; v4 changed ports and config schema
volumes:
- ${APPDATA_PATH}/qbit_manage/:/config:rw
- ${MEDIA_DATA}:/data:rw
- ${APPDATA_PATH}/qbittorrent/config:/qbittorrent/:ro
ports:
- "8084:8080" # Web API/UI - host port 8084 because qBittorrent's web UI already has 8080
environment:
# Web API Configuration
- QBT_WEB_SERVER=true # enable the web API and web UI
- QBT_PORT=8080 # web port inside the container (upstream default: 8181)
# Scheduler Configuration
- QBT_RUN=false # false = keep running on the schedule
- QBT_SCHEDULE=2 # minutes between runs
- QBT_CONFIG_DIR=/config
- QBT_LOGFILE=qbit_manage.log
# Command Flags (all false here: the commands come from config.yml)
- QBT_RECHECK=false
- QBT_CAT_UPDATE=false
- QBT_TAG_UPDATE=false
- QBT_REM_UNREGISTERED=false
- QBT_REM_ORPHANED=false
- QBT_TAG_TRACKER_ERROR=false
- QBT_TAG_NOHARDLINKS=false
- QBT_SHARE_LIMITS=false
- QBT_SKIP_CLEANUP=false
- QBT_DRY_RUN=false
- QBT_STARTUP_DELAY=0
- QBT_SKIP_QB_VERSION_CHECK=false
- QBT_DEBUG=false
- QBT_TRACE=false
# Logging Configuration
- QBT_LOG_LEVEL=INFO
- QBT_LOG_SIZE=10
- QBT_LOG_COUNT=5
- QBT_DIVIDER==
- QBT_WIDTH=100
restart: on-failure:2
labels:
- autoheal=true
# No official healthcheck - its own web UI (enabled via QBT_WEB_SERVER above) responds on QBT_PORT
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8080/"]
interval: 30s
timeout: 10s
retries: 3
start_period: 30s
| Mount | Why |
|---|---|
/config |
config.yml (what to do), qbm_settings.yml (web UI security settings) and logs. |
/data |
Same path as qBittorrent's /data, so the paths qBittorrent reports exist here too. Needed for the no-hardlinks check and orphaned-file cleanup. |
/qbittorrent (read-only) |
qBittorrent's config folder, so qbit_manage can read the .torrent files in BT_backup (used when it saves torrents to the recycle bin). |
Not behind the VPN
qbit_manage only talks to qBittorrent's API, so it doesn't need to be inside Gluetun. It reaches qBittorrent at http://gluetun:8080, because that's where qBittorrent's API lives (qBittorrent shares Gluetun's network stack).
config.yml: the parts that matter¶
Copy config.yml.sample (created in /config on first start) to config.yml. Sanitized outline of mine:
commands: # overrides the QBT_* command flags above
cat_update: true
tag_update: true
tag_tracker_error: true
rem_unregistered: false
rem_orphaned: false
tag_nohardlinks: false
share_limits: false
recheck: false
dry_run: false
qbt:
host: http://gluetun:8080
user: <YOUR_USER>
pass: <YOUR_PASSWORD>
settings:
force_auto_tmm: true # turn on Automatic Torrent Management for every torrent
tracker_error_tag: issue
tag_stalled_torrents: true # stalledDL tag on stuck downloads
disable_qbt_default_share_limits: true
cat_filter_completed: true # only re-categorise finished torrents
directory:
root_dir: /data/torrents/complete # must be the same path qBittorrent uses
cat: # every save path in qBittorrent must be listed
movies: /data/torrents/complete/movies
tv: /data/torrents/complete/tv
Uncategorized:
- /data/torrents/complete
tracker: # keyword from the tracker URL -> tag (+ optional category)
tracker-a.example:
tag: TrackerA
cat: movies
tracker-b.example:
tag: TrackerB
other:
tag: other
recyclebin:
enabled: false
How it fits together:
commands:wins. Ifconfig.ymlhas acommands:section, qbit_manage uses it and ignores theQBT_*command flags in the environment. That's why every flag in the compose isfalse: the real choices are in the config file, where the web UI can change them.- Tracker → category. A
cat:on a tracker entry takes priority over the save-path mapping incat:. Together withforce_auto_tmm: true, qBittorrent then moves the torrent to that category's save path. That gives per-tracker folders without any scripting. - Every save path must be in
cat:. If qBittorrent has a save path that isn't listed, qbit_manage logs errors. UseUncategorizedfor paths that should stay without a category. other:undertracker:gives every unmatched tracker one shared tag, instead of an auto-created tag per tracker domain.- Destructive commands are off.
rem_unregistered,rem_orphanedandshare_limitsdelete or pause things. Turn them on one at a time, withdry_run: truefirst, and read the log.
Web UI and authentication¶
The web UI is at http://<YOUR_SERVER_IP>:8084. It's a visual editor for config.yml plus a "run now" button. It can't change environment variables.
Turn authentication on
qbit_manage's web UI defaults to no authentication, and it shows and edits your config, including the qBittorrent password. In the web UI's Security section, pick Basic authentication (username + password) and generate an API key for scripts (sent as an X-API-Key header). /api/health and /api/version stay public, which is fine for healthchecks. If you lock yourself out, set authentication.method: none in qbm_settings.yml and restart.
Gotchas¶
- Pin the version. v4 changed the default web port (8080 → 8181) and reworked the config schema. A floating
latestcan jump a major version and breakQBT_*parsing. Upgrade on purpose and read the v4 migration guide. - Port numbers. qbit_manage listens on
8080inside its container (set byQBT_PORT) and is published as8084, because qBittorrent's web UI already uses8080on the host. The healthcheck uses the inside port. - Restart policy vs. autoheal.
restart: on-failure:2only covers crashes (non-zero exit, at most twice). A container that hangs but keeps running is what theautoheal=truelabel is for. The catch: after a longdocker pause(a nightly SnapRAID sync, for example) autoheal sees it unhealthy and restarts it, and Docker has to kill it after the 10 s stop timeout. See Autoheal.