用"更现代的"方法,建立基于 aria2c 的下载服务器

很早之前,我写过这么一篇关于 aira2c 下载服务器搭建的文章.现在看来,当时用的方法实在是怪异扭曲.所以,经过一番探索,我大概算是找到了一种更优雅的搭建姿势,也学到不少东西,下面就来写一写.

简单地说,我打算采用 AriaNg 作为前端, aria2c 作为 RPC 后端的方案,服务器中间件采用 Caddy, 前后端共用一个域名并让 Caddy 自动管理证书(假设域名是 aria.com), 使用 inotify 机制来监视证书更新,用 systemd 来管理守护进程,并用 screen 来运行 aria2c 以提供一个更友好的交互式界面.

AriaNg 是一个纯静态的 web app, 用 Caddy 来搭建基于它的站点相当简单,这里略过.也可选用其它的 aria2c 前端,如 YAAW. 下面,首先安装 aria2c 和后续要用到的 inotify-tools. 以 Fedora 为例,执行:

dnf install aria2 inotify-tools

aria2c 的 RPC 接口需要一个域名,我们让它和 AriaNg 前端共用相同的 aria.com, 并让 aria2c 使用 Caddy 维护的证书.这些证书和私钥位于 $HOME/.caddy/acme/acme-v02.api.letsencrypt.org/sites/aria.com. 编辑 aria2c 配置文件,指定证书和私钥路径.这里有一份模板,其中 RPC 密钥,限速,端口,下载位置等项目可改为适合的值,会话文件要自己新建:

# aria2.conf
#设置加密的密钥
rpc-secret=XXXXXXXXXXXXXXXXXXXXXX
#允许rpc
enable-rpc=true
rpc-secure=true
rpc-certificate=$HOME/.caddy/acme/acme-v02.api.letsencrypt.org/sites/aria.com/aria.com.crt
rpc-private-key=$HOME/.caddy/acme/acme-v02.api.letsencrypt.org/sites/aria.com/aria.com.key
#允许所有来源, web界面跨域权限需要
rpc-allow-origin-all=true
#允许外部访问,false的话只监听本地端口
rpc-listen-all=true
#RPC端口, 仅当默认端口被占用时修改
rpc-listen-port=6800
#最大同时下载数(任务数), 建议值: 3
max-concurrent-downloads=5
#断点续传
continue=true
#同服务器连接数
max-connection-per-server=16
#最小文件分片大小, 下载线程数上限取决于能分出多少片, 对于小文件重要
min-split-size=10M
#单文件最大线程数, 建议值: 5
split=16
#下载速度限制
max-overall-download-limit=
#单文件速度限制
#max-download-limit=0
#上传速度限制
max-overall-upload-limit=
#单文件速度限制
#max-upload-limit=0
#断开速度过慢的连接
#lowest-speed-limit=0
#验证用,需要1.16.1之后的release版本
#referer=*
#文件保存路径, 默认为当前启动位置
dir=
#文件缓存, 使用内置的文件缓存, 如果你不相信Linux内核文件缓存和磁盘内置缓存时使用, 需要1.16及以上版本
#disk-cache=0
#另一种Linux文件缓存方式, 使用前确保您使用的内核支持此选项, 需要1.15及以上版本(?)
#enable-mmap=true
#文件预分配, 能有效降低文件碎片, 提高磁盘性能. 缺点是预分配时间较长
#所需时间 none < falloc ? trunc << prealloc, falloc和trunc需要文件系统和内核支持
file-allocation=falloc
# 从会话文件中读取下载任务
input-file=/etc/aria2/aria2.session
# 在Aria2退出时保存`错误/未完成`的下载任务到会话文件
save-session=/etc/aria2/aria2.session
# 定时保存会话, 0为退出时才保存, 需1.16.1以上版本, 默认:0
save-session-interval=60
# 服务器返回 50X 时自动重连
max-tries=0
retry-wait=7

(如果你用了 h5ai, filebrowser 这些目录列表程序的话,可以把它们的根目录作为 aria2c 的默认下载位置,这样就是一个有离线下载功能的个人网盘了,超棒的)

把配置文件放在 $HOME/.aria2/aria2.conf, 这是 aria2c 默认的位置(虽说是一点都不现代的 "legacy path", 但  $XDG_CONFIG_HOME 那个变量我也没有嘛).接下来,我们需要让 aria2c 作为守护进程启动.

