banner
约 5,400 字
18 分钟

OpenList + qBittorrent 离线下载教程:部署、对接与 Tracker 自动更新

OpenList + qBittorrent 离线下载教程:部署、对接与 Tracker 自动更新

摘要

OpenList 聚合存储并投递磁力任务,qBittorrent 负责下载与 Tracker 订阅。含可复制 Compose、初始密码获取、qB 对接字段与 5.0+ Tracker 自动更新。

OpenList + qBittorrent 离线下载教程:部署、对接与 Tracker 自动更新

这套组合的价值只有一句话:你只管在网页上贴磁力链接,剩下的连接、下载、找种子、入库,全自动。 但要先厘清一件事:Tracker 列表不归 OpenList 管。OpenList 只负责把任务投递出去;连接 peer、订阅与维护 Tracker,全部在 qBittorrent 一侧完成。

下面从分工讲到部署,再到 qB 侧的 Tracker 自动订阅。

OpenList 面板:左侧存储挂载树 + 右侧文件列表,这里是所有下载任务的中转站
OpenList 面板:左侧存储挂载树 + 右侧文件列表,这里是所有下载任务的中转站

一、先看清分工:谁下载,谁索引

这两个软件经常被放在一起讲,但职责完全不同,混着理解就会配错。

角色

它做什么

它不做什么

OpenList

把本地磁盘、网盘、WebDAV、S3 等几十种存储挂到同一个网页文件列表下;接收磁力/种子/HTTP 链接,转交给后端下载器;下完后把文件转存到你指定的存储

不建立 P2P 连接、不连 peer、不维护 Tracker

qBittorrent

实际建立连接、下载、做种,以及订阅并自动更新公共 Tracker 列表

不关心文件最终落进哪个网盘

那它们凭什么能串起来?因为 OpenList 是通过 qBittorrent 的 WebUI API 投递任务的,源码里写得很直白:登录 qB WebUI 后,用 torrents/add 接口把链接、保存路径、标签一起递过去,标签固定为 openlist-<任务ID>,方便回头定位和清理。

所以整条链路是这样的:

纯文本
你在 OpenList 网页上贴一个磁力链接

OpenList 通过 WebUI API 把任务丢给 qBittorrent(带上保存路径)

qBittorrent 向 Tracker 询问「谁有这个文件」,连上 peer 开始下载

文件落到双方共享的目录

OpenList 把它转存到你选的目标存储(本地 / 阿里云盘 / OneDrive …)

关键推论:那个共享目录必须在两个容器里路径完全一致。原因下一节讲。

OpenList 能把任务交给哪些下载器

它不止支持 qBittorrent。完整清单(源码 internal/offline_download/ 下逐个实现):

  • 本地下载器:qBittorrent、aria2、Transmission、SimpleHttp(普通 HTTP 直链)

  • 网盘自带离线:115、115 Open、123Pan、123 Open、PikPak、光鸭云盘

  • 迅雷系:Thunder、ThunderX、ThunderBrowser

也就是说,如果你本来就有 115 会员或 PikPak,直接用它们自带的离线下载往往比自建 qB 更快——服务端带宽和已有缓存都在那儿。自建 qB 的优势是:不依赖任何会员、可控、能跑私有 Tracker、文件直接落到你自己的盘里。

二、准备:目录规划与端口

先想清楚数据放哪。下面这个结构一路能用:

bash
mkdir -p ~/openlist-stack/{openlist,qbit/config,shared,downloads}
cd ~/openlist-stack
纯文本
openlist-stack/
├── openlist/          # OpenList 的全部数据:数据库、配置、索引
├── qbit/config/       # qBittorrent 的配置与种子状态
├── shared/            # 【关键】两个容器共用的下载中转目录
└── downloads/         # 文件的最终去处,挂进 OpenList 当普通存储用

端口规划:

端口

用途

是否必须

5244

OpenList 面板(HTTP)

必须

8080

qBittorrent WebUI

必须

6881 TCP + UDP

