🎵 Navidrome Tutorial 🎵


Introduction

Do you dislike relying on centralised corporations such as Spotify to listen to your music meanwhile not actually owning any of it? If so you're in good company, because I do too. For a long time I was going back and forth between using Spotify and listening to the music I have stored locally. The primary reason behind this is that I have a large music taste. I was faced with the conundrum of somehow having the same music collection on my phone and on my computer.

In the end I thankfully stumbled upon Navidrome. Navidrome:

Anyway, enough waffle. Here's how to set-up Navidrome so that you can stream your own music from your own server.

Setup

First, we need to make sure ffmpeg is installed:

apt install ffmpeg

After this we will create a new user to run Navidrome under. Note, this is a non-login system user:

sudo useradd -r -s /bin/false navidrome

Next we need to create Navidrome's directory structure:

sudo install -d -o navidrome -g navidrome /opt/navidrome
sudo install -d -o navidrome -g navidrome /var/lib/navidrome

Now we can install Navidrome itself. At the time of writing v0.47.5 is the latest version. Make sure to check the releases page for a newer version and use that download link instead.

wget https://github.com/navidrome/navidrome/releases/download/v0.47.5/navidrome_0.47.5_Linux_x86_64.tar.gz -O Navidrome.tar.gz
sudo tar -xvzf Navidrome.tar.gz -C /opt/navidrome/
sudo chown -R navidrome:navidrome /opt/navidrome

Now we need to point Navidrome at the directory containing our music collection. Create a new file called navidrome.toml in /var/lib/navidrome and enter the following:

MusicFolder = "<library_path>"

Replace <library_path> with the path to your own music collection and ensure that the navidrome user or group can access this directory. If in doubt use the following command:

sudo chrgrp -R navidrome <library_path>

Once this has been completed, we need to create a new systemd unit file. Create a file called navidrome.service in /etc/systemd/system and enter the following:

[Unit]
Description=Navidrome Music Server and Streamer compatible with Subsonic/Airsonic
After=remote-fs.target network.target
AssertPathExists=/var/lib/navidrome

[Install]
WantedBy=multi-user.target

[Service]
User=navidrome
Group=navidrome
Type=simple
ExecStart=/opt/navidrome/navidrome --configfile "/var/lib/navidrome/navidrome.toml"
WorkingDirectory=/var/lib/navidrome
TimeoutStopSec=20
KillMode=process
Restart=on-failure
DevicePolicy=closed
NoNewPrivileges=yes
PrivateTmp=yes
PrivateUsers=yes
ProtectControlGroups=yes
ProtectKernelModules=yes
ProtectKernelTunables=yes
RestrictAddressFamilies=AF_UNIX AF_INET AF_INET6
RestrictNamespaces=yes
RestrictRealtime=yes
SystemCallFilter=~@clock @debug @module @mount @obsolete @reboot @setuid @swap
ReadWritePaths=/var/lib/navidrome
PrivateDevices=yes
ProtectSystem=full

Once this has been done we can start Navidrome and check that it is running correctly:

sudo systemctl daemon-reload
sudo systemctl start navidrome.service
sudo systemctl status navidrome.service

Assuming everything went smoothly you should be able to access the Navidrome interface at http://example.com:4533, with example.com being your own domain name.

Post-Install Configuration

While Navidrome is now installed properly and can be used, it is highly recommended that you implement the following post-installation steps.

Set Encryption Key

Due to limitations with the Subsonic API, Navidrome is unable to properly hash passwords and thus encrypts them. We need to change the default encryption key.

Go to navidrome.toml in /var/lib/navidrome again and set the PasswordEncryptionKey option. I suggest using a site such as this to generate a strong random key.

MusicFolder = "<library_path>"
PasswordEncryptionKey = "<key>"

Reverse Proxy

Out of the box Navidrome uses its own HTTP server and cannot handle HTTPS. This spells bad news for transmitting secure information such as passwords over the information. And let's face it, having to append the port number to the URL is plain ugly.

Instead, we should run Navidrome behind a reverse proxy such as nginx and proxy-pass the requests to Navidrome. This way we get both prettier URLs and HTTPS, two birds with one stone. Put this following config in /etc/nginx/sites-available under whatever filename you want.

server {
listen 443 ssl;
listen [::]:443;
server_name music.example.com;

location / {
proxy_pass http://localhost: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_set_header X-Forwarded-Protocol $scheme;
proxy_set_header X-Forwarded-Host $http_host;
proxy_buffering off;
}
}

In this configuration we are using a music subdomain. Ensure you set the appropriate DNS records. Now we need to run the following to obtain an HTTPS certificate and automatically install it into our nginx configuration.

sudo apt install python3-certbot-nginx
certbot --nginx

Follow the instructions presented and select the music subdomain. After certbot works its magic, your Nginx config file should look more like the following:

server {
if ($host = music.example.com) {
return 301 https://$host$request_uri;
} # managed by Certbot


listen 80;
listen [::]:80;
return 301 https://$server_name$request_uri;
server_name music.example.com;
}

server {
listen 443 ssl;
listen [::]:443;
server_name music.example.com;
ssl_certificate /etc/letsencrypt/live/music.example.com/fullchain.pem; # managed by Certbot
ssl_certificate_key /etc/letsencrypt/live/music.example.com/privkey.pem; # managed by Certbot

location / {
proxy_pass http://localhost: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_set_header X-Forwarded-Protocol $scheme;
proxy_set_header X-Forwarded-Host $http_host;
proxy_buffering off;
}
}

After this, we need to set up a crontab to make it so that we don't have to manually renew our certificates.

Execute the following command:

sudo crontab -e

And enter the following:

0 0 1 * * certbot --nginx renew

Finally we need to configure Navidrome to only accept proxied requests from nginx and not respond to any request from the outside world.

Once again to to navidrome.toml and append the following line:

Address = "localhost"

External Integrations

To get artist images and other features you should consider integrating Navidrome with the Spotify & Last.fm APIs. Easy steps to achieve this can be found here.