Navidrome¶
Navidrome is a modern self-hosted music server and streamer.
Description¶
It is a high-performance music server that allows you to listen to your music collection from any device. It is compatible with Subsonic/Madsonic API and provides a beautiful web interface.
What it is¶
Navidrome indexes a local music library, serves it through a responsive web UI, and exposes a Subsonic-compatible API for mobile and desktop music clients. It is lightweight enough for small home servers but still supports multi-user libraries, transcoding through ffmpeg, playlists, album art, and external clients.
What problem it solves¶
It turns a folder of owned audio files into a private streaming service. That avoids relying on commercial music subscriptions for personal collections, lets a household keep music available on the LAN/VPN, and gives automation scripts a stable API for library checks.
Where it fits in the stack¶
Navidrome belongs in the media services layer alongside Jellyfin and Audiobookshelf. In a home-office setup, it is usually deployed behind a reverse proxy, backed up with the rest of /data, and pointed at read-only music storage.
Typical use cases¶
- Stream a FLAC/MP3 library to browsers, phones, and Subsonic-compatible clients.
- Maintain family accounts with separate favorites, playlists, and playback state.
- Keep a low-resource music service separate from a heavier video server.
- Expose a music library over Tailscale or a private VPN without publishing file shares.
Strengths¶
- Small operational footprint: Simple single-binary or single-container deployment.
- Client compatibility: Works with many Subsonic-compatible apps.
- Read-only media mounts: Easy to keep the app from modifying source music files.
- Good homelab fit: Configuration can be managed through a TOML file or environment variables.
Limitations¶
- Music-focused: It is not a full video/photo media platform.
- Metadata-dependent: Poor tags lead to poor browsing results.
- Transcoding dependency:
ffmpegmust be available for some formats and clients.
When not to use it¶
Do not use Navidrome as a general media server for video, live TV, or photo libraries; use Jellyfin or Plex for those workloads. If you need audiobook-specific progress handling, chapter metadata, and podcast-style feeds, prefer Audiobookshelf.
Getting started¶
Docker Compose quick start¶
Create a data directory and point the music mount at an existing local music folder:
mkdir -p ./navidrome-data ./music
cat > docker-compose.yml <<'YAML'
services:
navidrome:
image: ghcr.io/navidrome/navidrome:latest
container_name: navidrome
user: "1000:1000"
ports:
- "4533:4533"
restart: unless-stopped
environment:
ND_SCANSCHEDULE: "1h"
ND_LOGLEVEL: "info"
ND_SESSIONTIMEOUT: "24h"
volumes:
- ./navidrome-data:/data
- ./music:/music:ro
YAML
docker compose up -d
Open http://localhost:4533, create the first admin user, and trigger or wait for the initial library scan.
Minimal configuration file¶
For non-container installs, a minimal navidrome.toml can be:
MusicFolder = "/srv/media/music"
DataFolder = "/var/lib/navidrome"
Address = "0.0.0.0"
Port = 4533
ScanSchedule = "1h"
LogLevel = "info"
CLI examples¶
# Follow startup and scan logs for the container
docker logs -f navidrome
# Confirm the web UI is listening on the default port
curl -I http://localhost:4533
# Check that the container can see mounted music files
docker exec navidrome find /music -maxdepth 2 -type f | head
API examples¶
Navidrome supports the Subsonic API. A basic ping request verifies that API authentication and the server endpoint are working:
: "${NAVIDROME_USER:?set NAVIDROME_USER to a Navidrome user}"
: "${NAVIDROME_PASSWORD:?set NAVIDROME_PASSWORD to that user's password}"
curl "http://localhost:4533/rest/ping.view?u=$NAVIDROME_USER&p=$NAVIDROME_PASSWORD&v=1.16.1&c=home-office&f=json"
Python health check using token authentication:
import hashlib
import secrets
import urllib.parse
import os
import urllib.request
base_url = os.environ.get("NAVIDROME_URL", "http://localhost:4533")
username = os.environ["NAVIDROME_USER"]
password = os.environ["NAVIDROME_PASSWORD"]
salt = secrets.token_hex(6)
token = hashlib.md5(f"{password}{salt}".encode()).hexdigest()
query = urllib.parse.urlencode({
"u": username,
"t": token,
"s": salt,
"v": "1.16.1",
"c": "home-office-check",
"f": "json",
})
with urllib.request.urlopen(f"{base_url}/rest/ping.view?{query}", timeout=10) as response:
print(response.read().decode())
Troubleshooting¶
- If the UI starts but no albums appear, verify Linux permissions with
ls -n ./musicand make the Composeusermatch the folder owner. - If remote clients cannot connect, confirm port
4533is reachable through the firewall, VPN, or reverse proxy. - If some files do not play, install or expose
ffmpegand check whether the client requires transcoding for that format. - If playlists are missing, create the admin user first, then touch
.m3ufiles or trigger a rescan.
Links¶
Alternatives¶
Backlog¶
- Integrate with "Audiobookshelf" for a unified audio library.
Sources / References¶
- https://www.navidrome.org/
- https://www.navidrome.org/docs/installation/
- https://www.navidrome.org/docs/getting-started/
- https://github.com/navidrome/navidrome
- https://airsonic.github.io/
Contribution Metadata¶
- Confidence: high
- Last reviewed: 2026-05-06