Navidrome Music Server Installation
Navidrome is a lightweight, self-hosted music streaming server that implements the Subsonic API, giving you access to a vast ecosystem of compatible mobile and desktop clients for streaming your MP3, FLAC, and other audio collections. With minimal resource requirements and Docker support, Navidrome is an excellent choice for running a personal music server on a VPS alongside other services.
Prerequisites
- Ubuntu 20.04+, Debian 11+, or CentOS/Rocky 8+
- Minimum 256 MB RAM (Navidrome is very lightweight)
- Your music library accessible on the server
- Root or sudo access
- FFmpeg installed (for transcoding)
Installing Navidrome
Method 1: Binary installation:
# Install FFmpeg dependency
sudo apt install -y ffmpeg # Ubuntu/Debian
sudo dnf install -y ffmpeg # CentOS/Rocky (with RPM Fusion)
# Create user and directories
sudo useradd -r -s /bin/false navidrome
sudo mkdir -p /opt/navidrome /var/lib/navidrome /music
# Download the latest release
NAVIDROME_VERSION="0.53.3"
curl -LO "https://github.com/navidrome/navidrome/releases/download/v${NAVIDROME_VERSION}/navidrome_${NAVIDROME_VERSION}_linux_amd64.tar.gz"
# Extract and install
tar -xzf navidrome_${NAVIDROME_VERSION}_linux_amd64.tar.gz
sudo mv navidrome /opt/navidrome/
sudo chown -R navidrome:navidrome /opt/navidrome /var/lib/navidrome
Method 2: Docker Compose (recommended):
sudo mkdir -p /opt/navidrome
sudo tee /opt/navidrome/docker-compose.yml <<'EOF'
version: '3'
services:
navidrome:
image: deluan/navidrome:latest
user: "1000:1000"
ports:
- "4533:4533"
restart: unless-stopped
environment:
ND_SCANSCHEDULE: "1h"
ND_LOGLEVEL: info
ND_SESSIONTIMEOUT: 24h
ND_BASEURL: ""
ND_MUSICFOLDER: /music
volumes:
- /opt/navidrome/data:/data
- /path/to/your/music:/music:ro
EOF
cd /opt/navidrome
sudo docker compose up -d
Create systemd service (binary install):
sudo tee /etc/systemd/system/navidrome.service <<'EOF'
[Unit]
Description=Navidrome Music Server
After=network.target
[Service]
User=navidrome
Group=navidrome
Type=simple
ExecStart=/opt/navidrome/navidrome --configfile /opt/navidrome/navidrome.toml
WorkingDirectory=/opt/navidrome
TimeoutStopSec=20
KillMode=process
Restart=on-failure
RestartSec=5
[Install]
WantedBy=multi-user.target
EOF
sudo systemctl daemon-reload
sudo systemctl enable --now navidrome
Library Configuration
Create the Navidrome configuration file:
sudo tee /opt/navidrome/navidrome.toml <<'EOF'
# Music folder location
MusicFolder = "/music"
# Data directory (database, covers cache)
DataFolder = "/var/lib/navidrome"
# Network settings
Address = "0.0.0.0"
Port = 4533
BaseURL = ""
# Scanning
ScanSchedule = "@every 1h"
ScanOnStartup = true
# Logging
LogLevel = "info"
# Transcoding
DefaultDownsamplingFormat = "opus"
# UI
EnableGravatar = false
EnableStarRating = true
EOF
sudo chown navidrome:navidrome /opt/navidrome/navidrome.toml
Set up your music directory:
# Navidrome expects a standard music directory structure
# Artist/Album/tracks
ls /music/
# Pink Floyd/
# The Dark Side of the Moon/
# 01 - Speak to Me.flac
# 02 - Breathe.flac
# Set permissions
sudo chown -R navidrome:navidrome /music/
# Or read-only if your music is managed elsewhere
sudo chmod -R 755 /music/
Subsonic API and Client Apps
Navidrome is fully compatible with the Subsonic API, giving access to many clients:
Popular Subsonic-compatible clients:
| Platform | Client |
|---|---|
| Android | Subtracks, DSub, Ultrasonic |
| iOS | Amperfy, play:Sub |
| Desktop | Sublime Music, Supersonic |
| CLI | beets, mympd |
Configure a client:
Server URL: https://music.example.com
Username: your-username
Password: your-password
API version: 1.13.0 (or auto-detect)
Test the Subsonic API directly:
# Ping the server
curl "http://localhost:4533/rest/ping?u=admin&p=password&v=1.13.0&c=test&f=json"
# Get playlists
curl "http://localhost:4533/rest/getPlaylists?u=admin&p=password&v=1.13.0&c=test&f=json"
Transcoding Setup
Navidrome uses FFmpeg for on-the-fly transcoding to reduce bandwidth:
# Verify FFmpeg is installed
ffmpeg -version | head -1
# Install codecs if needed (Ubuntu)
sudo apt install -y ffmpeg libavcodec-extra
Configure transcoding rules in the Navidrome admin panel:
- Log in as admin at
http://localhost:4533 - Go to Admin > Transcoding
- Add a transcoding rule:
Name: mp3
TargetFmt: mp3
Command: ffmpeg -i %s -map 0:0 -b:a %bk -v 0 -f mp3 -
Common transcoding configurations:
# High quality Opus (recommended for mobile)
Name: opus
TargetFmt: opus
Command: ffmpeg -i %s -map 0:0 -b:a %bk -v 0 -c:a libopus -f opus -
# MP3 fallback for older clients
Name: mp3
TargetFmt: mp3
Command: ffmpeg -i %s -map 0:0 -b:a %bk -v 0 -f mp3 -
User Management
# Create the first admin account via web UI on first launch
# http://localhost:4533 -> Create Account
# Additional users via Admin > Users
# Set:
# - Username and password
# - Maximum bitrate (e.g., 320 for premium users, 128 for limited)
# - Admin privileges (yes/no)
# - Download permission
Environment variable configuration for Docker:
environment:
ND_DEFAULTLANGUAGE: en
ND_ENABLESHARING: "true"
ND_ENABLEDOWNLOADS: "true"
ND_MAXSIDEBARPLAYLISTS: 100
ND_SPOTIFY_ID: "your-spotify-client-id" # For album art
ND_SPOTIFY_SECRET: "your-spotify-secret"
Reverse Proxy with Nginx
# /etc/nginx/sites-available/navidrome
server {
listen 80;
server_name music.example.com;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl;
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;
location / {
proxy_pass http://127.0.0.1:4533;
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_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
# Required for music streaming
proxy_buffering off;
proxy_read_timeout 600s;
}
}
sudo ln -s /etc/nginx/sites-available/navidrome /etc/nginx/sites-enabled/
sudo certbot --nginx -d music.example.com
sudo systemctl reload nginx
Troubleshooting
Library not scanning / no music appearing:
# Check Navidrome logs
sudo journalctl -u navidrome -f
# Verify music folder permissions
sudo -u navidrome ls /music/
# Trigger a manual scan via the UI: Admin > Library > Start Scan
# Or check scan schedule in config
grep -i scan /opt/navidrome/navidrome.toml
Client authentication failures (Subsonic API):
# Navidrome requires clients to use the token-based auth
# Some older clients use plaintext passwords — enable legacy auth:
# Add to navidrome.toml:
# EnableLegacyClients = true
# Or test with curl to debug
curl -v "http://localhost:4533/rest/ping?u=admin&t=TOKEN&s=SALT&v=1.13.0&c=test&f=json"
High CPU during scans:
# Limit scan goroutines in config
# Add to navidrome.toml:
# ScannerExtractor = "ffprobe"
# ScannerConcurrency = 2
Conclusion
Navidrome provides a full-featured self-hosted music streaming experience with minimal resource overhead, making it ideal for running alongside other services on a shared VPS. Its Subsonic API compatibility gives you access to a rich client ecosystem for every platform, while built-in transcoding with FFmpeg ensures your FLAC library streams efficiently to any device regardless of available bandwidth.