BT 监听端口,peer 连接与 DHT

强烈建议开放

6881 不是「能通就行」的可选项。它不通,你就只能主动连别人,别人连不上你——在只有少量种子的资源上,这直接决定下不下的动。有条件就做端口映射,并把 qB 的「使用 UPnP / NAT-PMP 端口转发」打开。

OpenList 镜像还暴露了 524552465246 是内置 S3 服务端口(默认关闭),5245 镜像里有 EXPOSE 但默认 compose 用不到。两个都不需要映射到公网,本方案里直接忽略。

三、docker-compose.yml:可直接复制

YAML
services:
  openlist:
    image: openlistteam/openlist:latest
    container_name: openlist
    user: '0:0'
    environment:
      - UMASK=022
      - TZ=Asia/Shanghai
      # 想跳过网页安装向导就填这一行,它会自动建 admin 账号
      - OPENLIST_ADMIN_PASSWORD=改成你的密码
    volumes:
      - ./openlist:/opt/openlist/data
      - ./shared:/opt/openlist/data/temp
      - ./downloads:/opt/openlist/data/downloads
    ports:
      - '5244:5244'
    restart: unless-stopped

  qbittorrent:
    image: lscr.io/linuxserver/qbittorrent:latest
    container_name: qbittorrent
    environment:
      - PUID=0
      - PGID=0
      - TZ=Asia/Shanghai
      - WEBUI_PORT=8080
    volumes:
      - ./qbit/config:/config
      # 注意:容器内路径必须和上面 OpenList 的临时目录一模一样
      - ./shared:/opt/openlist/data/temp
    ports:
      - '8080:8080'
      - '6881:6881'
      - '6881:6881/udp'
    restart: unless-stopped

三处必须理解的细节

1. 两个容器挂的是同一个宿主目录,容器内路径也写成一样

看这两行:

YAML
# OpenList
- ./shared:/opt/openlist/data/temp
# qBittorrent
- ./shared:/opt/openlist/data/temp

宿主目录都是 ~/openlist-stack/shared,容器内路径都是 /opt/openlist/data/temp

为什么路径必须一致?因为 OpenList 调 qB 接口时会把自己视角的路径原样传过去当作保存路径。如果 qB 这边挂成 /downloads,它就会老老实实往容器内的 /downloads 写,而那个目录 OpenList 根本看不见——任务显示下载完成 100%,OpenList 却找不到文件,转存这一步永久卡住。

2. user: '0:0'UMASK=022 别删

这是官方 compose 里的原样参数。OpenList 官方镜像默认以 root 运行、用 022 掩码建文件。改成普通用户容易和 qB 那边(LSIO 镜像用 PUID/PGID)产生权限打架,下下来的文件 OpenList 读不动。两边都跑 root 最省事,代价是宿主机上 shared/ 里的文件属主是 root。局域网自用没问题,多用户服务器要自己权衡。

3. OpenList 容器里访问 qB,不能用 localhost

这点在第五节展开,但它是最常见的「配置看起来全对就是连不上」。

四、首次启动:OpenList 的安装向导

先起容器:

bash
docker compose up -d
docker compose ps

两个都 running 后,先把初始密码捞出来,这一步别跳过:

bash
docker compose logs openlist | grep -i "initial password"

你会看到这样一行:

纯文本
Successfully created the admin user and the initial password is: fjN3vhjr

账号固定是 admin,密码是程序随机生成的 8 位字符串。这行只在第一次创建管理员时打印一次——数据卷里已经有管理员了就不会再出现,所以首次部署时务必先记下来。没抓到的用完整日志再翻一遍:

bash
docker compose logs openlist | head -40

浏览器打开 http://你的IP:5244,用 admin + 那串密码登录。

想固定密码:加一个环境变量

每次重装都要捞一遍随机密码很烦,尤其是数据卷不小心删掉的时候。在 compose 里加一行就彻底免掉:

YAML
environment:
  - OPENLIST_ADMIN_PASSWORD=你的密码

