SSD Nodes Learn 🎉 VPS $5.50/月起
指南 Matt Connor作者: Matt Connor

如何在VPS上自托管音乐流媒体:Navidrome指南

在VPS上部署Navidrome,使用Subsonic客户端从手机播放自有音乐。本文涵盖0.63.2版本、存储估算、离线同步、TLS配置与安全备份。

VPS 上自托管音乐流媒体的作用

在 VPS 上自托管音乐流媒体,意味着您运行播放器,并自行提供音乐。服务器保存您已经拥有的音乐文件,任何手机都可以使用普通登录方式通过互联网访问它。开始前应明确这一取舍:它替代的是流媒体服务的播放器,而不是其音乐目录。只有在您购买或翻录音乐,并将文件复制到服务器后,音乐库中才会出现新内容。

音频对服务器的要求远低于视频。音频文件较小,手机无需额外处理即可解码常见格式,而且一名听众占用的带宽低于视频通话。在这里,CPU 通常不是问题。真正受限的是磁盘空间。决定方案能否正常使用的另外两个因素是标签质量,以及手机应用是否支持下载音乐供离线播放。

Navidrome 是只需要音频功能时的默认选择。它是单个容器中的一个 Go 二进制文件,并将状态保存在一个 SQLite 数据库中。它提供 Subsonic API,这也是大量第三方手机应用得以存在的原因。2026 年 8 月,当前版本为 0.63.2。该项目称它可以在小至 Raspberry Pi Zero 的硬件上良好运行,因此服务器软件本身不是主要成本。

如果您已经在 VPS 上运行 将 Jellyfin 用作媒体服务器来处理视频,那么可以使用 Jellyfin。它的音乐库可以正常工作,Finamp 是适用于 Android 和 iOS 的 Jellyfin 音乐应用,支持下载曲目以供离线收听。限制在于 API。Jellyfin 没有内置的 Subsonic 端点,而添加该功能的社区插件已于 2022 年停止更新,因此 Subsonic 应用生态系统无法使用 Jellyfin。您只能使用支持 Jellyfin 自有 API 的应用,而这类应用更少。

Funkwhale 是联邦化选项,2.0 版本于 2026 年 3 月发布。Funkwhale 服务器称为 pod,pod 通过 ActivityPub(Mastodon 使用的协议)进行联邦通信,一个 pod 上的用户可以关注另一个 pod 上的公共媒体库。它也支持部分 Subsonic API,但有一个需要注意的区别:每个用户都要在自己的设置中单独设置 Subsonic 密码,因为 Subsonic 协议要求服务器能够读取密码。Funkwhale 的安装更复杂,因为 Web 应用之外还需要 PostgreSQL 和任务队列。

除非您需要联邦功能,或已经在运行 Jellyfin,否则请选择 Navidrome。本指南的其余部分将使用 Docker 部署 Navidrome。

Subsonic API 如何决定您使用哪款手机应用

Subsonic 是一种音乐服务器,其 HTTP API 后来成为自托管音频服务的通用接口。OpenSubsonic 是负责持续扩展该接口的社区项目。这段历史解释了为什么您可以选择手机应用。Navidrome 不提供自己的移动应用,也不需要这样做,因为任何 Subsonic 客户端都可以使用服务器地址和您的账户信息登录。

离线同步最能体现这一点,因为它决定了这套配置能否适应日常使用。手机进入隧道后无法连接服务器,因此客户端必须提前将文件复制到本地存储。所有客户端都支持串流,但只有部分客户端支持下载。位于 navidrome.org/apps 的客户端目录会说明哪些客户端支持下载。两个平台都有多种选择:Android 上有 Substreamer 和 Ultrasonic,iOS 上有 Amperfy 和 play:Sub。功能最强的客户端中有多款是付费应用,而 Android 上最常被提到的是 Symfonium。请先安装两款再做决定,因为这是您每天使用这套系统时接触最多的部分。

音乐库需要多少存储空间?

