我的海外 BitTorrent 下载方案
前言
很多人都有看电影电视的经历抑或是习惯。囿于国内的言论环境,很多资源都无法正常引进,或者在引进的时候被删减。通过各类云盘流通的资源质量良莠不齐,而使用国外流媒体平台观看又会面对诸多限制和高昂成本的问题,对于我来说,直接食用国外通过 BitTorrent(BT)分享的生肉或者加上自行寻找配对的熟肉字幕更加具有实践性。然而,又一次苦于国内的网络连通性和网络封锁,国内下载 BT 的时候免不了有的资源没有速度、无法下载完全。这个时候,一个国外的网络环境不可或缺。
然而,绝大部分的国外网络资源,无论是私有专用网还是服务器,都会受到 DMCA 或者其他类型的版权投诉的影响,使 BT 下载不可持续。也有一部分的服务器位于独特的司法管辖内,能给予资源获取较高的自由度。这篇文章分享了我低成本和低门槛的海外 BT 下载和取回的解决方案。
读懂本文,你需要:
- 对 Linux 系统和其操作的基本了解
- 对 Nginx 的基本了解
- 对英文的掌握度
- 一个海外网络环境
本文方案的构成:
- 某主机商(见文末)位于比利时卢森堡的服务器,挂载缓存 HDD 硬盘(256GB @ 35MB/s),约 26¥/月
- qBitTorrent-Nox 及其 Web UI 作为 BT 下载器
- Nginx 作为反向代理前端、目录列举和用户鉴权的工具
- AList 作为目录列举和文件管理工具
本文的局限性:
- 没有涉及 PT(Private Tracker)的使用
- 使用一键服务器环境,牺牲了安全性,存在可能的隐患
- 下载、取回速度显著受限于服务器挂载硬盘的读写速度以及(在直连的情况下)服务器和大陆的网络连通性
本文约 4000 字。
上手
准备服务器环境
系统为 Ubuntu 20.04。开机 df -h
看看磁盘状态:root@localhost:~# df -h
Filesystem Size Used Avail Use% Mounted on
udev 459M 0 459M 0% /dev
tmpfs 98M 628K 98M 1% /run
/dev/vda1 20G 974M 18G 6% /
tmpfs 489M 0 489M 0% /dev/shm
tmpfs 5.0M 0 5.0M 0% /run/lock
tmpfs 489M 0 489M 0% /sys/fs/cgroup
tmpfs 98M 0 98M 0% /run/user/0
首先 apt update && apt install -y python3-pip
更新软件列表,然后安装 pip3(Python 3)已经内置。
选择最优源
使用 pip3 install apt-select
安装 apt-select,这个工具可以为包管理工具选择最快的源,方便后面的其他安装。
因为服务器在比利时卢森堡,所以使用比利时的国家代码 BE:apt-select -C BE -m up-to-date -c -t 10
apt-select 输出如下:Getting list of mirrors...done.
Testing latency to mirror(s)
[4/4] 100%
Getting list of launchpad URLs...done.
Looking up 4 status(es)
[2/4] 50%
1. mirror.unix-solutions.be
Latency: 5.25 ms
Org: Unix-Solutions BVBA
Status: Up to date
Speed: 1 Gbps
2. archive.ubuntu.com
Latency: 12.87 ms
Org: Canonical Ltd.
Status: Up to date
Speed: 100 Mbps
Choose a mirror (1 - 2)
'q' to quit 1
使用数字键选择一个符合心意的源,使用如下命令替换生成好的 sources.list
并备份原来的:sudo cp /etc/apt/sources.list /etc/apt/sources.list.backup && \
sudo mv sources.list /etc/apt/
安装常用软件和 Web 环境
然后使用如下命令再次更新软件源并安装一些常用软件,最后更新所有软件包:apt update
apt install build-essential wget curl vim coreutils git htop iotop nload screen dnsutils
apt upgrade
Oneinstack 和警告
参见 https://v2ex.com/t/979226
Oneinstack 于 2023 年 4-5 月、9 月下旬以后两度出现官网安装包包含恶意代码的问题,且网站已经出售,请不要使用官网的一键包
下面的安装包为 Dropbox 转存版本,在没有完全代码审计的情况下一定程度上降低了风险,请按步骤操作
使用 Oneinstack 一键包安装 LNMP 环境(Linux, Nginx, MySQL, PHP)。鉴于最近 LNMP.org 和 Oneinstack 出现含有恶意代码的问题,这里使用本人转存自 Dropbox 的一个据称没有污染的版本 CleanInStack.
首先编辑 /etc/hosts
屏蔽 Oneinstack 官方不可信域名:0.0.0.0 mirrors.linuxeyes.com
0.0.0.0 mirrors.oneinstack.com
下载应该没问题的 Oneinstack 一键包并 md5 checksum:wget https://github.com/hifocus/CleanInStack/releases/download/0.0.0/cleaninstack-full.tar.gz
md5sum cleaninstack-full.tar.gz
# md5 应为 b2947bac8cb66d54fcd90d30e406598f
tar -xzf cleaninstack-full.tar.gz
./oneinstack/install.sh
其实安装 Nginx 即可,喜欢的话可以把 PHP 和 mySQL 装全了。
更新防火墙规则
然后更新防火墙规则:允许 22(或者你选择的 ssh 口)、80、443 端口,禁止其他端口:# 如果没安装
apt install ufw
ufw disable # 先禁用 ufw (Uncomplicated Firewall - iptables 的前端) 规则
ufw default deny # 默认阻拦所有规则
ufw allow 22/tcp
ufw allow 80/tcp
ufw allow 443/tcp
ufw enable # 应用更改和启用 ufw
ufw status verbose # 查看详细规则
禁止 IP 直接访问
到现在为止,如果我们直接访问服务器的 IP 会出现 Oneinstack 的界面,而访问 https://IP
在我们添加第一个 https 域名后也会显示该域名的证书。出于强迫症,让我们来禁止 80/443 端口对 IP 的直接访问。
首先自签一张 SSL 证书:mkdir /usr/local/nginx/conf/ssl/
openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout /usr/local/nginx/conf/ssl/nginx.key -out /usr/local/nginx/conf/ssl/nginx.crt
ls /usr/local/nginx/conf/ssl
注意此处
/usr/local/nginx/
为你 Nginx 的安装路径。
然后编辑 /usr/local/nginx/conf/nginx.conf
:; 在 80 端口的 server 块下添加 return 444;
server {
listen 80;
server_name _;
return 444;
}
; 新增一个监听 443 端口的 server 块:
server {
listen 443 ssl default_server;
server_name _;
ssl_certificate /usr/local/nginx/conf/ssl/nginx.crt;
ssl_certificate_key /usr/local/nginx/conf/ssl/nginx.key;
return 444;
}
保存文件,运行 nginx -t
测试:nginx: the configuration file /usr/local/nginx/conf/nginx.conf syntax is ok
nginx: configuration file /usr/local/nginx/conf/nginx.conf test is successful
没问题的话就可以用 service nginx restart
重启 Nginx。现在通过 80/443 端口就无法直接访问服务器的 IP 了。
安装 BitTorrent 下载环境
使用 qBitTorrent-nox:
qBitTorrent 和 qBitTorrent-nox 的区别在于后者带有 Web UI 而非原版的 GUI,在服务器环境上更方便操作
# 添加 ppa 源 |
添加守护进程
守护进程可以方便地管理软件的开关状态,也可以设置开机自启。# 使用你喜欢的编辑器,这里使用 vim
vim /etc/systemd/system/qbittorrent-nox.service
# 文件里放以下内容
[Unit]
Description=qBittorrent client
After=network.target
[Service]
ExecStart=/usr/bin/qbittorrent-nox --webui-port=10086 # 你喜欢的端口
Restart=always
[Install]
WantedBy=multi-user.target
启用开机自启动:sudo systemctl enable qbittorrent-nox
# Created symlink /etc/systemd/system/multi-user.target.wants/qbittorrent-nox.service → /etc/systemd/system/qbittorrent-nox.service.
现在你就可以通过:
service qbittorrent-nox start
启动 qBittorrent-noxservice qbittorrent-nox stop
停止 qBittorrent-noxservice qbittorrent-nox status
查看 qBittorrent-nox 的状态
qb-Nox 默认用户名:admin
,默认密码:adminadmin
因为我们之前在防火墙禁止了相关端口,此时 qB 的 Web UI 是没办法通过 IP:port
访问的。
使用 Nginx 创建反代
我们用 Nginx 来创建一层反向代理方便我们日后使用。此处我们使用 Oneinstack 自带脚本来创建一个虚拟主机:
首先将任意域名/子域名指向服务器 IP.cd ~
# 这里我把 acme.sh 的默认证书颁发机构改为了 Let's Encrypt,感觉 ZeroSSL 1. 不纯粹免费 2. 签发速度慢
./oneinstack/src/acme.sh-master/acme.sh --set-default-ca --server letsencrypt
# 创建 virtual host
./oneinstack/vhost.sh
按照提示选择选项,记住在开始选择 3 自动签发免费 SSL 证书,且确保域名 DNS 正确指向服务器。# 成功后输出
Your domain: example.huangxin.dev
Virtualhost conf: /usr/local/nginx/conf/vhost/example.huangxin.dev.conf
Directory of: /data/wwwroot/example.huangxin.dev
Let's Encrypt SSL Certificate:/usr/local/nginx/conf/ssl/example.huangxin.dev.crt
SSL Private Key: /usr/local/nginx/conf/ssl/example.huangxin.dev.key
编辑 /usr/local/nginx/conf/vhost/example.huangxin.dev.conf
:# 删除以下内容
location ~ [^/]\.php(/|$) {
#fastcgi_pass remote_php_ip:9000;
fastcgi_pass unix:/dev/shm/php-cgi.sock;
fastcgi_index index.php;
include fastcgi.conf;
}
location ~ .*\.(gif|jpg|jpeg|png|bmp|swf|flv|mp4|ico)$ {
expires 30d;
access_log off;
}
location ~ .*\.(js|css)?$ {
expires 7d;
access_log off;
}
# 添加以下内容
location / {
proxy_pass http://0.0.0.0:10086/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
此时,访问 https://example.huangxin.dev 就能看到 qB 的 Web UI 了。
为 Web UI 加上密码
但是我们同样不想把我们的 qB 面板暴露在公网。在这里我们创建一层 Basic Auth 来给 qB 面板加上密码(或者用 qB 自带用户系统也行):# 创建用户名(记得替换 {username})
sh -c "echo -n '{username}:' >> /usr/local/nginx/.htpasswd"
# 创建密码(输入两次密码确认)
sh -c "openssl passwd -apr1 >> /usr/local/nginx/.htpasswd"
在刚刚的 location / {}
块下添加:auth_basic "Restricted"; # 验证提示
auth_basic_user_file /usr/local/nginx/.htpasswd;
照例 nginx -t
测试,service nginx restart
重启。现在访问 example.huangxin.dev
就需要输入用户名和密码了。
可以进入 qB 面板 - Tools(工具) - Options (选项) - Web UI,在 Authentication(验证) 一栏下把 Bypass authentication for clients on localhost (对本地主机上的客户端跳过身份验证)
勾选上,这样就无需输入两次密码。当然,也可以在上面的 Langauge 一栏下把语言改成中文。
然后我们在设置里再进入 BitTorrent 一栏,开启匿名模式以及在底部添加一些 tracker,可以从以下两个仓库里选:
挂载 Volume
接下来,我们需要把另外购买的 Volume 挂载到服务器上,参考这篇文章:https://www.idcoffer.com/archives/6453# 查看磁盘列表
fdisk -l
# 选择要挂在的磁盘,这里是 /dev/sda
fdisk /dev/sda
# 分别选择
n # 创建新分区
p # 创建主分区
w # 保存更改
# 再次查看磁盘
fdisk -l
# 格式化成 EXT4 文件系统
mkfs.ext4 /dev/sda1
# 为分区创建一个文件夹
mkdir /disk2
# 挂载分区
mount /dev/sda1 /disk2
## 编辑 /etc/fstab 文件
vim /etc/fstab
# 加入下面一行 注意修改磁盘名称和挂载点
/dev/sda1 /disk2 ext4 defaults 0 0
# 重启服务器
reboot
# 看看是否成功自动挂载
df -h
现在,我们就可以进入 qB Web UI,把下载位置改成 /disk2
了。
启用目录列举
下载好了 BT,怎么拉回本地呢?有一个方法是直接通过 aria2c 的 Web RPC 推送到本地或者是路由器、NAS之类(见下一部分)。但是由于 aria2c 配置复杂和小白不友好,而且服务器在卢森堡,我觉得还是用 IDM 多线程下载比较好。
我们可以通过同一个域名,使用一个子目录,来实现目录列举。修改 /usr/local/nginx/conf/vhost/example.huangxin.dev.conf
:location /files {
# 依然开启 Basic Auth 验证
auth_basic "Restricted";
auth_basic_user_file /usr/local/nginx/.htpasswd;
# 将子目录的根目录指向下载文件夹
alias /disk2/downloads;
# 开启目录列举
autoindex on;
}
根据 ChatGPT 的针对大文件、相对慢的磁盘的推荐,我还在 location
块里加上了如下设置:gzip off;
sendfile on;
output_buffers 1 1m;
tcp_nopush on;
open_file_cache max=100 inactive=20s;
open_file_cache_valid 30s;
open_file_cache_min_uses 2;
open_file_cache_errors on;
这样,我们就可以通过 Nginx 自带的目录列举功能来直观地看到服务器上的文件了:
光看还不够,下载好的资源一个目录下十来个文件,如何全部获取他们的 URL 然后放到下载器里下载呢?虽然可以有很极客的解决办法,但是这里我们可以用比较原始的方法:
- 进入资源目录
- 右键查看源代码
- 复制所有 ` 标签
- Google 搜索 “href extraction” 工具,我随便找了个:
https://en.toolpage.org/tool/href-extractor
,提取所有相对链接,复制到 VS Code 内 - 回到资源目录,复制上方 URL,回到 VS Code,使用 Alt + Shift + 鼠标左键 选中所有 URL,然后 Ctrl + C 复制
- VS Code 内的就是所有文件的绝对 URL,放入 IDM(Task - Add Batch Download from Clipboard)即可开始下载
安装 AList
AList 是一个支持多个源的目录列举工具,包括本地、阿里云盘、Google Drive、各种对象存储等等
GitHub 页面:https://github.com/alist-org/alist
通过安装 AList,我们可以通过一个图形化的界面对服务器的文件目录直接进行操作(主要用来删除下载完的文件),免去了连接服务器和手打 rm -rf
命令的麻烦。另外,Alist 可以支持离线下载和使用 Aria2 RPC 推送下载。
AList 有一键脚本,但是只支持安装最新的版本。由于 v3.28.0 似乎魔改了后台,个人不太喜欢,这里手动安装 GitHub Release 里的 3.26.0 版本,参考 https://alist.nn.ci/zh/guide/install/manual.html。# 创建文件夹并进入
mkdir -p /data/apps/alist
cd /data/apps/alist
# 下载有 MUSL 静态链接的二进制文件并解压缩
wget https://github.com/alist-org/alist/releases/download/v3.26.0/alist-linux-musl-amd64.tar.gz
tar -xzf alist-linux-musl-amd64.tar.gz && rm alist-linux-musl-amd64.tar.gz
# 测试安装
./alist help
# 获取 admin 账户信息,并从输出里找到临时密码
./alist admin
# INFO[2023-10-06 21:19:47] Successfully created the admin user and the initial password is: xxxxxxxxxx
# 添加守护进程
vim /usr/lib/systemd/system/alist.service
# 输入以下内容
[Unit]
Description=alist
After=network.target
[Service]
Type=simple
WorkingDirectory=path_alist # 将 path_alist 改为 alist 的绝对路径,在这里是 /data/apps/alist
ExecStart=path_alist/alist server
Restart=on-failure
[Install]
WantedBy=multi-user.target
# 重载配置
systemctl daemon-reload
# 启用开机自启
systemctl enable alist
# 启用 alist
service alist start
# 查看状态,确保无报错
service alist status
子目录的反代设置
由于我们打算把 AList 放在子目录里,参考这篇文档,我们首先要进入 AList 同目录下的 /data
文件夹,修改 config.json
:vim /data/apps/alist/data/config.json
# 将 "site_url" 改为 `/cloud` 或者你喜欢的子目录名
# "site_url": "/cloud",
在 Nginx 虚拟主机配置文件内新增:location /cloud/ {
auth_basic off;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Range $http_range;
proxy_set_header If-Range $http_if_range;
proxy_redirect off;
proxy_pass http://0.0.0.0:5244/cloud/; # 注意 proxy_pass 必须带子目录路径和最后的斜杠
}
nginx -t
测试,service nginx restart
重启;此时,就能通过 https://example.huangxin.dev/cloud
访问 AList 实例。
访问 AList 实例,使用上面的 admin 账号密码登陆,修改密码,进入存储 - 添加 - 本地存储,设置挂载路径为 /
或者 /downloads
,设置根目录为 /disk2/downloads
(或者你对应的路径),就可以通过 AList 访问下载好的文件。
也可以在右边的工具栏设置本地 aria2 RPC,这样就可以直接推送下载了。
使用中转服务器加速下载
由于国内国际网络的连通性不加,加上服务器本身并没有大陆优化,如果你碰巧有对大陆优化且带宽相对充裕的服务器,除了使用代理下载外,还可以用中转服务器上的 Nginx 进行又一层的反代。
- 在中转服务器上安装 Nginx,参考上面的教程
- 新建一个子域名,例如
proxy-download.huangxin.dev
,并将其指向中转服务器 IP - 在中转服务器上建立一个虚拟主机
- 在 Nginx 虚拟主机配置文件里应用如下配置:
location / {
# 可以另外加一层 Basic Auth
auth_basic "Restricted Content";
auth_basic_user_file /usr/local/nginx/.htpasswd;
# 反代地址,记得尾端的斜杠
proxy_pass https://example.huangxin.dev/files/;
# Set the proxy headers so the original host and IP are known
proxy_set_header Host example.huangxin.dev;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
# Basic HTTP Authentication
# 在请求头内包含被代理服务器的 Basic Auth 用户名和密码
proxy_set_header Authorization "Basic dXNlcjpwYXNzd29yZA=="; ## user:password 的 base64 编码
# Enable support for resumable downloads
proxy_http_version 1.1;
proxy_set_header Connection "";
proxy_buffering on;
proxy_buffer_size 16k;
proxy_buffers 4 32k;
} - 现在,请求
https://proxy-download.huangxin.dev
就会被反代到https://example.huangxin.dev/files/
,并且会自动带上 Basic Auth 的用户名和密码
成果速览
使用 BuyVM 1C1G 20GB @ 10Gbps 的服务器可以做到 BT 跑满硬盘速度下载(约 35MB/s),通过中转服务器取回能跑到本地软件限制的限制带宽上限(约 7800KB/s):