注意它只在「首次创建管理员」时生效。 数据卷里已经有 admin 了,改这行不会覆盖旧密码——这种情况下要用下面的命令。

忘了密码怎么办

不用重装,命令行直接改:

bash
docker exec -it openlist ./openlist admin set 新密码

# 或者让它随机生成一个
docker exec -it openlist ./openlist admin random

执行成功会回显:

纯文本
admin user has been updated:
username: admin
password: 你设的密码

openlist admin 不带参数则会打印当前管理员用户名和所有可用子命令。密码在数据库里存的是哈希值,取不回来,只能重置

qBittorrent 这边

打开 http://你的IP:8080。linuxserver 镜像的默认账号是 admin,密码有两种可能:

  • 老版本是 adminadmin

  • 新版本首次启动会随机生成,要看容器日志

bash
docker compose logs qbittorrent | grep -i "password"

看到类似 The WebUI administrator password was not set. A temporary password is provided for this session: xxxxxxxx 就对了。登录后第一件事是进「设置 → WebUI」把它改成你自己的固定密码,否则重启后临时密码又变。

五、把 qBittorrent 接进 OpenList

现在做对接。路径:OpenList 面板 管理 → 设置 → 其他。往下翻就能看到三组下载器配置,排在离线下载区最前面:

纯文本
Aria2          →  Aria2 地址 / Aria2 密钥
qBittorrent    →  qBittorrent URL / qBittorrent 做种时间
Transmission   →  Transmission URI / Transmission 做种时间

找到 qBittorrent 那一组,填两个值:

字段

填什么

说明

qBittorrent URL

http://admin:你的密码@qbittorrent:8080/

用户名密码写在 URL 里,格式 http://用户:密码@主机:端口/

qBittorrent 做种时间

0N

单位是分钟,0 表示不做种

系统里的默认值是 http://admin:adminadmin@localhost:8080/直接留着会连不上,原因有两个:

坑一:主机名不能用 localhost OpenList 和 qB 是两个独立容器,localhost 在 OpenList 容器里指的是 OpenList 自己,8080 那个端口上什么都没有。要用 compose 里的服务名——上面 compose 写的是 qbittorrent,这里就填 qbittorrent

纯文本
http://admin:你的密码@qbittorrent:8080/

Docker Compose 默认会创建一个内部网络,服务名就是 DNS 名,直接可用。这也是不需要配置自定义 network 的原因,别再手动建 openlist-net 了。

坑二:密码里有特殊字符要转义。 @:/# 这类字符出现在密码里,URL 会被解析错位。最省事的做法:给 qB 单独设一个只有字母数字的 WebUI 密码,或者换用不带认证的内网访问(不推荐)。

填完保存,OpenList 会立刻用它去登录 qB WebUI 验证。填对了没有明显提示,填错了会在保存时报错——所以要用一个「能连」的信号来验证,方法是随便建一个本地存储挂载点,然后在文件列表里点「离线下载」,看能不能正常提交任务。

走一遍完整流程

  1. 先加一个存储,作为文件的最终去处:OpenList 面板左侧 存储 → 添加,驱动选 本机存储根文件夹路径/opt/openlist/data/downloads挂载路径起名 /downloads,保存

  2. 回到文件列表,进 /downloads,点工具栏的 离线下载 按钮

  3. 贴一个磁力链接,下载器选 qBittorrent,提交

  4. 切到 OpenList 的 任务 页面,能看到任务在跑,状态列会显示 [qBittorrent] downloading

  5. 同时打开 qB WebUI,任务列表里应该出现同一个种子,带 openlist- 开头的标签

第 5 步是关键验证点。qB 里能看到任务 = 对接成功;只有 OpenList 有任务、qB 里空着,就是 URL 没配通。

任务下载完之后,OpenList 会把它从临时目录转存(移动)到 /downloads,然后删掉临时副本。所以文件最终落到哪里,是在提交离线任务时选的那个目录决定的,不是 qB。

别往临时目录里放东西

