服务卡片 · 媒体
Navidrome:终结流媒体订阅之争的音乐服务器
家里的音乐收藏大约 90GB,这些文件在流媒体出现之前就在机器之间搬来搬去。Navidrome 给它们建索引,通过 Subsonic API 供给任何手机或浏览器,占 140MB 内存。它待在这台机架上而不是某个订阅服务里,理由不是省钱——而是你 2009 年买的那张专辑,在你搬去的国家没有授权。
| 容器镜像 | deluan/navidrome:0.54.4 |
|---|---|
| 宿主端口 | :4533/tcp |
| 数据目录 | /srv/homelab/navidrome/data |
| 内存预留 | 140 MB |
| CPU 上限 | 0.25 vCPU (cpus: "0.25") — transcoding happens only for clients that ask for it |
| 更新节奏 | twice a year. The Subsonic API it implements is stable and the database migrates in place |
| ARM 兼容 | arm64 native; the transcoder shells out to ffmpeg, which is included in the image and does have the AAC encoder this time |
| 宿主 | 容器 | proto | 暴露 | 用途 |
|---|---|---|---|---|
| :4533 | 4533 | tcp | 仅局域网 | web player and the Subsonic API that every mobile client speaks |
部署步骤
音乐目录只读挂载,并给转码缓存设上限
只读是为了不让扫描器的一个缺陷重排一个花了好几年才整理好标签的归档。缓存上限则避免一种几个月后才显现的慢性磁盘泄漏。
run sudo mkdir -p /srv/homelab/navidrome/data sudo chown -R 1000:1000 /srv/homelab/navidrome # compose:- /mnt/nas/music:/music:ro在别人能访问到界面之前建好管理员账号
第一个访问注册页的人会成为管理员。要在容器首次运行那天、在局域网内把这个做掉,而不是等哪天有人顺手打开它。
run cd /srv/homelab/navidrome && docker compose up -d docker logs --tail 20 navidrome # 打开 http://192.168.10.20:4533 创建管理员账号跑第一次扫描,和你知道的数量对一下
扫描是唯一吃 CPU 的时刻。如果专辑数高得离谱,原因几乎总是专辑艺术家标签缺失或不一致,而不是服务端的问题。
run docker exec navidrome navidrome scan docker exec navidrome navidrome scan --help # 然后拿专辑数和 NAS 上的目录数对一遍
音乐只读,只有元数据可写
音乐目录以只读挂载。Navidrome 不会把标签写回文件;它把标签读进自己的数据库。这意味着 NAS 上的媒体库永远不会被这个服务碰到,直接消掉了一整类事故。
相应的代价是,改一个错误的标签要在 NAS 上改文件,然后等下一次扫描。扫描每十二小时一次,手动扫描就是一个按钮。
docker exec navidrome navidrome scan --help
# 批量改过标签后做完整重扫:
docker exec navidrome navidrome scan -f转码是按客户端决定的
在局域网内,什么都不该转码:手机直接播 FLAC,派完全不干活。转码存在的意义是走移动网络时,原始 900kbps 的 FLAC 超出了那条线路想要的码率。
真正重要的设置是并发上限。在派上同时转两路会占满 CPU、音乐卡顿——对一个音乐播放器来说,这是最糟糕的失败方式。一次一路,第二个客户端等着。
| 客户端 | 请求什么 | 派的 CPU 开销 |
|---|---|---|
| 局域网内的浏览器 | 原始文件 | 无 |
| 局域网内的手机 | 原始文件 | 无 |
| 走移动网络的手机 | opus 或 128k 的 mp3 | 约单核的 15% |
| 两部手机走移动网络 | 第二个等待 | 仍然只用一个核 |
客户端,以及真正重要的那一个
值得用的客户端都讲 Subsonic API,所以同一个服务端能在 iOS、安卓和桌面上都用。安卓上 Symfonium 或 DSub,iOS 上 play:Sub 或 substreamer,桌面上网页界面诚实且够用。
网页界面是搭家庭歌单的地方,手机客户端是用它们的地方。两边的播放次数会合并,因为次数存在服务端——这正是它比网络共享上的一个文件夹强的地方。
compose 文件
整份文件放在 /srv/homelab/navidrome/compose.yaml。标签固定版本号,不用 latest——树莓派上回滚比升级麻烦得多。
services:
navidrome:
image: deluan/navidrome:0.54.4
container_name: navidrome
restart: unless-stopped
ports:
- "4533:4533/tcp"
environment:
TZ: Asia/Shanghai
ND_LOGLEVEL: info
ND_MUSICFOLDER: /music
ND_DATAFOLDER: /data
ND_SCANSCHEDULE: "@every 12h"
ND_TRANSCODINGCACHESIZE: 200MB
ND_MAXCONCURRENTTRANSCODES: "1"
ND_ENABLEFAVOURITES: "true"
ND_ENABLESHARING: "false"
ND_DEFAULTDOWNLOADSIZE: "0"
volumes:
- /srv/homelab/navidrome/data:/data
- /mnt/nas/music:/music:ro
networks: [rack]
networks:
rack:
external: true加固清单
- 音乐目录以只读挂载,扫描器的缺陷伤不到媒体库
- 账号逐个创建,来宾账号关闭;不启用任何公开分享功能
- 这个服务在反向代理上没有路由,所以不存在可供猜测的公开地址
- 转码限制为一并发任务,这既是 CPU 措施,也是防拒绝服务的措施
备份方案
音乐库本身在 NAS 上,这里不复制,容器只读它。要备份的是数据目录,里面有歌单、播放次数和用户账号——很小,而且正是重新扫描也重建不出来的那部分。
上线后验证
- 首次扫描完成,专辑数量和你所知道的媒体库内容一致
- 手机在局域网内播放 FLAC 时,派上没有任何 CPU 尖峰
- 同一部手机走移动网络时拿到的是转码流,派上显示一个核被部分占用
- 在网页界面标了收藏的曲目,在手机客户端里也是收藏
踩过的坑
- 扫描挂在 NFS 或 SMB 上的媒体库,比本地磁盘慢得多;90GB 的完整扫描走网络要好几个小时。把扫描排在夜里,日常用增量扫描。
- 转码缓存的默认大小会和平常一切共用那块固态盘并持续增长。限制在 200MB 可以避免一种几个月后才显现的慢性泄漏。
- 多碟专辑和合辑依赖标签一致。Navidrome 只读标签,不会修标签;标得糟糕的合辑会显示成十二张只含一首歌的专辑,而修的地方在文件里。
- 默认管理员账号在首次运行时创建,密码由你在界面里设定。要在别人能访问到界面之前把它建好,因为第一个访问者就成了管理员。
硬件与选型问答
- 音乐用 Navidrome 还是 Jellyfin?
- Jellyfin 能放音乐,它的音乐支持也算可用。Navidrome 在三件事上更好:Subsonic 客户端比 Jellyfin 的音乐客户端更成熟,扫描器更快也更容忍混乱的标签,而且内存占用只是零头。如果你已经为了视频跑了 Jellyfin,先试试它的音乐部分也很合理。
- 支持 CarPlay 和 Android Auto 吗?
- 通过客户端 App 支持:Symfonium 支持 Android Auto,play:Sub 支持 CarPlay。网页界面在车里没法用,这不是服务端的限制,但挑客户端时值得知道。
- 派能扛多大的媒体库?
- Pi 4 大约十五分钟索引一万首,十万首也没问题。数据库停在几百 MB 的量级,而播放本身不花什么——它就是一次文件读取加一个 HTTP 响应。