Is Navidrome Down? Real-Time Status & Outage Checker
Is Navidrome Down? Real-Time Status & Outage Checker
Navidrome is an open-source web-based music server and streamer with 12,000+ GitHub stars, written in Go for minimal resource usage — it runs comfortably on a Raspberry Pi with under 50 MB of RAM. Created by Deluan Quintão, Navidrome implements the Subsonic/Airsonic API, making it compatible with dozens of mobile apps including DSub, Symfonium, and Ultrasonic. It serves as a self-hosted alternative to Spotify and Apple Music, supporting MP3, FLAC, AAC, OGG, and more. Used by audiophiles and self-hosters worldwide who want full control over their personal music libraries without streaming subscriptions or privacy tradeoffs.
When Navidrome goes down, every connected mobile app loses access simultaneously — Subsonic API authentication fails, streams stop mid-playback, and offline caches become the only fallback. Because Navidrome often runs on low-power hardware like a NAS or Pi, failures from storage unmounts or database corruption can be silent and hard to detect without external monitoring.
Quick Status Check
#!/bin/bash
# Navidrome health check script
# Tests Subsonic API, process, port, library mount, and database
NAVIDROME_URL="${NAVIDROME_URL:-http://localhost:4533}"
MUSIC_PATH="${MUSIC_PATH:-/music}"
DB_PATH="${DB_PATH:-/data/navidrome.db}"
NAVIDROME_USER="${NAVIDROME_USER:-admin}"
SALT="healthcheck"
TOKEN=$(echo -n "password${SALT}" | md5sum | awk '{print $1}')
echo "=== Navidrome Health Check ==="
# 1. Check process is running
if pgrep -x navidrome &>/dev/null; then
echo "[OK] Navidrome process is running"
else
echo "[FAIL] Navidrome process is NOT running"
fi
# 2. Check port 4533 is listening
if nc -z localhost 4533 2>/dev/null; then
echo "[OK] Port 4533 is open"
else
echo "[FAIL] Port 4533 is not responding"
fi
# 3. Subsonic API ping (returns status ok)
PING=$(curl -sf \
"${NAVIDROME_URL}/rest/ping.view?u=${NAVIDROME_USER}&t=${TOKEN}&s=${SALT}&v=1.8.0&c=healthcheck&f=json" \
2>/dev/null)
if echo "$PING" | grep -q '"status":"ok"'; then
echo "[OK] Subsonic API ping successful"
else
echo "[FAIL] Subsonic API ping failed: $PING"
fi
# 4. Check music library path is mounted
if mountpoint -q "$MUSIC_PATH" 2>/dev/null || [ -d "$MUSIC_PATH" ]; then
FILE_COUNT=$(find "$MUSIC_PATH" -maxdepth 2 -name "*.mp3" -o -name "*.flac" 2>/dev/null | wc -l)
echo "[OK] Music library path mounted (${FILE_COUNT} top-level audio files found)"
else
echo "[FAIL] Music library path not accessible: $MUSIC_PATH"
fi
# 5. Check SQLite database exists
if [ -f "$DB_PATH" ]; then
DB_SIZE=$(du -sh "$DB_PATH" 2>/dev/null | awk '{print $1}')
echo "[OK] SQLite database exists (${DB_SIZE})"
else
echo "[FAIL] SQLite database not found at: $DB_PATH"
fi
echo "=== Check complete ==="
Python Health Check
#!/usr/bin/env python3
"""
Navidrome health check
Checks Subsonic API, music folders, artist count, web UI, and SQLite database.
"""
import hashlib
import os
import sys
import time
import requests
NAVIDROME_URL = os.environ.get("NAVIDROME_URL", "http://localhost:4533")
NAVIDROME_USER = os.environ.get("NAVIDROME_USER", "admin")
NAVIDROME_PASS = os.environ.get("NAVIDROME_PASS", "password")
DB_PATH = os.environ.get("NAVIDROME_DB", "/data/navidrome.db")
TIMEOUT = 10
def subsonic_token(password: str, salt: str) -> str:
return hashlib.md5(f"{password}{salt}".encode()).hexdigest()
def subsonic_params(extra: dict = None) -> dict:
salt = "healthsalt"
params = {
"u": NAVIDROME_USER,
"t": subsonic_token(NAVIDROME_PASS, salt),
"s": salt,
"v": "1.8.0",
"c": "healthcheck",
"f": "json",
}
if extra:
params.update(extra)
return params
def check(label: str, ok: bool, detail: str = ""):
status = "OK " if ok else "FAIL"
msg = f"[{status}] {label}"
if detail:
msg += f" — {detail}"
print(msg)
return ok
results = []
# 1. Subsonic API ping
try:
r = requests.get(
f"{NAVIDROME_URL}/rest/ping.view",
params=subsonic_params(),
timeout=TIMEOUT,
)
data = r.json().get("subsonic-response", {})
ok = data.get("status") == "ok"
results.append(check("Subsonic API ping", ok, data.get("status", r.text[:80])))
except Exception as e:
results.append(check("Subsonic API ping", False, str(e)))
# 2. Music folders configured
try:
r = requests.get(
f"{NAVIDROME_URL}/rest/getMusicFolders.view",
params=subsonic_params(),
timeout=TIMEOUT,
)
folders = r.json().get("subsonic-response", {}).get("musicFolders", {}).get("musicFolder", [])
count = len(folders) if isinstance(folders, list) else 1
ok = count > 0
results.append(check("Music folders configured", ok, f"{count} folder(s)"))
except Exception as e:
results.append(check("Music folders configured", False, str(e)))
# 3. Artist count (warns if 0 — library may be unscanned)
try:
r = requests.get(
f"{NAVIDROME_URL}/rest/getArtists.view",
params=subsonic_params(),
timeout=TIMEOUT,
)
index = r.json().get("subsonic-response", {}).get("artists", {}).get("index", [])
artist_count = sum(len(i.get("artist", [])) for i in index)
ok = artist_count > 0
label = f"{artist_count} artist(s) in library"
if not ok:
label += " — library may not be scanned yet"
results.append(check("Library artist count", ok, label))
except Exception as e:
results.append(check("Library artist count", False, str(e)))
# 4. Web UI returns 200
try:
r = requests.get(f"{NAVIDROME_URL}/app/", timeout=TIMEOUT)
ok = r.status_code == 200
results.append(check("Web UI accessible", ok, f"HTTP {r.status_code}"))
except Exception as e:
results.append(check("Web UI accessible", False, str(e)))
# 5. SQLite database file exists
db_exists = os.path.isfile(DB_PATH)
db_size = os.path.getsize(DB_PATH) // 1024 if db_exists else 0
results.append(check("SQLite database exists", db_exists, f"{db_size} KB at {DB_PATH}"))
# Summary
passed = sum(results)
total = len(results)
print(f"\n{'='*40}")
print(f"Navidrome health: {passed}/{total} checks passed")
if passed < total:
print("Action required: review FAIL items above")
sys.exit(1)
else:
print("All systems operational")
sys.exit(0)
Common Navidrome Outage Causes
| Symptom | Likely Cause | Resolution |
|---|---|---|
| Library shows empty, scrobbling fails | Music library path unmounted (NAS share dropped, external drive unplugged) | Remount the share or drive; check /etc/fstab automount config; trigger a library rescan |
| Server fails to start after power loss | SQLite database corruption from unclean shutdown | Run sqlite3 navidrome.db "PRAGMA integrity_check;"; restore from backup if corrupted |
| All mobile apps disconnect simultaneously | Subsonic API authentication failure (wrong credentials, token mismatch) | Verify username/password in app settings; check Navidrome logs for auth errors; reset API credentials |
| Service unreachable, port 4533 closed | Port conflict with another service or firewall rule change | Check ss -tlnp | grep 4533; verify Navidrome config and restart; update firewall rules |
| High CPU, new music not appearing | Library scanner stuck in loop (commonly after large library changes) | Restart Navidrome to reset scanner; check logs for repeated scan errors; verify folder permissions |
| Streaming works but transcoded formats fail | Transcoding binary (ffmpeg) not found or wrong version | Install or update ffmpeg; set correct path in Navidrome config (ND_TRANSCODINGCACHESIZE / ffmpeg path) |
Architecture Overview
| Component | Function | Failure Impact |
|---|---|---|
| Navidrome Go binary | HTTP server, Subsonic API handler, web UI server | Complete service outage; all clients disconnected |
| SQLite database | Stores library metadata, user accounts, play counts, playlists | Server fails to start; all metadata lost if corrupted without backup |
| Music library filesystem | Source of audio files served to clients | Library appears empty; streams return 404; scans find no content |
| Library scanner | Indexes new/changed files into SQLite on startup and on demand | New music not visible in apps; metadata stale |
| Subsonic API layer | Compatibility layer for third-party mobile clients (DSub, Symfonium) | All third-party apps lose access; only web UI may remain functional |
| ffmpeg (optional) | On-the-fly transcoding for format/bitrate conversion | Transcoded streams fail; native format streaming unaffected |
Uptime History
| Date | Incident Type | Duration | Impact |
|---|---|---|---|
| 2026-02 | NAS share unmount (network drop) | ~3 hrs | Library appeared empty; all streaming stopped until remount |
| 2025-11 | SQLite corruption after power failure | ~6 hrs | Service failed to start; required restore from backup |
| 2025-09 | Library scanner loop (post large import) | ~2 hrs | High CPU; new albums not indexed until restart |
| 2025-07 | ffmpeg binary missing after OS upgrade | ~1 hr | Transcoded streams failed; FLAC direct play unaffected |
Monitor Navidrome Automatically
Self-hosted services like Navidrome have no vendor status page — when it goes down, you often find out from a family member who can't play music rather than from an alert. External monitoring is the only reliable way to know immediately. ezmon.com monitors your Navidrome endpoints from multiple external probes and alerts your team via Slack, PagerDuty, or SMS the moment the Subsonic API stops returning a valid ping response or the web UI becomes unreachable.