上面那个共享目录(/opt/openlist/data/temp)是 OpenList 的工作区,它有一个会主动清空自己的行为,值得单独说一句。

OpenList 在每次启动时会做一次判断:如果没有任何「待转存」的离线任务,就把整个临时目录清空。源码里就是一句:

Go
if len(tool.TransferTaskManager.GetAll()) == 0 { // prevent offline downloaded files from being deleted
    CleanTempDir()
}

两个直接后果:

  1. 下载还没完成时不要重启 OpenList。 正在下载的文件就在这个临时目录里,重启时若没有待转存任务,它们会被一并删掉。

  2. 不要把想长期保留的文件放进这个目录。 它只适合做「下载中转」——任务转存走之后空着,正是它的正常状态。

这也是上面验证流程里,我们看的是 qB 的任务列表而不是 OpenList 文件列表的原因:临时目录随时可能是空的。 如果你确实想让 qB 的下载目录和 OpenList 的临时目录分开,可以给 OpenList 加一个环境变量 TEMP_DIR=/opt/openlist/data/dl,然后把 qB 也挂到 /opt/openlist/data/dl。注意:容器内路径仍然必须两边保持一致,上一条规则不因换目录而改变。

六、让 Tracker 自动更新:qBittorrent 5.0 及以上

这是整套配置里最容易配错、也最值得配对的一环。好在答案很干净:qBittorrent 自己就能订阅 Tracker 列表,不需要任何外部脚本或共享文件。

前提是 qBittorrent v5.0 或更新版本。先确认版本:

bash
docker exec qbittorrent qbittorrent-nox --version
# 或者直接看 WebUI 右下角

v5.0 及以上的操作:

  1. 打开 qB WebUI → 工具 → 选项(工具栏上那个扳手/齿轮图标)

  2. 切到 BitTorrent 标签页

  3. 往下找到这两组选项,认准带 from URL 的那一组

  4. 勾选它,在 URL: 框里填订阅地址

  5. 应用 / 保存,然后重启 qBittorrent

qBittorrent 的 BitTorrent 选项页:上面是不带 URL 的静态列表,下面勾选的是「Automatically append trackers from URL to new downloads」
qBittorrent 的 BitTorrent 选项页:上面是不带 URL 的静态列表,下面勾选的是「Automatically append trackers from URL to new downloads」
bash
docker compose restart qbittorrent

重启这一步不能省。qB 是在启动时去拉列表的,保存后不重启,列表不会立刻生效,你会以为配置失败了。

两组选项别搞混

BitTorrent 页上相邻的两组开关长得几乎一样,但行为完全不同:

界面文字

对应的配置键

实际行为

Automatically append these trackers to new downloads:

add_trackers

把你粘贴进去的文本原样追加到新任务。它不会去请求任何地址

Automatically append trackers from URL to new downloads:

add_trackers_url

订阅。qB 自己去下载这个地址的内容,并持续更新

要勾的是第二组(带 from URL 的那个)。 把订阅地址填进第一组的输入框是没用的——它只当普通文本处理,不会去下载。

第二组勾上、地址填好之后,下面还有一个只读的区域 Fetched trackers,显示的是 qB 实际拉取回来的内容

  • 框里有内容 → 订阅生效

  • 框里空着 → 没拉到(先排查容器能不能访问那个域名)

这比去任务详情里一个个数 Tracker 快得多,配完顺手看一眼就行。

七、Tracker 列表从哪来

推荐 XIU2/TrackersListCollection(GPL-3.0,每日更新,三万两千多 star)。它提供四个列表,按需选一个:

列表

订阅地址

条数

什么时候用

BEST

https://cf.trackerslist.com/best.txt

71

首选,人工筛过的高可用节点

ALL

https://cf.trackerslist.com/all.txt

120

冷门资源,追求覆盖度

HTTP(S)

https://cf.trackerslist.com/http.txt

49

运营商封 UDP 时的备选

No HTTP

https://cf.trackerslist.com/nohttp.txt

