Raspberry Pi Music Server

← Self-Hosting · Media · Replaces: Spotify, Apple Music

What You'll Build

Spotify rents you music: stop paying and your library disappears. This project flips that around. You'll turn a Raspberry Pi into a private music-streaming server that plays your own music files to your phone, laptop, and car — anywhere in the world — with no subscription and no ads.

We'll use Navidrome, a free, lightweight music server that runs happily on a Pi. It gives you:

How it fits together:

  Music files on USB drive
            │
            ▼
  ┌─────────────────────────┐
  │ Raspberry Pi            │
  │  └─ Docker              │
  │      └─ Navidrome :4533 │
  └─────────────────────────┘
            │  (home Wi-Fi, or Tailscale when you're away)
            ▼
  Phone app · Web browser · Desktop player

Time needed: about 1–2 hours, plus however long it takes to copy your music. Difficulty: Medium — you'll use the terminal, but every command is given.

Why Navidrome? (vs Jellyfin and Plex)

NavidromeJellyfinPlex
FocusMusic onlyMovies, TV, musicMovies, TV, music
CostFree, open sourceFree, open sourceFree tier; remote streaming and some features need Plex Pass
RAM on a PiVery low (tens of MB)HigherHigher
Phone appsMany (any Subsonic app)Official + third-partyPlexamp (polished)
Needs an online accountNoNoYes (Plex login)

If you only want music, Navidrome is the lightest and simplest choice. If you also want movies, Jellyfin is the better fit.

What You Need

The Build

Follow the steps in order. Every command is run on the Pi over SSH unless it says otherwise.

Step 1: Flash Raspberry Pi OS Lite

"Lite" means no desktop — perfect for a server, since it saves memory for Navidrome.

  1. On your computer, download and open Raspberry Pi Imager.
  2. Choose Device: your Pi model.
  3. Choose OS: Raspberry Pi OS (other) → Raspberry Pi OS Lite (64-bit).
  4. Choose Storage: your microSD card.
  5. When asked to apply OS customisation, choose Edit Settings and set:
    • Hostname: musicpi
    • A username and a strong password (we'll assume the username pi below — use yours)
    • Wi-Fi details (only if you can't use Ethernet)
    • Your time zone
    • Services tab: Enable SSH with password authentication
  6. Write the card, put it in the Pi, plug in Ethernet and the music drive, then power on. Give it 2 minutes for the first boot.

Step 2: Connect Over SSH and Update

From your computer's terminal (Windows: PowerShell):

# Connect to the Pi (replace "pi" with the username you chose)
ssh pi@musicpi.local

# Once logged in, bring everything up to date
sudo apt update && sudo apt full-upgrade -y

# Reboot to load any new kernel, then reconnect after ~1 minute
sudo reboot

"Could not resolve hostname musicpi.local"? Log in to your router and find the Pi's IP address in the connected-devices list, then use ssh pi@192.168.x.x instead.

Step 3: Set Up the Music Drive

We want the USB drive to appear at the same folder, /mnt/music, every time the Pi boots.

3a. Find the drive

lsblk -f
# Look for your USB drive — usually "sda" with a partition "sda1".
# The FSTYPE column shows the format (ext4, exfat, ntfs …).

3b. (Optional) Format it as ext4

This erases the drive. Skip this if your music is already on it. exFAT and NTFS drives work fine as-is; ext4 is simply the most reliable choice for a Linux server.

# Double-check the name with lsblk first! Formatting the wrong disk destroys it.
sudo mkfs.ext4 -L music /dev/sda1

3c. Mount it permanently

# Create the folder the drive will appear in
sudo mkdir -p /mnt/music

# Get the drive's unique ID (UUID) — copy the long UUID="…" value for sda1
sudo blkid /dev/sda1

# Open the file that lists drives to mount at boot
sudo nano /etc/fstab

Add this line at the bottom (paste your UUID and change ext4 to exfat or ntfs3 if you didn't format):

UUID=your-uuid-here  /mnt/music  ext4  defaults,nofail  0  2

nofail means the Pi still boots if the drive is unplugged. Save with Ctrl+O, Enter, then exit with Ctrl+X.

# Reload the list and mount everything in it
sudo systemctl daemon-reload
sudo mount -a

# Confirm it worked — you should see the drive's size
df -h /mnt/music

# ext4 only: give your user ownership so you can copy music in
sudo chown -R $USER:$USER /mnt/music

Step 4: Install Docker

Docker runs Navidrome in a self-contained "container", which makes installing, updating, and removing it a one-line job.

# Docker's official install script (works on Raspberry Pi OS)
curl -fsSL https://get.docker.com | sh

# Let your user run docker without typing sudo every time
sudo usermod -aG docker $USER

# Log out and back in so the group change takes effect
exit
ssh pi@musicpi.local

# Test — should print "Hello from Docker!"
docker run --rm hello-world

Step 5: Create the Navidrome Configuration

# A home for Navidrome's settings and database
mkdir -p ~/navidrome/data
cd ~/navidrome

# Find your user and group ID numbers (usually 1000 and 1000)
id -u
id -g

# Create the configuration file
nano compose.yaml

Paste this in (change 1000:1000 if id printed different numbers):

services:
  navidrome:
    image: deluan/navidrome:latest   # official image, supports Pi (arm64)
    container_name: navidrome
    user: "1000:1000"                # run as your user, not root
    ports:
      - "4533:4533"                  # web player on port 4533
    restart: unless-stopped          # start again automatically after a reboot
    environment:
      ND_SCANSCHEDULE: "1h"          # look for new music every hour
      ND_LOGLEVEL: "info"
      ND_SESSIONTIMEOUT: "168h"      # stay logged in for a week
      ND_ENABLESHARING: "true"       # allow share links for songs/albums
    volumes:
      - "./data:/data"               # database + settings (back this up!)
      - "/mnt/music:/music:ro"       # your music, read-only so it can't be changed

Save and exit (Ctrl+O, Enter, Ctrl+X).

YAML files are picky about spaces. Use spaces (never tabs) and keep the indentation exactly as shown.

Step 6: Start Navidrome and Create Your Account

# Start Navidrome in the background (-d = detached)
docker compose up -d

# Check it's running — STATUS should say "Up"
docker compose ps

# Watch the logs as it scans your music (Ctrl+C to stop watching)
docker compose logs -f
  1. On any device on your home network, open http://musicpi.local:4533
  2. The first visit asks you to create the admin user. Pick a strong password — this account can manage everything.
  3. You'll land in the web player. If your drive already had music on it, albums start appearing as the scan runs.
  4. For family members: open the admin Settings → Users menu and click + Create, and give each person their own login so they get their own playlists and history.

Step 7: Add and Organise Your Music

Folder layout

Navidrome reads the tags inside each file (artist, album, track number), so good tags matter more than folder names. A tidy layout still helps you:

/mnt/music/
├── Artist Name/
│   └── Album Name (Year)/
│       ├── 01 - First Song.flac
│       ├── 02 - Second Song.flac
│       └── cover.jpg          ← album art is picked up automatically
└── Another Artist/
    └── …

Copying music from your computer

# Run this on YOUR COMPUTER (macOS/Linux), not the Pi.
# rsync copies only new/changed files, so re-running it is fast.
rsync -avh --progress ~/Music/ pi@musicpi.local:/mnt/music/

On Windows, use WinSCP (drag and drop over SSH), or unplug the drive and copy to it directly.

Fixing messy tags

MusicBrainz Picard (free, on Windows, macOS, and Linux) listens to each file's audio fingerprint, looks it up in a huge online database, and fixes titles, track numbers, and album art automatically. Run it on your collection before copying it to the Pi.

Where to get music you own

New music appears within the hour (the scan schedule). To scan right away, open the web player, click the activity icon in the top bar, and start a quick scan. (Or restart the container: docker compose restart.)

Step 8: Install the Phone and Desktop Apps

Navidrome speaks the Subsonic protocol, so any Subsonic-compatible app works. Good picks:

PlatformAppNotes
AndroidSymfoniumPaid (one-time), the most polished. Offline sync, Android Auto, casting.
AndroidTempoFree and open source; available on F-Droid and GitHub.
iPhoneAmperfyFree and open source. CarPlay and offline downloads.
iPhoneplay:Sub / substreamerPopular alternatives with CarPlay support.
DesktopFeishin / SupersonicSpotify-style desktop players for Linux, Windows, and macOS.

In any of these apps, add a server with:

At this point everything works at home. The next step makes it work everywhere.

Step 9: Listen From Anywhere (Safely) With Tailscale

Tailscale creates a private, encrypted network between your own devices. Your phone can reach the Pi from anywhere, but the Pi is not exposed to the public internet. It's free for personal use.

# On the Pi: install Tailscale
curl -fsSL https://tailscale.com/install.sh | sh

# Connect the Pi to your Tailscale account — open the link it prints and log in
sudo tailscale up

# Show the Pi's Tailscale address (starts with 100.)
tailscale ip -4
  1. Install the Tailscale app on your phone and log in with the same account.
  2. In your music app, change the server address to http://musicpi:4533 (Tailscale's MagicDNS name) or http://100.x.y.z:4533.
  3. Turn off Wi-Fi on your phone and hit play. If music plays over mobile data, you're done.

Don't just forward port 4533 on your router. That puts an unencrypted login page on the open internet. If you really want a public address (e.g. to share links with friends), put Navidrome behind a reverse proxy with HTTPS, such as Caddy, and keep it updated. See Server Hardening first.

Step 10: Save Mobile Data With Transcoding

A FLAC song can be 30–40 MB. Navidrome can shrink songs on the fly to a much smaller format while streaming, without touching your originals. The Docker image already includes the ffmpeg converter it needs.

  1. Most apps have a "max bitrate on mobile data" setting — set it to 128 or 160 kbps. The app asks Navidrome to transcode, and it does.
  2. Navidrome comes with MP3 and Opus transcoding already set up. Opus gives the best quality per MB. (Want to edit the formats yourself? Add ND_ENABLETRANSCODINGCONFIG: "true" to the environment list, restart, and a Transcodings page appears in Settings.)
  3. For Wi-Fi at home, leave it at "original" for full quality.

Getting the "Spotify Experience"

Spotify featureHow to get it here
Playlists & liked songsBuilt in. Hearts (stars) sync across every app.
Offline downloadsSymfonium, Amperfy, and Tempo can download albums/playlists to your phone.
Auto-generated playlistsSmart playlists: drop a .nsp file into your music folder with rules like "rating ≥ 4 and played in the last 30 days". See Navidrome's docs.
Listening history / "Wrapped"Connect ListenBrainz or Last.fm scrobbling from your Navidrome profile page.
LyricsEmbedded lyrics tags, or .lrc files with the same name as the song, are shown by supporting apps.
Share a song with a friendShare links (enabled by ND_ENABLESHARING). Only reachable by others if you've set up public access.
Discover new musicNot included — you only hear what you own. Use Bandcamp, ListenBrainz recommendations, or radio for discovery.

Keeping It Running

Update Navidrome

cd ~/navidrome
docker compose pull      # download the newest version
docker compose up -d     # restart on the new version (your data is kept)
docker image prune -f    # delete the old version to free space

Update the Pi itself (monthly)

sudo apt update && sudo apt full-upgrade -y

Back up the important parts

Your music is the big one — keep a second copy on another drive or computer. Navidrome's own data (users, playlists, play counts) is tiny and lives in ~/navidrome/data:

# Run on your computer: copies the Pi's Navidrome data to a local backup folder
rsync -avh pi@musicpi.local:~/navidrome/data/ ~/Backups/navidrome-data/

Troubleshooting

What's Next?