为什么要在自己的服务器上搭一套音乐流媒体
做站长这些年,我越来越依赖自托管。照片有 Immich,影视有 Jellyfin,但音乐一直是个空白——直到我用上了 Navidrome。它解决的是一个很具体的问题:我的音乐散落在好几块硬盘、几个网盘和一堆旧手机备份里,想听一首歌得先想起来它在哪台设备上。更要命的是,网易云、QQ 音乐这些平台的曲库会随着版权到期不断变灰,你收藏了十年的歌单,可能某天早上起来一半都放不了了。
本文记录的是我把几十个 GB 的本地音乐库搬上服务器、用 Navidrome 做成私人流媒体、再通过 Nginx 反代加 HTTPS 对外提供服务的完整过程。全程 Docker 部署,一台 1 核 1G 的小机器就能跑,手机、电脑、车机都能连。文末我会总结个人站长搭这套系统最容易踩的六个坑。
Navidrome 是什么,为什么选它而不是别的
Navidrome 是一个开源的音乐流媒体服务器,它实现了 Subsonic API。这句话有两个关键信息:第一,它自己不带曲库,你放什么它就播什么,版权问题不存在;第二,因为兼容 Subsonic API,你能用市面上几乎所有「Subsonic 客户端」App(Android 的 DSub、Symfonium,iOS 的 play:Sub、iSub,桌面端的 Sonixd、Feishin),选择面极宽。
和同类方案对比,它的定位很清楚:
- Plex / Emby 的音乐模块:功能全,但音乐只是附庸,索引逻辑偏视频,且闭源收费、要连它们的服务器验证。Plex 一旦检测不到授权服务器,你自己买的音乐都听不了。
- Airsonic / Airsonic-Advanced:Subsonic 的老牌 fork,Java 写的,功能多但配置繁琐、界面老旧,内存占用也大。Navidrome 是 Go 写的单二进制,把「够用、轻、快」做到了极致。
- Jellyfin 的音乐库:也能放音乐,但 Jellyfin 的资源大头给了转码和影视刮削,纯听歌场景下 Navidrome 的资源占用和扫描速度都明显更优。
- 自己写 API + 前端:除非你有特殊需求,否则没必要重复造轮子。
一句话总结:Navidrome = Subsonic 协议 + 单二进制 + 自动扫描 + 移动端 App 生态。对个人站来说,这就是最优解。
部署前的准备:目录规划与音乐整理
很多人一上来就 docker run,结果音乐库扫描出来一堆乱码、封面全错、整张专辑被拆成十几首单曲。问题不在 Navidrome,而在元数据。Navidrome 靠读取音频文件的 ID3 标签(标题、艺术家、专辑、曲目号、封面)来建立索引,如果你的文件名是「周杰伦 - 青花瓷.mp3」但从没写过标签,它就只能靠文件名猜,猜错的概率很高。
我的建议是先用 MusicBrainz Picard 或者 Mp3tag 把标签整理一遍,至少要保证「艺术家 / 专辑 / 曲目号 / 标题」四项齐全。目录结构推荐这种经典布局:
/music/
华语/
周杰伦/
2007 - 我很忙/
01 - 牛仔很忙.mp3
02 - 彩虹.mp3
欧美/
Coldplay/
2000 - Parachutes/
01 - Don't Panic.mp3
注意两点:第一,专辑文件夹里最好放一张 cover.jpg,Navidrome 会优先读它做封面,比嵌入图片更省解析时间;第二,不要用中文全角的括号和斜杠,某些客户端在拼接 URL 时会把它们转义得一塌糊涂,导致播放 404。
服务器上我习惯这样规划:
/opt/navidrome/ # 部署目录,放 docker-compose.yml /data/music/ # 音乐文件(只读挂载进容器) /data/navidrome/data/ # 数据库、缓存、封面(必须可写)
这里有个新手最容易忽略的点:Navidrome 会在 data 目录里存一个 SQLite 数据库和它自己生成缩略图缓存,这个目录会随着曲库增大而变大,一定要放在空间充足的盘上,别顺手塞进系统盘。
用 Docker Compose 把 Navidrome 跑起来
官方镜像 deluan/navidrome 已经很成熟,我直接用 Compose 管理,方便升级和迁移。写一个 /opt/navidrome/docker-compose.yml:
services:
navidrome:
image: deluan/navidrome:latest
container_name: navidrome
user: "1000:1000" # 用非 root 跑,宿主机 music 目录属主也要对上
restart: unless-stopped
ports:
- "127.0.0.1:4533:4533" # 关键:只绑回环,公网访问走 Nginx 反代
environment:
ND_SCANSCHEDULE: "1h" # 每小时增量扫描一次
ND_LOGLEVEL: "info"
ND_SESSIONTIMEOUT: "24h"
ND_BASEURL: "" # 反代到子域名时留空
ND_ENABLEGRAVATAR: "false"
volumes:
- "/data/music:/music:ro" # 音乐只读挂载,防止误删
- "/data/navidrome/data:/data"
几个参数值得解释一下。user: "1000:1000" 让容器以 uid 1000 运行,你必须保证宿主机 /data/music 和 /data/navidrome/data 的属主也是 1000,否则会出现「容器起来了但扫描不到任何歌」或者「数据库没权限写入」的问题,命令是 chown -R 1000:1000 /data/music /data/navidrome/data。
ports 里写 127.0.0.1:4533 而不是 4533 是安全底线。Navidrome 默认没有强认证、也没有防爆破,直接暴露到公网等于把你的整个音乐库送人,还有被扫到弱密码入侵的风险。所以端口只绑本机,外部通过 Nginx 反代 + HTTPS 访问。
启动:
cd /opt/navidrome docker compose up -d docker compose logs -f navidrome # 看日志里有没有 "Scanning" / "Server listening"
首次启动它会开始扫描音乐库。几十 GB 的库扫描可能要几分钟到十几分钟,取决于文件数量和磁盘速度。日志里出现 Scan complete 就说明好了。此时本地 curl http://127.0.0.1:4533/ping 应该返回一段 HTML(那是 Web UI),说明服务活着。
初始化管理员账号与基本设置
第一次访问 Web UI(我用 SSH 隧道 ssh -L 4533:127.0.0.1:4533 user@server,然后本地浏览器开 http://127.0.0.1:4533)会让你创建管理员账号和密码。这个账号同时用于客户端登录,务必设一个强密码。
登进去之后,先去「设置」里改几个默认值:
- 扫描计划(Scan Schedule):默认是
0(不自动扫),改成1h或0 */6 * * *。这样你往目录里丢新歌,最多一小时后就能在 App 里看到。 - 转码设置(Transcoding):Navidrome 支持按比特率转码,方便在弱网下播放。但如果你服务器 CPU 很弱(比如 1 核的小机器),建议关掉或只保留一个低码率档,避免多端同时播放时把 CPU 打满。
- Last.fm 刮削:可选。开了之后它会用 Last.fm 补全缺失的艺术家简介和相似歌手,但需要科学的网络环境,国内服务器常常连不上,反而不如关掉专注本地标签。
这里提醒一句:Navidrome 的 Web UI 本身是简/繁中文可选的,但客户端 App 显示什么语言取决于 App 自己。子域名建议用 music.你的域名 这种好记的形式。
用 Nginx 反代并加上 HTTPS
把 4533 端口包进一个带证书的域名,是这套系统能不能日常用的关键。Nginx 配置大致如下:
server {
listen 443 ssl http2;
server_name music.example.com;
ssl_certificate /etc/letsencrypt/live/music.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/music.example.com/privkey.pem;
client_max_body_size 100M; # 网页端上传/歌单导入时用得上
location / {
proxy_pass http://127.0.0.1:4533;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade"; # WebSocket,用于实时刷新
proxy_buffering off; # 音频流不要缓冲
proxy_read_timeout 300s;
}
}
要点有三个。第一,proxy_buffering off:音乐流媒体是长连接持续传输,如果开启缓冲,Nginx 会先把数据攒起来再发,导致手机端拖动进度条时卡顿、甚至超时断开。关掉之后数据边收边发,体验顺滑很多。
第二,WebSocket 头必须配:Navidrome 的 Web UI 用 WebSocket 做实时状态刷新(扫描进度、正在播放)。少了 Upgrade 和 Connection 两行,界面看起来能用,但刷新进度永远卡着不动,很容易被误判成服务挂了。
第三,证书用 Certbot 自动续期:certbot --nginx -d music.example.com 一条命令搞定,它会自动写好 443 配置并加续期定时任务。别忘了 systemctl list-timers | grep certbot 确认续期任务真的存在。
另外如果你的流量走 CDN(比如套了 Cloudflare 橙云),记得关掉它对音频流的「缓存」和「 Rocket Loader」,否则会出现间歇性播放失败,排查起来非常痛苦。
手机与桌面客户端的接入方法
Navidrome 自己只有个网页版,日常听歌还得靠 Subsonic 客户端。接入信息就三样:服务器地址(https://music.example.com)、用户名、密码。注意地址要带 https 前缀且不带结尾斜杠,很多客户端对这两个细节很敏感。
- Android:Symfonium(付费但体验最好,支持离线缓存、歌单同步)、DSub(老牌免费)、Tempo(轻量)。填地址后它会自动走 Subsonic API 登录,成功后会拉取你的全部曲库并支持下载离线播放。
- iOS:play:Sub、iSub、Amperfy(开源免费)。iOS 的沙盒机制下离线缓存空间有限,建议在设置里限制缓存上限。
- 桌面:Sonixd(Electron,跨平台)、Feishin(较新,界面现代)。桌面端推荐开「scrobble 到 Last.fm」把播放记录同步出去。
- 车机 / 智能音箱:只要支持 Subsonic 协议就能连;不支持的话可以用
mpd+mpc这类命令行客户端曲线救国。
离线缓存是我最看重的功能。通勤地铁没信号时,提前在 App 里把几张专辑下到本地,Navidrome 只负责播放和同步,不需要我为「在线」付出任何代价。这是我弃用商业平台后最不后悔的一点。
备份、升级与多用户
Navidrome 的数据分两块,备份策略也不一样。音乐文件本身(/data/music)可以用 rsync、restic 之类的工具按普通文件备份,这块只增不改,增量备份很便宜。真正需要小心的是 /data/navidrome/data 里的 SQLite 数据库——它记录着用户、播放次数、歌单、收藏、星标。备份这个库有两种办法:一是简单粗暴地 docker compose stop navidrome 后打包整个 data 目录;二是热备份,sqlite3 navidrome.db ".backup /tmp/navidrome-backup.db",SQLite 的 .backup 命令在写入时也能保持一致快照。
我个人的做法是每天晚上 cron 跑一次 sqlite3 .backup 导出到异地,再让 restic 把音乐文件每周同步一次。这样即使服务器炸了,最坏也就丢一天的播放记录。
升级非常简单:docker compose pull && docker compose up -d。Navidrome 会在启动时自动做数据库迁移,一般不会有问题。但升级前务必先备份 data 目录——历史上出现过某次版本迁移不兼容旧库导致歌单丢失的情况,备份是你唯一的安全绳。
多用户方面,Navidrome 支持在设置里开「允许用户注册」,也可以管理员手动建号。每个用户的播放记录、收藏、歌单互相隔离,适合家庭共享。团队或朋友共享时,建议给每人单独开号并限制转码权限,避免一个人把 CPU 跑满影响所有人。
六个最容易踩的坑
- 端口直接暴露公网:4533 无强认证,暴露等于音乐库裸奔。永远只绑 127.0.0.1,外部走反代 + HTTPS。
- 音乐目录权限不对:容器以非 root 跑,宿主机目录属主必须匹配,否则扫描不到歌。用
chown -R 1000:1000统一。 - 忘了
proxy_buffering off:不关缓冲,播放时拖动进度条必卡,还会导致连接超时。 - data 目录放系统盘:封面缓存和数据库会越来越大,塞满根分区会连累整个系统。
- 元数据全靠文件名猜:标签不全就会专辑拆散、封面错乱,先整理 ID3 再入库,一劳永逸。
- 升级前不备份:数据库迁移是不可逆的,升级前先
.backup一份,几十秒的事能救命。
搭好之后你会发现,自建音乐流媒体的意义不只是「省了会员费」,而是你终于对自己的聆听记录有了完全的控制权——歌单不会因为平台版权变动而消失,播放历史存在自己的数据库里,换设备换平台都能迁移。这才是自托管的真正价值。