Self-Hosted Music Streaming Setup
We earn commissions when you shop through the links on this page, at no additional cost to you.
Tired of paying $12–15 monthly for Spotify while Google and Apple track your listening habits? I built my own music streaming server last year and haven't looked back. With Navidrome running in Docker, I stream lossless audio across my home network and remotely from anywhere using a reverse proxy. Here's exactly how to do it.
Why Self-Host Music Streaming?
When I started this journey, I had three problems: my music collection scattered across drives, no control over algorithm-driven recommendations, and no way to listen offline without downloading tracks one by one. Self-hosting solved all three.
Navidrome is my go-to because it's lightweight (runs on 512MB RAM), supports 60+ audio formats including FLAC, and works with established mobile clients like Symfonium and Ultrasonic. Unlike Plex or Jellyfin (which are over-engineered for music), Navidrome strips out the bloat and gives you a straightforward music library with scrobbling to Last.fm if you want it.
The entire stack costs nothing beyond your hardware. I run it on a Raspberry Pi 4, but even an old laptop works. If you need more performance or don't have home hardware available, VPS providers like RackNerd's KVM VPS offer affordable options starting at $15/year that comfortably handle music streaming for a household.
Hardware and Storage Requirements
Here's what I'm running: a Raspberry Pi 4 with 8GB RAM, a 2TB external USB-attached SSD holding my FLAC library (about 800 albums), and a 1Gbps local network. This handles 3–4 concurrent streams without breaking a sweat.
For a music collection, allocate roughly 1MB per minute of lossless audio. My 800-album collection sits around 300GB. If you're streaming compressed MP3s, expect 5MB per minute. Your server needs enough disk I/O; USB 3.0 external drives work fine, but NVMe over Thunderbolt is smoother.
CPU isn't critical—Navidrome transcodes on-the-fly for remote playback, but it's single-threaded and lazy. A Raspberry Pi 4 handles this without throttling. If you're planning to serve 10+ simultaneous users or transcode 4K video alongside music (which you shouldn't), jump to a VPS with at least 2 CPU cores.
Docker Compose Setup
I prefer Docker because it isolates Navidrome from my system and makes upgrades trivial. Here's my exact compose file:
version: '3.8'
services:
navidrome:
image: deluan/navidrome:latest
ports:
- "4533:4533"
environment:
ND_LOGLEVEL: info
ND_BASEURL: "https://music.example.com"
ND_ENABLESTARRATING: "true"
ND_ENABLEGRAVATAR: "false"
ND_DEFAULTLANGUAGE: "en"
ND_SCANSCHEDULE: "@hourly"
ND_TRANSCODINGDEFAULTBITRATE: "192"
volumes:
- ./navidrome_data:/data
- /mnt/music:/music:ro
restart: unless-stopped
networks:
- music-net
caddy:
image: caddy:latest
ports:
- "80:80"
- "443:443"
volumes:
- ./Caddyfile:/etc/caddy/Caddyfile
- caddy_data:/data
- caddy_config:/config
restart: unless-stopped
networks:
- music-net
networks:
music-net:
driver: bridge
volumes:
caddy_data:
caddy_config:
Save this as `docker-compose.yml`. The key variables here: `/mnt/music` is where my FLAC library lives (change this to your path), and the `ND_TRANSCODINGDEFAULTBITRATE` of 192 Kbps is my compromise between remote streaming quality and bandwidth. For hi-res local playback, clients will request FLAC untranscoded.
Before running the stack, create the music directory and ensure it has read permissions:
sudo mkdir -p /mnt/music
sudo chown 1000:1000 /mnt/music
chmod 755 /mnt/music
# Copy your FLAC files here
rsync -av ~/Music/ /mnt/music/
# Start the stack
docker-compose up -d
ND_SCANSCHEDULE to a specific time (e.g., 0 2 * * * for 2 AM) to batch imports.Reverse Proxy with Caddy
I use Caddy because it handles HTTPS automatically via Let's Encrypt and requires minimal config. Create a `Caddyfile` in the same directory:
music.example.com {
encode gzip
reverse_proxy localhost:4533 {
header_up Host {host}
header_up X-Real-IP {remote_host}
header_up X-Forwarded-For {remote_host}
header_up X-Forwarded-Proto {scheme}
}
# Cache static assets
@static {
path /static/* /assets/*
}
header @static Cache-Control "max-age=31536000, immutable"
}
Replace `music.example.com` with your actual domain. Caddy auto-renews the certificate 30 days before expiry. This setup handles transcoding requests gracefully—if your remote connection is 5 Mbps, Caddy sits between your client and Navidrome without adding latency.
If you're exposing this to the internet, enable DNS-only on your domain and use Cloudflare's free tier to hide your IP. Navidrome doesn't have rate-limiting built-in, so I pair it with fail2ban on the host to block brute-force login attempts:
sudo apt install fail2ban
# Create /etc/fail2ban/jail.local
[navidrome]
enabled = true
port = http,https
logpath = /var/lib/docker/containers/*/navidrome-*.log
maxretry = 5
findtime = 600
bantime = 3600
Mobile Clients and Scrobbling
On Android, I use Symfonium ($6 one-time). It supports offline download, equalizer presets, and scrobbling to Last.fm. In the app, add a server with URL `https://music.example.com` and your Navidrome username/password. The app auto-detects transcoding options and caches playlists locally.
For iOS users, Substreamer ($4.99 on App Store) is the best option. It's less polished than Symfonium but reliable for remote streaming.
If you want Last.fm integration, configure it in Navidrome's web UI: Settings > Last.fm. You'll need a Last.fm API key (free from last.fm), and then enable scrobbling per-user. My chart stats have improved dramatically—I now have a real history of what I actually listen to instead of what an algorithm thinks I should hear.
Library Management and Metadata
Navidrome reads ID3 tags, so ensure your music is properly tagged before importing. I use MusicBrainz Picard (free, open-source) to batch-tag everything before sync:
# Install Picard on your desktop
sudo apt install picard # Linux
# or brew install picard # macOS
# Then use its "Cluster" feature to auto-identify albums
Once synced, Navidrome builds playlists from your tags. I organize by genre, date added, and rating. The web UI is functional but minimal—don't expect Spotify-level curation. However, you can export playlists as M3U files and share them with friends (they'll see your entire music library if you give them your server URL, so be aware of privacy implications).
Performance Tuning
After six months running, I made one key optimization: moved the Navidrome database from the USB drive to the host SSD. The `.db` file is small (20MB for 800 albums) but accessed constantly during scans and searches. Moving it cut query latency from 200ms to 50ms:
volumes:
- ./navidrome_data:/data # Keep this on fast storage
- /mnt/music:/music:ro # Can be on slower USB drive
Also, disable cover art caching if you're low on disk: `ND_IMAGECACHEDIR: ""`. Navidrome will serve covers from ID3 tags instead. This saves ~2GB for large libraries.
For transcoding, monitor CPU usage during playback. If you hit 80%+ utilization, lower `ND_TRANSCODINGDEFAULTBITRATE` to 128 Kbps for remote clients or upgrade your hardware. A second-gen Raspberry Pi will struggle; a Pi 4 is minimum.
Backup Strategy
Your music library and Navidrome database are precious. I back up daily to a NAS using rsync:
#!/bin/bash
# /home/user/backup-music.sh
rsync -av --delete /mnt/music/ nas:/backups/music/
docker exec navidrome tar czf - /data | ssh nas "tar xzf - -C /backups/navidrome/"
# Run via cron: 0 3 * * * /home/user/backup-music.sh
This keeps a versioned copy of your database and tagged files. If your Raspberry Pi dies, rebuilding takes 10 minutes: spin up a new Navidrome container, restore the tar, and you're back online.
Conclusion and Next Steps
A self-hosted music server gives you privacy, control, and sonic freedom. Start with the Docker Compose setup above, grab your favorite mobile client, and upload your library. Most people report this setup taking 2–3 hours from nothing to first remote stream.
If you don't have home hardware, a RackNerd KVM VPS running 24/7 costs $15/year and handles music streaming for a family without breaking a sweat. You'd still run the same Navidrome config, just in a cloud environment instead of your living room.
Next: configure a client on your phone, test remote playback over 4G/5G, then export your favorite playlists as M3U files for sharing. Welcome to the indie music streaming movement.
Discussion