编程 aria2 自建 RPC 下载服务:先 curl 验通,再谈 AriaNg

2026-11-13 00:03:25

aria2 自建 RPC 下载服务:先 curl 验通,再谈 AriaNg

本文只谈 aria2 RPC 的鉴权格式与连通性判据——端口怎么暴露、token 写在哪、反代怎么配、容器起不来怎么查。单文件的 -x/-s/-k 切分与 Range 行为见站内 #8237,这里不重复。

项目信息:

  • 官网:https://aria2.github.io/
  • 源码:https://github.com/aria2/aria2
  • WebUI:https://github.com/mayswind/AriaNg
  • Docker 指南:https://aria2.org/zh/guides/docker/

1. 鉴权格式:token: 是 JSON-RPC 协议层的一部分

aria2 的 RPC 端点默认是 http://host:6800/jsonrpc,走 JSON-RPC 2.0。它的鉴权不在 HTTP 头里,也不是查询参数,而是塞进 params 数组的第一项,形如 "token:SECRET":

{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "aria2.getVersion",
  "params": ["token:CHANGE_ME_TO_A_LONG_RANDOM_SECRET"]
}

这带来一个非常常见的抄错点,必须分清两个地方:

  • 手工 curl / 自己写脚本:params 首项必须带 token: 前缀,少了它就是没鉴权,rpc-secret 非空时直接返回错误。
  • AriaNg 的「RPC 密钥」输入框:只填明文 secret,不要加 token:。AriaNg 内部会自己拼前缀,你手填 token:xxx 的结果是它发出 token:token:xxx,表现为「一直断开」。

system.* 系列方法(如 system.listMethods)不需要密钥,这是后面做健康检查的基础。rpc-secret 留空时所有方法都不需要 token——但那等于把下载器交给任何能访问 6800 的人,不建议。

2. 第一步是 curl 拿结论,不是打开 UI

排查连不上时,先把 UI 放一边。用 aria2.getVersion 打一发,能返回版本号,说明进程、监听、token 三段都是通的:

curl -s http://localhost:6800/jsonrpc \
  -d '{"jsonrpc":"2.0","id":1,"method":"aria2.getVersion","params":["token:CHANGE_ME_TO_A_LONG_RANDOM_SECRET"]}'

正常返回:

{"id":1,"jsonrpc":"2.0","result":{"enabledFeatures":["Async DNS","BitTorrent","Firefox3 Cookie","GZip","HTTPS","Message Digest","Metalink","XML-RPC"],"version":"1.37.0"}}

enabledFeatures 顺便能看出构建差异:Alpine 版不含 SFTP,功能列表比 Ubuntu 版少一项,不是配置问题。

如果这里返回鉴权错误,问题一定在 rpc-secret 与 params 首项是否一致;如果 curl 直接连接被拒,问题在监听与端口发布,跟密钥无关。先把这两类错误分开,再去看 AriaNg。

3. rpc-listen-all 管容器内,端口发布管容器外

容器的端口转发来自容器外部,因此容器内的 aria2 必须监听所有接口,rpc-listen-all=true 是必需的。它只决定「bind 到 0.0.0.0」,不放行任何防火墙——真正的可达范围由 compose 的 ports 决定:

ports:
  - "6800:6800"                # 主机所有网络,别这么干
  - "192.168.1.10:6800:6800"   # 只绑单个网卡
  - "127.0.0.1:6800:6800"      # 只给主机,配反代用这个

这里有个容易踩的坑:Linux 上 Docker 发布的端口不受 ufw 规则过滤,Docker 官方文档对此有明确警告。也就是说 6800:6800 一旦发布出去,你以为了 ufw 挡住了,实际公网可直连。不要依赖 ufw 隐藏 6800;没有 HTTPS 保护时,切勿让 6800 从公网可达。

需要从外面访问,就走两条路:VPN,或者 127.0.0.1:6800:6800 + HTTPS 反代,并且 rpc-secret 用足够长的随机串。

4. nginx 反代 /jsonrpc:协议版本、Upgrade、超时

反代不只是 proxy_pass,AriaNg 的部分交互依赖 WebSocket,缺了 Upgrade 头会在某些操作上断连:

