Repository navigation
Upgrading to 0.11
0.11.0 is a breaking release. A 0.10.x deployment that only changes its image tag won't come back up as it was: 0.11 no longer reads /config, and qBittorrent's "Run external program" line has changed. This page lists everything that changed since 0.10.x, then the steps. The details are on the pages it links.
Copy, don't move. Leave /config as it is until you're happy with 0.11: rolling back is then just the old image tag with the old mount (see Rolling back).
| 0.10.x | 0.11 | Notes |
|---|---|---|
/config/config.yml |
/etc/qbt-rules/config.yaml |
Renamed to .yaml. Optional (every setting has a variable). The directory can be read-only. A config.yml left there with no config.yaml is refused |
/config/rules.yml |
/var/lib/qbt-rules/rules.yml |
In the state directory, not /etc/qbt-rules: the dashboard's rules editor saves it, so it must be writable by PUID (mode 0644). A rules.yml left in /etc/qbt-rules, with none in the state directory, is refused |
/config/qbt-rules.db (+ -wal) |
/var/lib/qbt-rules/qbt-rules.db |
The job queue and history. In WAL mode: copy it with sqlite3 β¦ ".backup β¦", or as a file with the old container stopped |
/config/.history/ |
/var/lib/qbt-rules/.history/ |
The rules editor's backups, if you have any |
/config/qbt-rules.log |
(the console) | Not copied; see Logs |
There is no fallback to /config and nothing is copied into place on first start (0.10.x created a default rules.yml; 0.11 starts with no rules until you copy yours or the editor saves one). Mount /var/lib/qbt-rules as a directory, not file by file: SQLite's -wal/-shm files and the editor's .history/ are written beside the files. The full table, with the reasons, is in In-Depth Configuration.
The server refuses to start while any of these is left, and lists all of them in one error, each with its fix.
In config.yaml:
-
engine.dry_runis now a top-leveldry_run(the variableQBT_RULES_DRY_RUNis unchanged). - Every path under
/configis refused: deletelogging.file,queue.sqlite_pathand therules:block (rules.file). The defaults already point at the new places. -
server.workersother than1is refused: delete it (see One process). -
metrics.multiproc_diris refused: delete it. -
server.hostandserver.portstill work as deprecated aliases oflisten.hostandlisten.port, with a warning at startup. Rename them when convenient.
In the environment:
| 0.10.x | 0.11 |
|---|---|
QBT_RULES_<SECTION>_<FIELD> and β¦_FILE
|
Unchanged |
QBT_RULES_SERVER_PORT, QBT_RULES_SERVER_HOST
|
Deprecated aliases (a warning at startup). Use QBT_RULES_LISTEN_PORT and QBT_RULES_LISTEN_HOST: the image's healthcheck reads only QBT_RULES_LISTEN_PORT
|
CONFIG_DIR, QBT_RULES_CONFIG_DIR
|
Refused: remove them (QBT_RULES_CONFIG names another config file, QBT_RULES_STATE_DIR another state directory) |
QBT_RULES_LOG_LEVEL |
Refused: it was never a setting. Use QBT_RULES_LOGGING_LEVEL
|
QBT_RULES_METRICS_MULTIPROC_DIR, PROMETHEUS_MULTIPROC_DIR
|
Refused: remove them; QBT_RULES_METRICS_ENABLED alone turns /metrics on |
QBT_RULES_SERVER_WORKERS |
Must be 1: remove it |
The exact config.yaml diff a production 0.10.1 config needed is in In-Depth Configuration.
The image runs qbt-rules serve (its CMD). qbt-rules --serve is gone, with no alias. If you override the container's command, change it to serve, or drop the override.
The server is one uvicorn process with the worker and the scheduler as threads beside it. Gunicorn and its worker processes are gone, so server.workers is gone too. Jobs run strictly one at a time (0.10.x could run two at once). docker stop now stops it cleanly within a second; 0.10.x ignored SIGTERM and was killed after 10 seconds. Keep one replica: a second one would run every scheduled job twice. The probes are GET /healthz (liveness) and GET /readyz (readiness), on port 5000 by default; see Deployment.
The flags-only CLI is gone, with no alias: the command comes first (serve, execute, jobs list|status|cancel, stats, validate, rules list, config, version). The old form exits 2 and names the new command.
Update qBittorrent's "Run external program" (Tools β Options β Downloads):
# torrent added
qbt-rules execute --context torrent-imported --hash "%I"
# torrent finished
qbt-rules execute --context download-finished --hash "%I"With qBittorrent and qbt-rules in separate containers, run it in the qbt-rules container:
docker exec qbt-rules qbt-rules execute --context torrent-imported --hash "%I"Per-setting flags (--server-port, --log-level, β¦) are their QBT_RULES_* variables. Exit codes are 0 ok, 1 failure, 2 usage or configuration. The full old-to-new table is in CLI Reference; update any cron job or script that calls qbt-rules too.
Every timestamp in the JSON API is ISO 8601 in UTC (2026-01-15T10:30:00.123456+00:00), with either queue backend. With SQLite, 0.10.x sent RFC 822 dates (Thu, 15 Jan 2026 10:30:00 GMT): a script that parses them must accept ISO 8601. See HTTP API Reference.
The session cookie changed (qbt_rules_session), so a 0.10.x login isn't recognised: log in again with the API key. A ?key= on a dashboard URL now logs in and redirects to the same URL without the key, and the login form needs its CSRF token (a script posting to /login must load the form first). Links are relative, so the dashboard works behind a path prefix.
The log goes to the console only (docker logs, kubectl logs), not /config/qbt-rules.log. Set logging.file (QBT_RULES_LOGGING_FILE) to a path outside /config, such as /var/lib/qbt-rules/qbt-rules.log, to keep a rotated file as well. The old log stays in /config; delete it once you've upgraded.
queue.cleanup_after (default 7d) is now applied at startup and then hourly; 0.10.x never applied it. So the first start deletes every finished job older than that: on one production database, about 80% of the history. From 0.11.1 the database is vacuumed after a cleanup that removes a large share of the jobs, so the file shrinks too (0.11.0 left it, and its -wal file, at full size). To keep the history, set queue.cleanup_after higher, or 0, before the first start. The copy of the database left on /config is untouched.
-
Rules validation is stricter.
delete_torrentwithkeep_filesis an error (from 0.10.2): 0.10.x ignoredkeep_filesand deleted the files. Writedelete_files: true(what the rule has been doing) ordelete_files: false. The server still starts and runs such a rule as before, butqbt-rules validateexits 1 and the editor won't saverules.ymluntil it's fixed. -
Metrics.
/metricskeeps its names and labels; the content type istext/plain; version=0.0.4; charset=utf-8, and themetricsextra (prometheus_client) is gone. - Python 3.13 or later, for a non-container install.
-
Back up the old
/configdirectory (or volume). - Stop the 0.10.x container, so the database can be copied consistently.
-
Copy into two new directories, leaving
/configuntouched:-
config.ymlβ<config dir>/config.yaml, then edit it:engine.dry_runβdry_run; deletelogging.file,queue.sqlite_pathand therules:block; deleteserver.workers. -
rules.ymlβ<state dir>/rules.yml, mode0644, owned byPUID:PGID. -
qbt-rules.dbβ<state dir>/qbt-rules.db, withsqlite3 /config/qbt-rules.db ".backup <state dir>/qbt-rules.db"(orcp -pwith the old container stopped). -
.history/β<state dir>/.history/, if it exists.
-
-
Fix the environment: remove
CONFIG_DIR,QBT_RULES_CONFIG_DIR,QBT_RULES_LOG_LEVEL(useQBT_RULES_LOGGING_LEVEL) and the multiprocess variables; renameQBT_RULES_SERVER_PORTtoQBT_RULES_LISTEN_PORT. -
Mount
<config dir>at/etc/qbt-rules(read-only is fine) and<state dir>at/var/lib/qbt-rules(a writable directory), instead of/config. Drop any command override other thanserve. - Start the 0.11 image and check the log: no configuration errors, a deprecation warning for each alias still in use, and one "Cleaned up N old jobs" line.
-
Check:
docker exec qbt-rules qbt-rules validate,docker exec qbt-rules qbt-rules jobs list,GET /readyzanswers{"status":"ready"}, and log in to the dashboard again. - Update qBittorrent's "Run external program" line (see above).
Per platform:
-
Docker Compose: Deployment, with
./configand./statebeside the compose file. -
Unraid: the qbt-rules template now has two paths instead of
/config. Create two folders inside the old appdata folder, for example/mnt/user/appdata/qbt-rules/etcand/mnt/user/appdata/qbt-rules/state, copy the files into them as in step 3 (the old files stay where they are), and point the template's Config path atetcand its State path atstate. The container gives the state folder toPUID:PGID(99:100on Unraid) when it starts. -
Kubernetes: keep the old volume and mount it twice with
subPaths: a subdirectory holdingconfig.yamlat/etc/qbt-rules(read-only), and a subdirectory holdingrules.ymland the database at/var/lib/qbt-rules(a directory mount). An initContainer can do step 3, skipping each file that already exists. Switch the probes to HTTPGET /readyzand/healthzon port 5000.
Put the 0.10.x image tag back, with its old /config mount and command, and remove the 0.11 mounts. Because step 3 copied rather than moved, /config still holds the 0.10.x files as they were (the database without the jobs 0.11 ran). Rolling back from a later 0.11.x to 0.11.0 needs nothing but the tag.
0.11.2 reads schedule with interpose's list sections instead of its own loader. Nothing else in the configuration changes, ${VAR} expansion included. What you may notice:
-
A lone
QBT_RULES_SCHEDULE_<N>_CONTEXTstops the server. 0.11.1 ignored a_CONTEXTwith no_CRONbeside it; now the entry exists when either variable is set, and the missing one is an error naming both:schedule[1].cron: QBT_RULES_SCHEDULE_1_CRON is not set, but QBT_RULES_SCHEDULE_1_CONTEXT is. Set the_CRONor remove the_CONTEXT. -
New warnings at startup. A key in
config.yamlthat isn't a setting, aQBT_RULES_*variable that no setting reads, a misspelt field in a schedule entry, and a schedule variable past the end of the list (_3_CRONwith no_2_*) were ignored silently; they still are, but each is now logged as a warning, with the setting it probably meant.qbt-rules configandqbt-rules validateprint them too. -
Schedule errors read differently. They count entries from 0, as the variables do, and name the file or variable:
schedule[0].cron: a required field, not set (from /etc/qbt-rules/config.yaml)where 0.11.1 saidschedule entry #1 has no 'cron'. Anything that matched the old text needs updating. -
New:
QBT_RULES_SCHEDULE_FILEnames a YAML file holding the whole list (for a ConfigMap or secret mount). SettingQBT_RULES_SCHEDULEitself is an error saying to use it.
qbt-rules | A rules engine for qBittorrent automation, with a job queue, scheduler and web dashboard
GitHub β’ Container image β’ Releases β’ Issues β’ Discussions β’ Changelog β’ Contributing β’ License
Requirements: Docker β’ qBittorrent with Web UI enabled
Released into the public domain under the Unlicense
This wiki is generated from docs/wiki/ on every push to main: edits made here are overwritten. Change it with a pull request.
- Rules Architecture
- Contexts
- Conditions
- Actions
- Available Fields
- Reusable References
- HTTP API Reference
- CLI Reference
- Dashboard
- Metrics
- In-Depth Configuration
- Deployment
- Upgrading to 0.11
- Scheduling
- Examples
- Advanced Rules Example
- Advanced Topics
- π Client-server architecture (HTTP API + worker)
- π¦ Persistent job queue (SQLite or Redis)
- β»οΈ Reusable references (
$ref,${vars.x}) - π₯οΈ Web dashboard with a validating
rules.ymleditor - π³ Docker-first deployment