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,不必重建镜像。