location /jsonrpc {
    proxy_pass http://127.0.0.1:6800/jsonrpc;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";
    proxy_set_header Host $host;
    proxy_read_timeout 1h;
}

proxy_http_version 1.1 是 Upgrade 生效的前提;proxy_read_timeout 默认 60s,长任务或空闲连接容易被掐,拉到 1h 更稳。

不要在 /jsonrpc 上叠 nginx basic auth。 浏览器发 CORS 预检(OPTIONS)时不带凭据,预检被 401 掉,基于浏览器的 WebUI 直接不可用。这与 rpc-allow-origin-all=true 是配套的:跨域放开了,就别指望用 basic auth 在同一个 location 上补一层。要收紧访问,靠网络层(VPN、白名单)或足够强的 rpc-secret。

5. session 文件不存在,aria2 直接不启动

input-file 指向的 session 文件缺失时,aria2 会退出而不是自动新建。Docker 镜像里用 entrypoint 先 touch 兜底:

FROM alpine:3.20
RUN apk add --no-cache aria2 ca-certificates tzdata
VOLUME ["/config", "/downloads"]
EXPOSE 6800 6888 6888/udp
# aria2 will not start if the session file is missing, so create it first
ENTRYPOINT ["sh","-c","touch /config/aria2.session && exec aria2c --conf-path=/config/aria2.conf"]

手写 systemd 单元同理,需要 After=network-online.target 与 Wants=network-online.target,并预先创建、chown 好 session 文件。另外,不要把 rpc-secret 写在 ExecStart 的命令行参数里——它会明文出现在进程列表和日志中,写在配置文件里。

对应的 aria2.conf 关键项:

dir=/downloads
continue=true
file-allocation=falloc
max-concurrent-downloads=5
max-connection-per-server=16
split=16
min-split-size=1M
disk-cache=64M

enable-rpc=true
rpc-listen-all=true
rpc-listen-port=6800
rpc-allow-origin-all=true
rpc-secret=CHANGE_ME_TO_A_LONG_RANDOM_SECRET

listen-port=6888
dht-listen-port=6888
enable-dht=true
enable-peer-exchange=true
seed-ratio=1.0

input-file=/config/aria2.session
save-session=/config/aria2.session
save-session-interval=60

on-download-complete=/config/on-complete.sh
log=/config/aria2.log
log-level=notice

6. healthcheck 用不需要密钥的 system.listMethods

健康检查里塞 rpc-secret 会把密钥散到 docker inspect 里。system.* 不需要密钥,用它判断进程活着、RPC 端点可解析即可:

healthcheck:
  test: ["CMD-SHELL", "wget -qO- --post-data='{\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"system.listMethods\"}' http://127.0.0.1:6800/jsonrpc | grep -q aria2.addUri"]
  interval: 60s
  timeout: 10s
  retries: 3

grep -q aria2.addUri 顺带确认返回的是方法列表而不是错误对象。注意这个检查只覆盖「容器内 RPC 可用」,不覆盖「反代链路可用」;后者用 curl https://your.host/jsonrpc 单独验。

7. 故障排查对照

  • Bind for 0.0.0.0:6800 failed: port is already allocated:主机端口被占,改成 6801:6800,或先 ss -tlnp | grep :6800 看谁在监听,确认 aria2 是否真的 bind 到 0.0.0.0。
  • touch /config/aria2.session: Permission denied:chown -R 1000:1000 config downloads,或去掉 compose 里的 user:。
  • 日志出现 IPv6 RPC: failed to bind TCP port 6800:前一行若有 IPv4 RPC: listening on TCP port 6800,可忽略。
  • 日志出现 Exception: [AbstractCommand.cc:351] CUID#X - Failed to open file:多为路径或挂载权限问题,与鉴权无关。
  • WebUI 显示已断开:依次查容器状态、rpc-secret 与输入框是否一致(输入框不要带 token:)、连接地址是否写成容器地址而非主机地址。
  • HTTPS 页面连不上明文 6800:浏览器只允许 HTTPS 页面访问 http://localhost,其他一律走 HTTPS 反代。
  • 改完配置只需 docker restart aria2,不必重建镜像。
复制全文 生成海报 aria2 下载工具 AriaNg Docker 运维实战

推荐文章

程序员茄子在线接单