Apps / Media / :4533

Navidrome

Your music collection, streamed like your own Spotify.

No MiniControl yet? Download MiniControl, then install Navidrome from its catalog.

Navidrome streams your own music files to a web player and to dozens of Subsonic apps on iPhone and Android. It handles big libraries, playlists, favourites and several users, and stays light enough to forget it's running.

Why on a Mac: It plays the Music folder, so songs you add on the Mac show up on your phone.

After the install: Open it to create the admin account. It plays the music in the Music folder.

Free, like the whole catalog.

What MiniControl installs

Packages
brew install navidrome
Web page
Port 4533
Keeps running
As LaunchAgent app.minicontrol.navidrome, also after a restart
Its data
~/services/navidrome
Memory
50–150 MB
Licence
GPL-3.0-only
The install script

What MiniControl runs on your server, word for word. The app shows the same script before it installs.

#!/bin/bash
# Generated by MiniControl for Navidrome. Runs on the machine.
set -euo pipefail
export HOMEBREW_NO_AUTO_UPDATE=1 HOMEBREW_NO_ENV_HINTS=1 NONINTERACTIVE=1
export PATH="/opt/homebrew/bin:/opt/homebrew/sbin:/usr/local/bin:$PATH"
step() { echo "STEP|$1|$2"; }
fail() { echo "ERR|$1"; exit 1; }
U=$(id -u)
BREW=$(command -v brew || true)
[ -n "$BREW" ] || fail "Homebrew isn't installed. Server Setup → Homebrew installs it."
BP=$("$BREW" --prefix)
step 1 "Checking the machine"
for f in "$HOME"/Library/LaunchAgents/*.plist; do
  if grep -qsF -- 'bin/navidrome' "$f"; then fail "Navidrome is already set up here, as $(basename "$f" .plist)."; fi
done
if lsof -nP -iTCP:4533 -sTCP:LISTEN >/dev/null 2>&1; then
  fail "Something else already uses port 4533: $(lsof -nP -iTCP:4533 -sTCP:LISTEN | awk 'NR == 2 {print $1}')."
fi
step 2 "Installing with Homebrew"
"$BREW" list --formula navidrome >/dev/null 2>&1 || "$BREW" install navidrome
step 3 "Setting it up"
mkdir -p "$HOME/services/navidrome/log" "$HOME/Library/LaunchAgents" "$HOME/services/navidrome/data"
PL="$HOME/Library/LaunchAgents/app.minicontrol.navidrome.plist"
cat > "$PL" <<EOF
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
  <key>Label</key><string>app.minicontrol.navidrome</string>
  <key>ProgramArguments</key>
  <array>
    <string>$BP/opt/navidrome/bin/navidrome</string>
    <string>--datafolder</string>
    <string>$HOME/services/navidrome/data</string>
    <string>--musicfolder</string>
    <string>$HOME/Music</string>
    <string>--address</string>
    <string>0.0.0.0</string>
    <string>--port</string>
    <string>4533</string>
  </array>
  <key>RunAtLoad</key><true/>
  <key>KeepAlive</key><true/>
  <key>ThrottleInterval</key><integer>10</integer>
  <key>ProcessType</key><string>Background</string>
  <key>StandardOutPath</key><string>$HOME/services/navidrome/log/launchd.out.log</string>
  <key>StandardErrorPath</key><string>$HOME/services/navidrome/log/launchd.err.log</string>
</dict>
</plist>
EOF
plutil -lint "$PL" >/dev/null
[ -x "$BP/opt/navidrome/bin/navidrome" ] || fail "$BP/opt/navidrome/bin/navidrome isn't there after the install."
step 4 "Starting Navidrome"
# Services run in the logged-in user's session (gui/<uid>), like every service in the panel.
launchctl bootstrap "gui/$U" "$PL" || fail "launchd didn't start it. Services run while you're logged in on the machine; Server Setup's \"Log in automatically after a restart\" fixes that."
if /usr/libexec/ApplicationFirewall/socketfilterfw --getglobalstate 2>/dev/null | grep -q enabled; then echo "FW|$BP/opt/navidrome/bin/navidrome"; fi
step 5 "Waiting for it to answer"
# Localhost, and the Tailscale IP for apps that bind only to it.
# `|| true`: with set -e, a failed substitution in an assignment would end the script.
HOSTS="127.0.0.1 $(for t in "$BP/bin/tailscale" /usr/local/bin/tailscale; do [ -x "$t" ] && "$t" ip -4 2>/dev/null && break; done | head -1 || true)"
ok=0
for i in $(seq 1 45); do
  for h in $HOSTS; do
    if curl -fsS -m 3 -o /dev/null "http://$h:4533/app/" 2>/dev/null; then ok=1; break 2; fi
  done
  sleep 2
done
[ "$ok" = 1 ] || echo "WARN|It started, but isn't answering on port 4533 yet. Big apps can take a minute on first start."
echo "DONE"

MiniControl isn’t affiliated with Navidrome. Questions about Navidrome itself go to its makers; about installing it, to [email protected].