说到守护进程啊...本站那些老文章里通通是用 screen + crontab 的怪异方案.说起来也挺不好意思的,我第一次要设置守护进程的时候就被 SysV init, systemd, supervisord, upstart 啥啥啥的一大堆乱七八糟的吓到了,然后试着去学 systemd 的时候又被吓到了,我就想整一个开机启动,咋这么麻烦然后当时看到一篇文章就是走的 screen + crontab 的野路子,实在是小白大救星,看起来一点都不复杂,而且 screen 可以随时切进去切出来,能有个可交互的终端,实在是太友好了.没错!我一直对接管标准输出的 systemd 和标准输出直接没了的 SysV init script (不重定向的话)有隔阂,我就是想能直接看到程序自己的界面所以沉迷 screen 不能自拔.直到现在,一番搜索之后才知道, systemd 启动的守护进程并非不能有可交互的界面,这里面能玩出的花还不少.

我们可以用 systemd 来启动一个 screen 会话,然后在里面运行 aria2c. service 文件如下:

# /etc/systemd/system/aria2c.service
[Unit]
Description=aria2c

[Service]
ExecStartPre=-/usr/bin/screen -X -S aria2c kill
ExecStart=/usr/bin/screen -dmS aria2c -O -l /usr/bin/aria2c
ExecStop=/usr/bin/screen -X -S aria2c kill
Type=forking
RemainAfterExit=false
Restart=on-failure
RestartSec=5s
SuccessExitStatus=1

[Install]
WantedBy=multi-user.target

其中的 ExecStartPre 用来避免出现同名的 screen 会话,那个 - 表示即使失败也继续.

接下来,还有另一个问题:证书更新时,应该重启 aria2c 来载入新的证书.过去使用 acme.sh 管理证书时,这可以通过 acme.sh 自带的功能实现.现在使用的 Caddy 并没有类似的证书更新时的行为,毕竟它本身也没打算为别的程序管理证书.怎么办呢?我们可以用 inotify 来监视证书文件的变化,从而触发相应的操作.编写一个简单的脚本:

# inotify_aria2c.sh
#!/bin/bash

DOMAIN=aria.com
MONITOR_PATH="$HOME/.caddy/acme/acme-v02.api.letsencrypt.org/sites/${DOMAIN}"
CRT_FILE="${DOMAIN}.crt"

inotifywait -m -e close_write --format "%f" $MONITOR_PATH | while read FILE
do
    if [[ $FILE = $CRT_FILE ]]
    then
        sleep 2
        systemctl restart aria2c
        echo "Certificate modified. Restart aria2c."
    fi
done

我们用 inotifywait 来监听目录下文件的 close_write (就是"写完了")事件,并通过 systemd 重启 aria2c. 当然,这个脚本也需要作为守护进程启动,一个简单的 service 文件就能完成任务:

# /etc/systemd/system/inotify_aria2c.service
[Unit]
Description=Automatically restart aria2c after certificate renewal

[Service]
ExecStart=/path/to/inotify_aria2c.sh
Restart=on-failure

[Install]
WantedBy=multi-user.target

把上述两个 service 文件放到 /etc/systemd/system, 然后执行:

systemctl daemon-reload
systemctl enable aria2c.service
systemctl enable inotify_aria2c.service
systemctl start aria2c.service
systemctl start inotify_aria2c.service

这样就设置好了开机启动,并启动了服务.不仅可以用 systemctl status aria2c.service 来看到 aria2c 的运行状态,也可以随时用 screen -r aria2c 切进交互式终端里.以后,如果证书发生变更,我们可以在 inotify_aria2c.service 的日志里看到 aria2c 已经被它重启了:

最后,访问 AriaNg 前端,填好端口号和 RPC 密钥,大功告成啦!

(接下来,你还可以让 aria2c 使用这里提供的 tracker 列表)

(你可能会看到这样的报错: [WARN] aria2c had to connect to the other side using an unknown TLS protocol. The integrity and confidentiality of the connection might be compromised. 根据网上的说法,这是因为 aria2c 使用的加密库和你的浏览器采用了 TLS 1.3, 但 aria2c 并不知道 TLS 1.3 是什么,所以就报告给你,事实上并没有哪里出错.包管理器里的 aria2c 似乎很久没更新了,目前的最新版本没有包含解决这一问题的补丁.强迫症的话,可以自己编译 aria2c)

以上.

发表评论

电子邮件地址不会被公开。 必填项已用*标注