qBit Tracker Safety — How Classification Works
How Classification Works¶
BEP 27 — The Private Flag¶
BEP 27 (Private Torrents) is the BitTorrent standard that defines how private tracker content is marked. Private tracker software (Gazelle, Ocelot, UNIT3D — the frameworks powering virtually every reputable private tracker) sets a single field in each .torrent file's info dict:
info:
private: 1
The spec says clients MUST ONLY announce to the private tracker and MUST ONLY connect to peers returned by it — no DHT, no PEX, no LSD. This flag is how private trackers protect their swarms; every modern BitTorrent client honors it.
Two properties make it extremely reliable for our purposes:
- Part of the info-hash. Removing or modifying the flag changes the torrent's identity — the resulting torrent can no longer cross-seed with the original. There's no way to "strip" it without breaking the torrent.
- Set by default in major tracker software. Gazelle source code adds it automatically on upload (
"add private tracker flag and sort info dictionary"). UNIT3D and Ocelot do the same. Even semi-private trackers (open registration) set it, per the installgentoo wiki definition.
qBittorrent 5.0+ exposes the flag directly via its WebUI API as torrent.private. That's our ground truth.
Why not rely on Prowlarr metadata alone?
Prowlarr's privacy field is indexer metadata — it describes the tracker, not the torrent. It's also unreliable for our purposes:
- Bitmagnet is flagged
privatein Prowlarr because it's a local torznab endpoint, but every torrent it serves is public DHT content - Manual magnet imports bypass Prowlarr entirely
- Prowlarr definitions are community-maintained and can lag reality
- A private tracker added to Prowlarr after you've been using it leaves existing torrents misclassified
BEP 27 travels with the torrent file itself, so none of these edge cases matter.
The Two-Gate Safety Stack¶
BEP 27 alone covers the overwhelming majority of cases, but a belt-and-suspenders design closes the remaining gaps. Every torrent is classified using two gates in sequence, with a final cleanup pass for previously-misclassified torrents:
Two-gate classification with cleanup. BEP 27 catches nearly everything; the hostname blocklist is pure safety net.
Gate 1 — BEP 27 flag (primary)
If torrent.private == True, it's private. No injection. Reason logged as bep27.
Gate 2 — Hostname blocklist (safety net)
The script queries Prowlarr's API at runtime for every indexer with privacy == "private" and extracts hostnames from their URLs. If any of the torrent's announce URLs match a hostname in this list, it's private regardless of BEP 27. Reason logged as hostname.
This gate exists for two edge cases:
- Amateur or homebrew trackers that forgot to set the BEP 27 flag
- Alternate announce hostnames that differ from the indexer URL (TorrentLeech's site is
torrentleech.orgbut its announce istleechreload.org)
Manual Overrides¶
A small overrides file handles two final edge cases that auto-sync can't cover:
| Syntax | Meaning | Example |
|---|---|---|
hostname.tld |
Add to blocklist (treat as private) | tleechreload.org — TL's alt announce host |
-hostname.tld |
Remove from blocklist (Prowlarr false-positive) | -bitmagnet — serves public DHT despite private flag |
The final blocklist is: (Prowlarr private indexers ∪ manual additions) − manual exclusions.
Reclassification Cleanup¶
The trickiest edge case: what if a torrent was classified public earlier (and got trackerslist injected), but has since been reclassified private? The tags flip, but the previously-injected trackers are still attached — a leak.
The script handles this by checking every torrent classified private for attached trackers that match the current trackerslist, and calling qBittorrent's removeTrackers API to strip them. This makes classification bidirectional: public→private transitions undo prior injection.
Fail-Safe Behavior¶
If the script can't reach Prowlarr, it refuses to run rather than proceeding with a stale blocklist. A missed injection sweep is harmless — misclassifying a private torrent as public is not. This matters most when you've just added a new private indexer to Prowlarr: if Prowlarr is briefly unreachable at 4 AM, the script skips that run cleanly.
Coverage matrix
| Scenario | Gate that catches it |
|---|---|
| Mainstream private tracker (TorrentLeech, seedpool, etc.) | BEP 27 ✅ |
| Manual magnet from an unknown private tracker | BEP 27 ✅ |
| Amateur tracker missing BEP 27 but in Prowlarr | Hostname ✅ |
| Private tracker using alternate announce host | Manual override ✅ |
| Previously-public torrent reclassified private | Reclassification cleanup ✅ |
| Bitmagnet (Prowlarr flags private, content is public) | Manual exclusion (-bitmagnet) ✅ |
TL;DR
BEP 27's private flag, exposed by qBittorrent 5.0+ as torrent.private, is the reliable ground-truth signal for "is this a private torrent". A Prowlarr-synced hostname blocklist catches the rare cases where BEP 27 is missing. A small overrides file handles alt-hosts and false-positives. Reclassification cleanup strips any leaked public trackers from torrents now flagged private. The script refuses to run if Prowlarr is unreachable.
Previous: ← The Problem Next: Setup →