70

纯 UDP,减少明文流量特征

直接填进上一节那个 URL: 输入框即可,比如:

纯文本
https://cf.trackerslist.com/best.txt

国内访问 cf.trackerslist.com 不通时,用备用地址(把文件名换成你要的那个):

纯文本
https://cdn.jsdelivr.net/gh/XIU2/TrackersListCollection/best.txt
https://fastly.jsdelivr.net/gh/XIU2/TrackersListCollection/best.txt
https://gcore.jsdelivr.net/gh/XIU2/TrackersListCollection/best.txt
https://raw.githubusercontent.com/XIU2/TrackersListCollection/master/best.txt

另一个老牌项目 ngosang/trackerslist(五万五千多 star)也在持续更新,格式兼容,可以互为备份。

加多少合适

不要贪多。 官方 FAQ 的建议是挑 10–30 个稳定的就够,其他全交给 DHT 和 Peer 交换。往几百个 Tracker 上刷 announce 只会增加无效流量,速度并不会更好——Tracker 的作用是「把人找齐」,不是凭空变出带宽。真正决定速度的是做种人数,冷门资源没有做种者,配什么列表都下不动。

八、v5.0 以下:手动粘贴

如果你的 qB 版本低于 5.0,界面上没有 from URL 那一组,只能用静态方式:

  1. 用浏览器打开 https://cf.trackerslist.com/best.txt全选复制

  2. qB → 工具 → 选项 → BitTorrent

  3. 勾选 Automatically append these trackers to new downloads:,把内容粘贴进下方文本框

  4. 应用保存,重启

粘贴前先清空文本框里原有的内容,新旧混在一起会出现格式错误,反而一个都连不上。

这种方式的缺点很明显:列表是死的,TrackersListCollection 每天都在更新,你得自己去重新复制一遍。能用容器就别省这一步——把镜像 tag 改成 latest 再拉一次,几分钟就能升到 5.x,然后自动订阅就通了。

九、验证 Tracker 是不是真的在工作

配完不要只看「设置里填了」,要实际验证。三个检查点,从易到难:

1. 看任务详情里的 Tracker 列表。 随便加一个热门种子(比如 Ubuntu 官方镜像的 torrent),双击任务 → Tracker 标签页。应该能看到一长串条目,状态列有 工作中 / Working。全是 未工作 / Not working 说明列表没拉到。

2. 看 peer 数量。 同一个任务切到 Peers 标签页,热门资源在几分钟内应该能连上几十个。同时开 DHT(默认开启)和 Peer 交换(PeX),三者叠加效果最好,别只依赖 Tracker。

3. 重启之后再看一次。 这一步专门验证「会不会丢」:

bash
docker compose restart qbittorrent

容器回来后,重新打开 选项 → BitTorrent,看 Fetched trackers 框里是不是还有内容。有,说明订阅已经落到配置里、每次启动都会自己去拉,而不是只在当前这次会话里有效。

如果订阅地址明明填了、Fetched trackers 却一直空着,多半是容器访问不了那个域名——cf.trackerslist.com 在国内网络下时通时不通。换成第七节里的 jsDelivr 备用地址,重启容器再试。

十、qB WebUI 的远程访问与反向代理

局域网自用,这一节可以跳过。要在公网上用,有两件事必须做对。

第一,改掉默认端口和密码,别裸奔。 qB 的 WebUI 只有一层账号密码,暴露在公网上就是被扫。至少:改掉 8080、设强密码、在 qB 设置里勾选 「对本地主机以外的连接启用 Host header 校验」(防 DNS 重绑定)。

第二,反代必须传对 Host 头。 这是 qB 反代最容易出错的地方。它默认会校验请求的 Host,Nginx 如果不把原始 Host 透传过去,你会看到 Unauthorized 或者白屏。

Nginx 配置要点:

nginx
location / {
    proxy_pass http://127.0.0.1:8080;
    proxy_set_header Host $http_host;      # 关键:传完整 Host,含端口
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;
}

