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:

PlatformClient
AndroidSubtracks, DSub, Ultrasonic
iOSAmperfy, play:Sub
DesktopSublime Music, Supersonic
CLIbeets, 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:

  1. Log in as admin at http://localhost:4533
  2. Go to Admin > Transcoding
  3. 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.