ChartStorage per 1,000 albums by audio format
The data behind this chart
[
  {
    "label": "Opus 128k",
    "kbps": 128,
    "gb_per_1000_albums": 43
  },
  {
    "label": "MP3 320k",
    "kbps": 320,
    "gb_per_1000_albums": 108
  },
  {
    "label": "FLAC 16/44.1",
    "kbps": 900,
    "gb_per_1000_albums": 304
  },
  {
    "label": "FLAC 24/96",
    "kbps": "3,000",
    "gb_per_1000_albums": "1,013"
  }
]

这些是根据比特率推算出的数量级,不是对实际音乐库的测量结果。计算方法足够简单,您可以用自己的文件进行核对。将一张专辑按 45 分钟计算,即 2,700 秒。将每秒千比特数乘以 2,700,再除以 8,000,即可得到 MB。在 320 kbps 下,一张专辑需要 108 MB,因此一千张专辑约需 108 GB。

无损格式会改变结果。对于普通录音,CD 音质的 FLAC 平均接近 900 kbps,因此同样的一千张专辑约需 304 GB。24 bit、96 kHz 的音乐库大约需要 1,013 GB;对于一套可以列在纸上的音乐库,这已经是整整 1 TB。适合手机播放的 128 kbps Opus 副本,则可将同样的一千张专辑压缩到 43 GB。对现有音乐库运行 du -sh /path/to/music,因为您自己的平均比特率是在选择方案时唯一重要的数值。

带宽只占费用中较小的一部分。320 kbps 的音频流每秒传输 40 KB,因此听一小时约传输 144 MB。每月收听 100 小时约消耗 14 GB,VPS 的流量额度通常不会受到影响。例外是手机首次进行离线同步时,一个晚上可能传输数十 GB。

存储层还是计算层?

音乐服务器通常只是大量冷数据的存储,几乎不需要计算。以每秒 40 kilobytes 的速度读取文件时,任何磁盘都处于空闲状态。CPU 只会在扫描媒体库或转码时工作,而您通常不会进行转码。因此,计算型方案中的高速 NVMe 在这里没有实际价值;真正阻止您上传 FLAC 副本的是其每 GB 的价格。这正是存储型 VPS 优于普通 VPS的情况,因为这类方案按 TB 而不是按 CPU 核心计费。

内存需求不高。Navidrome 为个人媒体库提供服务时只需几百 MB,扫描过程的内存峰值高于播放过程。为服务器配置 1 GB 或 2 GB RAM,然后将剩余预算用于磁盘。

使用 Docker Compose 安装 Navidrome

首先创建目录,并将其所有者设置为容器运行时使用的用户 ID。如果您不熟悉 Compose,请参阅VPS 上的 Docker Compose,其中介绍了本文件的前提条件。

sudo install -d -m 755 -o 1000 -g 1000 /srv/navidrome /srv/music

在单独的目录中写入 docker-compose.yml,不要添加其他内容:

services:
  navidrome:
    image: deluan/navidrome:0.63.2
    user: "1000:1000"
    ports:
      - "127.0.0.1:4533:4533"
    restart: unless-stopped
    environment:
      ND_LOGLEVEL: "info"
      ND_SESSIONTIMEOUT: "24h"
      ND_SCANNER_SCHEDULE: "@every 24h"
      ND_BACKUP_PATH: "/data/backup"
      ND_BACKUP_SCHEDULE: "0 4 * * *"
      ND_BACKUP_COUNT: "7"
    volumes:
      - /srv/navidrome:/data
      - /srv/music:/music:ro
docker compose up -d
docker compose ps

docker compose ps 应显示服务正在运行,而不是不断重启。容器循环重启几乎总是因为 /srv/navidrome 的权限存在问题,docker compose logs navidrome 会指出它无法写入的文件。

该文件中有 4 个细节需要说明。端口仅发布到 127.0.0.1,因此服务器可通过反向代理访问,而不会通过 4533 端口直接暴露在公网中:Docker 会自行写入防火墙规则,因此即使在 ufw 报告所有连接均被拒绝的服务器上,普通的 4533:4533 仍会保持暴露。音乐目录以只读方式挂载,因此扫描器漏洞不会删除唯一的音乐副本。ND_SCANNER_SCHEDULE 默认处于禁用状态,在 Navidrome 0.55 之前编写的指南将其称为 ND_SCANSCHEDULE,但该名称已不存在。最后 3 个备份设置会启用内置数据库备份,下面的备份部分依赖此功能。

