qBittorrent v5 → v4.6.5 降级:Python HOME 环境变量 bug

2026-07-14

引子

用 Docker 部署 qBittorrent,第一件事通常是去 WebUI 装搜索插件。结果 v5.x 的搜索页面要么是空的,要么点「安装」毫无反应——这个问题我花了接近两天才彻底搞清楚,中间绕了好几个弯。

如果你遇到的是完全不同的错误(比如无法启动或下载任务 error),本文不适用。但如果你也是 Docker 部署的 qBittorrent 并且搜索插件用不了,尤其是日志里有 ImportError: No module named parseIndentationErrorNameError: name '__file__' is not defined 之类的东西,那大概率跟我是同一个坑。

报了什么

搜索插件装不上,WebUI 点安装无反应,插件列表始终为空。翻日志能看到这样的输出:

Could not parse Nova search engine capabilities, msg:
Error: Traceback (most recent call last):
  File "/config/qBittorrent/nova3/nova2.py", line X, in <module>
    import urllib.parse
ImportError: No module named parse

urllib.parse 是 Python 3 标准库的模块,不存在「找不到」的可能——问题不在代码本身,而在 Python 是怎么被调用的。还有其他报错混在一起出现:

IndentationError: unexpected indent
NameError: name '__file__' is not defined

这几个错误指向一个方向:Python 没有正常运行一个 .py 文件,而是进入了一个奇怪的执行模式。

定位:从日志到环境变量

先从最简单的入手:看看容器里 Python 能不能正常工作。

docker exec qbittorrent python3 --version
# 能正常输出版本号

试着运行搜索插件脚本本身:

# 直接运行
docker exec qbittorrent /usr/bin/python3 \
  /config/qBittorrent/nova3/nova2.py --capabilities
# 正常输出,没有报错

这就矛盾了——手动执行没问题,qBittorrent 内部调用就出错。说明 qBittorrent 调用 Python 的方式和手动执行不一样。qBittorrent 内部用 QProcess 启动 Python,关键区别在于当前工作目录环境变量

查一下环境变量:

docker exec qbittorrent env | grep HOME
# HOME=/config

HOME=/config。linuxserver 系列镜像有个常见做法:把 HOME 设为 /config 以方便配置文件挂载。大部分情况下这无害,但对 Python 3.12+ 有问题。

验证一下:

# 在 HOME=/config 下执行 Python
docker exec qbittorrent sh -c "cd /config && python3 -c \"print('hello')\""
# >>>   ← 直接进了交互模式!

docker exec qbittorrent sh -c "cd /tmp && python3 -c \"print('hello')\""
# hello  ← 正常输出

确认了:只要工作目录在 /config(即 HOME 目录)下,Python 3.12+ 会强制进入交互模式,导致脚本执行一半就卡住。

根因:Python 3.12 的 site.py 做了什么

Python 3.12 的 site.py 有一段新增的逻辑(PEP 668 相关):启动时检查当前工作目录是否在用户 HOME 下,如果在,尝试初始化用户站点包(~/.local 等)路径。如果该目录不存在或权限不对,Python fallback 到交互模式

在 linuxserver 的 qbittorrent 容器中:

  • HOME=/config
  • site.py 发现工作目录在 /config
  • 尝试访问 ~/.local/lib/python3.12/site-packages/——该路径不存在或不可写
  • fallback 到交互模式

qBittorrent 内部调用流程:

QProcess("python3 /config/qBittorrent/nova3/nova2.py --capabilities")
  → CWD 是 /(默认),但 /config/qBittorrent/nova3/nova2.py 的目录在 HOME 下
  → site.py 检测到路径在 HOME 中 → 交互模式
  → python3 启动后显示 >>> 等待输入
  → qBittorrent 等待 stdout 输出 → 超时 → "Could not parse"

这就是手动执行(指定 cwd)和 QProcess 执行(默认 cwd)行为不一致的根本原因。

各种尝试(全部失败)

为了不让你重复走弯路,这些方案我都验证过了:

方案 结果 原因
symlink nova3 到 /opt ❌ 手动执行 OK,qB 内部仍失败 QProcess 不跟随 symlink,Python 仍检测到路径在 HOME 下
设置 python_executable_path 配置项 ❌ 没影响 只指定 Python 二进制路径,不影响环境变量
清除 __pycache__ 重试 ❌ 无效 缓存不是根因
删除 nova3 目录让 qB 重新生成 ❌ 新建文件仍在 /config 下 问题在目录级,不在文件内容
--tmpfs /config/qBittorrent/nova3 ❓ 理论上可行,未验证 把 nova3 挂到 tmpfs 可能绕过检测,但破坏性大
修改 Dockerfile 重设 HOME ❓ 需要自定义镜像 脱离 linuxserver 官方支持范围

