深色模式
不再把音乐全放本地:R4S 挂载百度网盘,搭建 Navidrome 云端曲库
音乐文件越来越多,但我不想为了听歌,把整套曲库一直放在路由器本地。既然百度网盘已经有 SVIP,家里的 NanoPi R4S 也一直开着,能不能让 Navidrome 直接读取网盘里的音乐?
这次实际搭建后,答案是可以。最终采用的是 百度网盘 → OpenList → Rclone/FUSE → Navidrome Docker。网盘保存音乐,R4S 负责连接、缓存和提供音乐服务,手机或浏览器负责播放。这篇文章记录完整思路、关键配置、验证结果,以及实际遇到的权限和状态显示问题。
一、先明确:云端挂载不等于下载整个曲库
原来的方式,是把音频文件复制到 R4S 的磁盘,再让 Navidrome 扫描。现在则把网盘目录呈现为 R4S 上的一个文件夹,Navidrome 仍然读取文件系统路径,但数据来自百度网盘。
播放时会产生网络读取和本地缓存,扫描也会读取音频元数据,因此它并不是“完全不占空间、完全不下载”。区别在于:不必在本地永久保存整套音乐文件。R4S 主要保存配置、数据库、封面和有限缓存。
txt
百度网盘:/影音/音乐
↓ OpenList 连接网盘
WebDAV:只读专用账号
↓ Rclone + FUSE
R4S:/mnt/wrt-disk/CloudMusic/Baidu
↓ Docker 只读映射
Navidrome:/music/Baidu
↓
浏览器或手机音乐客户端这里的使用前提是 R4S 持续运行、网络可用、网盘授权有效。断网时,即使缓存里有部分内容,也不能把这套方案当成完整的离线音乐库。
二、这次使用的设备与环境
| 项目 | 实际环境 |
|---|---|
| 设备 | NanoPi R4S,ARM64,约 4GB 内存 |
| 系统 | ImmortalWrt 24.10.6 |
| 内核 | 6.6.133 |
| 包管理器 | opkg |
| 音乐服务 | 已运行的 Navidrome Docker,版本 0.64.2 |
| 网盘 | 百度网盘 SVIP |
| OpenList | Docker 镜像 openlistteam/openlist:v4.2.9-lite |
| Rclone | 系统软件源版本 1.70.3 |
| 数据磁盘 | /mnt/wrt-disk,部署前约剩余 10.4GB |
这些版本是本次部署的实测环境,不代表其他固件可以照搬安装包。尤其是内核模块,必须按自己的系统核查。
三、几个组件分别负责什么
- **OpenList:**负责连接百度网盘,并提供 WebDAV 文件访问接口。
- **Rclone:**通过 WebDAV 读取 OpenList,管理目录访问和文件缓存。
- **FUSE:**让 Rclone 提供的远程文件,以 Linux 文件系统目录的形式出现。
- **Navidrome:**扫描音频标签,整理歌曲、专辑、歌手,并提供搜索与播放。
这次没有让 Rclone 直接对接百度网盘,而是通过 OpenList 转接。这样,百度网盘授权与音乐库扫描各自有清楚的职责。
四、安装前,先保护现有环境
R4S 还承担家庭网络服务,不能为了音乐功能随意升级系统、强装内核模块或重建现有容器。我先检查了 Docker 的运行状态、Navidrome 的目录映射、数据库位置、软件源和磁盘空间。
修改前保存了容器完整配置、Navidrome 配置、数据库及相关数据,以及原软件源配置。数据库备份时短暂暂停容器,复制完成后立即恢复,避免直接复制正在变化的数据库文件。
**配置和数据库备份不等于音乐文件备份。**后面清理本地音乐,是在云端读取、实际播放和完整扫描都验证通过后,按自己的使用决定执行的;不建议把删除本地曲库当成安装步骤。
五、先解决 FUSE,而且必须精确匹配内核
最初 R4S 没有 Rclone,也不存在 /dev/fuse。先执行只读检查:
txt
cat /etc/openwrt_release
uname -r
opkg status kernel
cat /etc/opkg/distfeeds.conf
ls -l /dev/fuse
opkg list-installed | grep -E 'fuse|rclone'更新软件包索引后,核对 kmod-fuse 的依赖。不能只看到双方都写着“6.6.133”就认定兼容,还要对比内核包的完整构建标识。
txt
opkg update
opkg info kmod-fuse
opkg status kernel
opkg --noaction install kmod-fuse rclone fuse3-utils本次仓库中的依赖与已安装内核完全一致,模拟安装也没有依赖冲突,才继续:
txt
opkg install kmod-fuse rclone fuse3-utils
ls -l /dev/fuse
rclone version安装后还做了临时目录的实际只读挂载与文件读取测试,再卸载测试挂载。整个过程没有使用强制依赖选项,也没有升级内核或固件。
六、部署 OpenList,网盘授权由自己完成
OpenList 并不必须使用 Docker。iStore 也可能提供安装入口,但入口背后是原生程序还是容器,需要看对应安装脚本。本次已有 Docker,因此沿用容器部署,数据独立保存在:
txt
/mnt/wrt-disk/Configs/OpenList使用精简版镜像、固定版本、有限日志和容器自动启动,服务端口只绑定设备的局域网地址,没有为这次部署开放公网访问。容器内运行用户需要对映射的数据目录有正确权限。
初始化管理员后,在“存储”中选择百度网盘,完成自己的百度登录与授权。令牌直接填写到自己部署的 OpenList,不写进文章、截图或公开配置。使用在线 API 的授权方式时,也要理解它涉及 OpenList 的在线刷新服务,并核对授权页面的权限范围。
本次存储配置的关键项如下:
| 选项 | 设置 |
|---|---|
| OpenList 挂载路径 | /百度音乐 |
| 百度网盘根文件夹路径 | /影音/音乐 |
| 下载接口 | 官方 |
| WebDAV 策略 | 本机代理 |
| 仅列出视频文件 | 关闭 |
百度客户端中的“我的网盘/全部文件”属于界面导航,不是需要填入的目录层级。实际路径从 /影音/音乐 开始。保存后重新打开设置,确认值确实保存,再查看文件列表;只看到“工作中”还不足以证明目录范围正确。
百度部分大文件读取涉及 User-Agent 要求。本次通过 OpenList 本机代理完成传输,FLAC 与 MP3 都做了实测,不能仅以“目录能列出来”作为播放成功的依据。
七、为 Rclone 建立只读专用账号
没有把 OpenList 管理员账号交给 Rclone,而是建立一个专用账号:
txt
用户名:navidrome-reader
基本路径:/百度音乐
权限:仅 WebDAV 读取不授予写入、删除、移动或 WebDAV 管理权限。这个账号登录 WebDAV 后看到的根目录,就对应获准访问的音乐存储,不需要再次拼接 OpenList 的挂载路径。
Rclone 的配置文件放在 /mnt/wrt-disk/Configs/Rclone/rclone.conf,只有受限账号可读。示意配置如下,示例地址需要替换为自己的局域网地址:
txt
[baidumusic]
type = webdav
url = http://ROUTER_LAN_IP:5244/dav/
vendor = other
user = navidrome-reader
# 密码通过本机交互配置,不在公开示例中填写Rclone 配置中的密码即使经过 obscure 处理,也不是不可恢复的加密保险箱,仍应把整个配置文件当作凭据保护。先用 rclone lsf 检查根目录,确认只显示预期的音乐文件夹。
八、只读挂载与有限缓存
这次把宿主机挂载点放在:
txt
/mnt/wrt-disk/CloudMusic/Baidu挂载命令的关键参数如下。这里用于解释配置,不应在已有自动挂载服务运行时再次手动启动同一个挂载点。
txt
rclone mount baidumusic: /mnt/wrt-disk/CloudMusic/Baidu \
--config /mnt/wrt-disk/Configs/Rclone/rclone.conf \
--read-only --allow-other \
--vfs-cache-mode full \
--cache-dir /mnt/wrt-disk/rclone-cache \
--vfs-cache-max-size 1G \
--vfs-cache-max-age 6h \
--vfs-cache-min-free-space 3G \
--vfs-cache-poll-interval 1m \
--buffer-size 8M \
--vfs-read-chunk-size 8M \
--vfs-read-chunk-size-limit 32M \
--dir-cache-time 10m \
--poll-interval 0 \
--contimeout 10s --timeout 60s**1GB 是缓存目标,不是严格磁盘配额。**正在使用的文件不一定能立即清理,首次扫描、并发播放或大文件读取都可能让缓存暂时超出目标;保留 3GB 空闲也是尽力执行的清理策略。数据库、封面、转码缓存和日志另外占空间,仍要观察磁盘余量。
缓存明确放在数据磁盘,避免默认路径占满系统分区。普通使用不需要把 100GB 曲库预先下载到本地,但首次扫描会产生实际的网络读取。
九、Docker 接入时,要考虑挂载重连
如果只在容器启动时把一个 FUSE 目录绑定进去,重连后可能出现宿主机已经恢复、容器仍看不到新挂载的问题。本次给 CloudMusic 父目录建立共享挂载,再以只读、单向接收挂载传播的方式接入 Navidrome:
txt
宿主机:/mnt/wrt-disk/CloudMusic
容器内:/music
绑定模式:ro,rslave这样,宿主机的 Baidu 子挂载重新建立时,可以传播到容器内。共享父挂载需要在 Docker 启动前准备,不能只有一次手工命令;这部分也纳入了开机服务。
自动挂载交给 ImmortalWrt 的 procd 管理,服务位于 /etc/init.d/cloudmusic,启动顺序设为 S98,早于本机 S99 的 Docker 服务。Rclone 进程退出后会重试,启动包装脚本负责处理失效的 FUSE 挂载。
实际验证了挂载服务重启后,容器仍能列出音乐目录。已启用开机启动,但这次没有为了测试而重启整台路由器,避免中断家庭网络,因此不把“已配置自动启动”写成“整机重启实测通过”。
十、曲库怎样自动更新:谁来执行扫描?
网盘能访问,不代表 Navidrome 会立即知道新增了哪些歌曲。挂载负责提供文件,扫描负责更新音乐数据库,两者是不同的工作。
本次关闭了 Navidrome 自带的启动扫描、内置定时扫描和文件变化监听,改由 R4S 的 cron 定时调用检查脚本。真正扫描和整理音乐的,仍然是 Navidrome 自己。
txt
R4S 的 cron 定时服务
↓
/usr/libexec/cloudmusic-scan
↓ 检查挂载存在、远端可列目录且非空
检查通过 → docker exec navidrome /app/navidrome scan
检查失败 → 跳过本次,不发起扫描定时任务保存在 /etc/crontabs/root,当前实际安排是每天北京时间凌晨 4:30:
txt
30 4 * * * /usr/libexec/cloudmusic-scan如果以后希望每小时扫描,可以把该行替换成下面这一行,而不是同时保留两行:
txt
0 * * * * /usr/libexec/cloudmusic-scan**本文完成时仍是每天 4:30,并未改成每小时。**这项任务由 R4S 自己执行,电脑无需开机,也不依赖聊天助手在线。
脚本先检查挂载点,再通过 Rclone 发起新的远端列表请求;检查成功后才发起扫描,并用锁目录避免脚本重复执行。它能减少挂载尚未准备好时扫描空目录的情况,但不是全程网络健康保证,扫描中途仍可能断线。日常扫描保留“缺失文件不自动永久清除”的策略,避免把暂时不可用当成真正删除。
Navidrome 自带的启动扫描和定时扫描也能用,分别由 Scanner.ScanOnStartup 和 Scanner.Schedule 控制,当前版本没有对应的网页开关。Docker 环境变量优先于配置文件:如果容器已有 ND_SCANNER_SCHEDULE=0,只修改 TOML 不会覆盖它。
需要立即更新时,仍可以在 Navidrome 的“设置 → 媒体库”里手动点击快速扫描;大量整理目录后可用完全扫描。手动操作不会经过外部检查脚本,执行前应先确认网盘正常。
十一、新增音乐和整理文件夹,有哪些影响?
- **新增:**把已展开的音频文件放入百度网盘
/影音/音乐下,等下一次扫描或手动扫描。 - **子目录整理:**可以移动、重命名内部子文件夹,完成后重新扫描。Navidrome 会尝试识别移动,但大量变化时不保证所有歌单和历史关联都能保留。
- **外层路径:**如果把
/影音/音乐改名或移走,必须同步调整 OpenList 的根路径。 - **缓存延迟:**Rclone 目录缓存约 10 分钟,OpenList 也有自己的缓存。新增内容可能需要等待,两层缓存的延迟不能简单当作固定的 10~30 分钟承诺。
- **压缩包:**RAR、ZIP 可以出现在目录中,但 Navidrome 不能把压缩包内部歌曲直接当成普通曲库扫描,需要先解压。
十二、两个实际踩过的坑
1. Docker 正常,iStore 页面却显示“未运行”
为了保留旧配置,我把原容器改名为 navidrome-local-backup 并停止。管理插件用名称模糊匹配,结果把正式容器与备份容器一起查出来,状态同时包含 running 和 exited,页面就误判了。
解决方式是把状态和端口查询改成精确匹配正式容器:
txt
docker ps --all -f 'name=^/navidrome$' --format '{{.State}}'修正后页面恢复为“运行中”。所以,红色的旧备份容器只是已停止,不代表音乐服务故障。确认不需要时可以只删除旧容器;不要连带删除当前服务共用的数据目录或存储卷。插件升级可能覆盖本地脚本修正,之后遇到相同现象应再核对。
2. Windows 能看到 CloudMusic,却提示没有权限
这次不是网盘授权失效,而是 CloudMusic 父目录创建时权限为 700,只有 root 能进入。Windows 共享使用普通账号,自然会被挡住。
处理时只修改这个父目录的属组与权限,让现有共享账号拥有读取和进入权限,未递归修改网盘内容,也没有用 chmod 777。思路是:
txt
chown root:实际共享账号的组 /mnt/wrt-disk/CloudMusic
chmod 750 /mnt/wrt-disk/CloudMusic之后可从 Windows 访问类似下面的路径,服务器地址和共享名称按自己的环境替换:
txt
\\ROUTER_LAN_IP\WRT-Disk\CloudMusic\BaiduFUSE 已设置 allow-other,网盘挂载仍是只读。这样电脑可以浏览和读取,上传、整理和删除仍在百度网盘完成。只读访问同样会产生网盘流量,Windows 预览或批量扫描文件时也要注意这一点。
十三、最后的实测结果与维护方式
首次完整扫描约 3 分 25 秒结束,退出码为 0,扫描日志中没有 error 记录。最终曲库统计为 396 首歌曲、30 张专辑、缺失文件 0,音频总大小约 15.63GB。这个大小是云端音频统计,并非 R4S 实际占用。
FLAC 已在网页播放器中实际播放并观察到进度前进;MP3 做了从指定位置开始的实际解码测试;挂载重启后容器内的音乐目录仍可读取。确认这些结果后,才清理了约 2.7GB 的原本地音乐,磁盘可用空间约为 12GB。
日常检查主要看下面几项:
txt
/etc/init.d/cloudmusic status
mountpoint /mnt/wrt-disk/CloudMusic/Baidu
docker ps
/usr/libexec/cloudmusic-scan
tail /tmp/cloudmusic-scan.log
df -h /mnt/wrt-disk配置、数据库和原容器定义单独保留备份,凭据文件不公开。恢复旧容器本身不能恢复已删除的本地音频,需要重新从自己的音乐备份或网盘取得文件。以后从 iStore 点击升级或重建 Navidrome 前,也要保存当前 Docker 配置,因为普通安装脚本可能覆盖挂载传播、环境变量和日志限制等定制参数。
这套方案解决的是“音乐必须完整放在 R4S 本地才能使用 Navidrome”的限制。音乐存储交给百度网盘,本地保留一个常开的轻量服务入口;代价是更依赖网络、网盘授权和远端接口的稳定性。对已经有 SVIP、R4S 又长期在线的使用场景,这个取舍比较符合我的需求。
参考资料
记录日期:2026 年 11 月 1 日。本文基于一次真实部署,示例中省略了密码、令牌和实际局域网地址;其他设备的软件源、内核依赖、共享账号和启动顺序需要分别核查。