注意是 $http_host含客户端请求的端口),不是 $host(只有域名)。如果你不是挂在 443 标准端口上,用 $host 会让 qB 校验失败。

反代做通之后,记得在 qB 设置里把「WebUI → 外部域名」填上你的域名,否则部分功能(比如种子下载链接)会返回内网地址。

十一、常见问题排查

Q:OpenList 任务一直卡在「等待中」,qB 里什么都没有。

对接没通。按顺序查:① URL 里是不是写了 localhost(要用服务名 qbittorrent);② 密码里有没有 @ / # 这类字符;③ qB 的 WebUI 密码是不是被改过而 OpenList 没同步。确认容器之间能通:

bash
docker exec -it openlist ping -c 2 qbittorrent

Q:任务下到 100%,OpenList 却报「文件不存在」。

共享目录路径不一致。两个容器的挂载点必须都是 /opt/openlist/data/temp。回头检查 compose 里 qB 那行有没有写成 /downloads

Q:速度只有几十 KB。

按这个顺序排查:先去任务详情看 Tracker 列表和 peers 数量——先确认是「找不到人」还是「找到了但传不动」。前者查 Tracker(第六节),后者查端口:6881 的 TCP 和 UDP 有没有映射出去。没有公网 IP 的话,优先想办法上 IPv6,上传速度会好很多。

Q:OpenList 里下载完的文件不见了。

正常现象。OpenList 会把临时文件转存到你选的目标存储后删除本地副本。去你提交任务时选的那个目录里找。

Q:重启容器后 OpenList 又要我重新配置。

数据卷没挂对。/opt/openlist/data 必须挂到宿主机的持久目录上(./openlist),它装着数据库 data.db 和全部配置。

Q:qB 密码每次重启都变。

linuxserver 镜像首次启动给的是临时密码,登录后必须自己改。改完写进 /config(已经持久化了),下次就不会变。

十二、安全与合规

最后几句必须说。

这套东西是自用工具,不要做成公开服务。 一个暴露在公网的 qB WebUI,等于把机器的磁盘和带宽交出去;一个开放注册的 OpenList,等于帮别人存文件。两者都做过反向代理的话,至少加上访问控制(Cloudflare Access、Nginx Basic Auth、只允许内网 IP)。

关于离线下载的内容本身。 BT 协议中立,但资源不是。Tracker 列表只负责帮你「找到更多人」,它不会也不能判断你下的是什么。请只下载你有权获取的资源,遵守所在地的法律法规与版权规定。公开 Tracker 名单里也可能混入恶意或被投毒的节点,不要用它去下需要账号凭据的私有种子——私有 Tracker 有自己的 tracker,混入公共列表轻则被 ban,重则牵连账号。

权限最小化。 上面 compose 里两个容器都跑 root,是为了让文件权限不打架。如果你的机器还有别的服务,建议新建一个专用用户(把 user: '0:0' 改成 user: '1000:1000'PUID/PGID 改成 1000),并把 shared/ 目录的属主改掉,避免容器有权限动到不该动的地方。

十三、写在最后

把这件事拆开看,会发现真正难的地方一个都不在「装」。

OpenList 已经帮你解决了「几十种存储怎么统一成一个界面」这个最麻烦的问题;qBittorrent 从 5.0 起也把 Tracker 维护这件事内置了。你要做的,其实只有三件:

  1. 路径对齐——让两个容器看见同一个目录,而且叫同一个名字

  2. 网络对齐——OpenList 用服务名找 qB,qB 用 $http_host 被别人找到

  3. 别用过时的做法——放弃「共享文本文件 + 定时脚本」那套,订阅一个每天更新的 URL 就够了

剩下的就是等。Tracker 的作用是把你和做种的人连上,它不会凭空造出速度;冷门资源下不动的时候,与其反复换列表,不如换个源。

这套组合我会一直放在 NAS 上跑着。它最大的价值不是快,是不用管——贴链接、关网页、第二天文件已经在盘里了。

END