结论:v5.x 在 linuxserver 镜像上搜索插件不能用,且没有干净可靠的 workaround。

降级到 v4.6.5

第零步:备份种子

ssh root@<nas-ip> \
  "cp -r /path/to/qbittorrent/BT_backup /backup/qb_bt_backup"

第一步:停止并清理

ssh root@<nas-ip> "docker stop qbittorrent && docker rm qbittorrent"

config 目录可以清也可以不清——v4.x 能直接读取 v5 的配置,但如果要彻底干净,清掉也没问题:

ssh root@<nas-ip> "rm -rf /path/to/qbittorrent/config/*"

第二步:拉取 v4.6.5 镜像

# 如果需要代理
ssh root@<nas-ip> \
  "HTTP_PROXY=http://<proxy-ip>:<proxy-port> HTTPS_PROXY=http://<proxy-ip>:<proxy-port> \
  docker pull lscr.io/linuxserver/qbittorrent:4.6.5"

193MB 的镜像,速度看代理情况,快则几分钟,慢则半小时。

第三步:启动容器

ssh root@<nas-ip> "docker run -d --name qbittorrent \
  -e WEBUI_PORT=8080 -e PUID=99 -e PGID=100 -e TZ=Asia/Shanghai \
  -p 6881:6881 -p 6881:6881/udp -p 8085:8080 \
  -v /path/to/qbittorrent/config:/config \
  -v /path/to/downloads:/downloads \
  --restart unless-stopped \
  lscr.io/linuxserver/qbittorrent:4.6.5"

第四步:取临时密码 + 配置 Jackett 插件

# 获取临时密码
docker logs qbittorrent 2>&1 | grep -i 'temporary password'

# 登录并关闭 HostHeaderValidation
docker exec qbittorrent curl -s -c /tmp/c \
  -d 'username=admin&password=TEMPPWD' \
  'http://localhost:8080/api/v2/auth/login'

docker exec qbittorrent curl -s -b /tmp/c \
  'http://localhost:8080/api/v2/app/setPreferences' \
  -d 'json={"WebUI":{"HostHeaderValidation":false}}'

# 安装 Jackett 搜索插件
curl -s -b /tmp/qb \
  'http://<nas-ip>:8085/api/v2/search/installPlugin' \
  -d 'sources=https://raw.githubusercontent.com/qbittorrent/search-plugins/master/nova3/engines/jackett.py'

Jackett 的 URL 和 API Key 从 Jackett WebUI 右上角复制。

替代方案:Jackett Web UI

如果你不想降级,Jackett 本身有完整的 Web 搜索界面——直接在浏览器打开 Jackett 的端口(默认 9117),搜索、复制 magnet 链接、切回 qBittorrent 粘贴下载。少了「一键添加」的便利,但功能完整。

总结

这个 bug 的完整链路:

linuxserver 镜像 HOME=/config
  → Python 3.12 site.py 检测到工作目录在 HOME 下
  → 尝试初始化用户站点包失败
  → fallback 到交互模式
  → qBittorrent QProcess 调用 Python 进入 >>> 等待
  → nova2.py 不能正常解析
  → "Could not parse Nova search engine capabilities"

技术含量不算高,但层层嵌套的三个环节(Docker 镜像惯例 + Python 版本行为变化 + 内部进程调用方式)让你很难一眼看出根因。

另外说说什么时候该降级。通常不建议回退版本——安全更新和新功能都追不上。但这个情况的判断依据很简单:

  1. 根因在镜像环境,不在应用本身——换个环境就能正常工作的 bug,降级是合理的
  2. 没有其他 workaround——5 种尝试都失败,不需要继续死磕
  3. 功能差异明确——v4.x 和 v5.x 对 BT 下载这个核心功能没区别,差别只在搜索插件的实现方式
  4. v5.x 的新功能你用不上——如果 v5 没有你必须用的特性(比如 I2P 支持、新的 RSS 引擎等),降级零代价

回到最初的那句话:如果 v5 没有你非用不可的理由,v4.6.5 配合 Jackett 是目前 docker-qbittorrent 搜索功能最稳定的组合。

标签: 教程