将音乐导入服务器

使用 rsync 将音乐库复制到服务器。连接中断后,rsync 可以继续传输,而不必从头开始。

rsync -av --info=progress2 ~/Music/ user@music.example.com:/srv/music/

源路径末尾的斜杠很重要。省略斜杠会得到 /srv/music/Music。复制完成后,修正所有权:

sudo chown -R 1000:1000 /srv/music
id -u

容器以用户 ID 1000 运行,挂载点为只读,因此每个文件都必须允许该 ID 读取。如果您的 SSH 账户在 VPS 上的 UID 不是 1000,复制的文件就会归其他用户所有,扫描结果会显示 0 个音轨,而 Web 界面仍然为空。id -u 会输出您的实际 ID,Docker 容器中的 PUID 和 PGID 工作方式会完整说明这种映射。

反向代理和 TLS,让手机可以从任何地方访问

将 DNS A 记录指向 VPS,然后为 Caddy 添加以下三行:

music.example.com {
    reverse_proxy 127.0.0.1:4533
}
sudo systemctl reload caddy

Caddy 会在收到第一个请求时申请证书。80 和 443 端口都必须开放,因为 ACME(自动证书管理环境)质询通过 80 端口完成。在 nginx 中,将 proxy_buffering off; 添加到 location 块:Navidrome 通过一条长连接向 Web 界面推送进度事件。启用缓冲后,界面会一直等待 nginx 仍在持有的响应。如果通过 /music 这类路径提供服务,而不是使用独立子域名,请将 ND_BASEURL 设置为相同路径,否则界面会加载为空白页面。VPS 上的 Nginx、Caddy 和 Traefik 对比了这三种常用代理。

打开网站并创建第一个账户。系统没有默认密码,首位访问者需要创建管理员用户。因此,在告知他人地址前完成此操作。然后测试手机客户端使用的确切路径:

SALT=$(openssl rand -hex 6)
TOKEN=$(printf '%s%s' 'YOUR_PASSWORD' "$SALT" | md5sum | cut -d' ' -f1)
curl -s "https://music.example.com/rest/ping.view?u=YOUR_USER&t=$TOKEN&s=$SALT&v=1.16.1&c=curl&f=json"

正常响应以 {"subsonic-response":{"status":"ok" 开头,并将 navidrome 标识为服务器类型。正文包含 "status":"failed" 且错误代码为 40,表示代理正常,但凭据错误。此时应首先修复证书错误,因为大多数手机客户端会拒绝不正确的证书,并向用户显示没有实际帮助的信息。

首次扫描后,为什么媒体库显示不正确

Navidrome 按标签而不是按文件夹浏览,因此标签决定了您看到的内容。没有专辑艺术家标签的曲目会归到其曲目艺术家名下,这就是为什么一张每首曲目艺术家都不同的合辑会变成 20 张各只有 1 首曲目的专辑。请直接修复文件中的标签,不要在 Navidrome 中修复:MusicBrainz Picard 和 beets 都会在 MusicBrainz 数据库中查询专辑,并将标准标签写回文件。

Navidrome 还会将包含多个艺术家的标签拆分为独立艺术家。因此,艺术家名称中包含分隔符的乐队可能会被错误拆分,AC/DC 就是最常见的例子。ND_SCANNER_ARTISTSPLITEXCEPTIONS包含绝不能拆分的名称。

新文件写入后,文件监视器会在几秒内发现这些文件。文件监视器依赖内核变更通知,而从另一台计算机挂载的网络共享中的文件不会触发此类通知。因此,在这种环境中,定期执行 ND_SCANNER_SCHEDULE 才能保持媒体库最新。完整重新扫描会读取每个文件的标签,在大型媒体库中速度较慢;这也是值得保护下方数据库的原因之一。

用户、播放列表和共享

管理员在 Web 界面中创建其他账户,不支持用户自行注册。每个用户都有独立的播放次数、播放列表、收藏和评分,因此家庭成员不会共用同一个偏好档案。

播放列表有两种来源。在客户端中创建的播放列表存储在数据库中。将 .m3u 文件放入媒体库目录后,扫描时会导入该文件。这是在桌面播放器和服务之间迁移播放列表的简单方法。智能播放列表使用 .nsp 文件,即内容简短的 JSON 规则文件,会以相同方式导入,并在媒体库发生变化时自动更新。

从 2026 年 7 月发布的版本 0.63.0 开始,共享功能默认启用。用户可以为专辑创建公开链接,任何人无需登录即可打开该链接。如果服务器保存了完整的媒体库,这种设置可能并不符合需求。将 ND_ENABLESHARING 设置为 false 可关闭该功能。

单独备份数据库和音乐文件

Navidrome 自带的备份功能只覆盖数据库。文档对此说明得很直接:备份过程会备份数据库,包括用户、播放次数及其他数据,但不会备份音乐文件或配置。应按这个边界理解备份,因为这两部分的故障方式不同。音乐文件可以从存放源文件的磁盘再次复制。播放次数、评分、收藏和播放列表不会在其他位置保存,重新扫描也无法恢复这些数据。

compose 文件已将每晚生成的副本写入 /data/backup,并保留其中 7 个。升级前手动执行一次备份:

sudo docker compose run --rm navidrome backup create

恢复操作会删除当前数据库,并将备份复制到原位置,而且必须在 Navidrome 停止运行时执行。在线服务器上执行恢复操作并不安全。

这些文件仍存放在同一台 VPS 上,因此 VPS 故障时它们也无法保留。按计划将 /srv/navidrome 推送到另一台机器或对象存储。restic 和 BorgBackup 就是为此类任务设计的。整个目录很小,通常远低于 1 GB,因此每天将加密副本备份到服务器之外几乎没有成本,却能恢复重新扫描无法找回的全部数据。

FAQ

我需要在 VPS 上转码音乐吗?

几乎不需要。手机和浏览器可以自行解码 MP3、AAC、Opus 和 FLAC,因此服务器按原文件发送,几乎不占用 CPU。只有一种情况值得启用转码:通过移动数据流式传输 FLAC 音乐库时,将约 900 kbps 转换为 128 kbps 的 Opus,可将数据用量减少约 7 倍。Navidrome 可以按用户和播放器分别启用转码,默认保持关闭,直到您手动开启。

为什么我的手机应用无法下载音乐以供离线收听?

因为离线存储是客户端功能,不是服务器功能。Subsonic API 允许任何客户端获取完整文件,但是否在手机上保留副本由应用决定。请查看 navidrome.org/apps 中的客户端目录,选择描述中提到离线下载或缓存的客户端。有些客户端只会缓存您已经播放过的内容,这不同于在出行前同步整张专辑。

为什么扫描后,一张专辑被拆分成了多张专辑?

因为曲目中的专辑艺术家标签缺失,或各曲目之间不一致。Navidrome 按标签而不是按文件夹分组,因此 12 首曲目如果有 12 个不同的艺术家值,且没有共同的专辑艺术家值,就会被识别为 12 张专辑。为该专辑的每首曲目设置专辑艺术家标签;对于合辑,通常设置为 Various Artists,然后让 Navidrome 重新扫描。MusicBrainz Picard 或 beets 可以一次处理整个文件夹。

自托管音乐流媒体能取代 Spotify 吗?

它能取代播放器和音乐库,但不能取代曲库。您可以在每台设备上访问自己的音乐收藏,并保留播放列表和播放次数;这些内容不会因授权变更而被平台收回。但您不会获得新发行内容,也不会获得基于他人收听记录生成的推荐。大多数运行此类服务的人会购买自己的音乐,同时保留一个价格低廉的流媒体账户用于发现新音乐。

#navidrome#music#streaming#自托管#media-server