Navidrome is a lightweight, open source music server that streams your MP3, FLAC, Opus and other audio files through a modern web player and the Subsonic API, so you can use dozens of existing mobile and desktop apps. It is a single Go binary that runs comfortably with a few hundred megabytes of RAM. In this tutorial you will install Navidrome on Ubuntu 24.04 as a systemd service running under its own user, publish it over HTTPS with Nginx and connect a Subsonic client.
Prerequisites
To follow this guide you need:
- A server running Ubuntu 24.04 LTS (x86_64), for example a CubePath VPS. 512 MB of RAM is enough for a personal library.
- A non-root user with
sudoprivileges. - Your music collection, or space to upload it.
- A domain or subdomain (this guide uses
your_domain) with a DNSArecord pointing toyour_server_ip, for HTTPS in Step 5.
Step 1 - Installing dependencies and creating the service user
Navidrome uses FFmpeg to transcode audio on the fly for clients with limited bandwidth. Install it along with the tools used later in this guide:
sudo apt update
sudo apt install -y ffmpeg curl
Create a system user with no login shell to run the service, and the directories for the program, its data and your music:
sudo useradd --system --no-create-home --shell /usr/sbin/nologin navidrome
sudo install -d -o navidrome -g navidrome /opt/navidrome /var/lib/navidrome
sudo install -d -o "$USER" -g navidrome -m 2750 /srv/music
/srv/music belongs to your user so you can upload files, and to the navidrome group so the service can read them. The setgid bit (2) makes new files and folders inherit the group.
Step 2 - Downloading Navidrome
Navidrome publishes prebuilt binaries on GitHub. Look up the latest version number from the GitHub API:
ND_VERSION=$(curl -fsSL https://api.github.com/repos/navidrome/navidrome/releases/latest | grep -Po '"tag_name": "v\K[^"]+')
echo "$ND_VERSION"
0.xx.x
Download the Linux x86_64 archive for that version and extract it into /opt/navidrome:
cd /tmp
curl -fLO "https://github.com/navidrome/navidrome/releases/download/v${ND_VERSION}/navidrome_${ND_VERSION}_linux_amd64.tar.gz"
sudo tar -xzf "navidrome_${ND_VERSION}_linux_amd64.tar.gz" -C /opt/navidrome
sudo chown -R navidrome:navidrome /opt/navidrome
Confirm the binary runs:
/opt/navidrome/navidrome --version
0.xx.x (xxxxxxxx)
Step 3 - Configuring Navidrome
Navidrome reads its settings from a TOML file. Create it in the data directory:
sudo nano /var/lib/navidrome/navidrome.toml
Add the following configuration:
MusicFolder = "/srv/music"
DataFolder = "/var/lib/navidrome"
# Listen only on localhost; Nginx will expose it publicly
Address = "127.0.0.1"
Port = 4533
LogLevel = "info"
Binding to 127.0.0.1 keeps the service unreachable from the internet until it is behind HTTPS. Make the file readable by the service user:
sudo chown navidrome:navidrome /var/lib/navidrome/navidrome.toml
Step 4 - Creating the systemd service
Create a unit file so systemd starts Navidrome at boot and restarts it if it crashes:
sudo nano /etc/systemd/system/navidrome.service
[Unit]
Description=Navidrome music server
After=network-online.target remote-fs.target
Wants=network-online.target
[Service]
User=navidrome
Group=navidrome
Type=simple
ExecStart=/opt/navidrome/navidrome --configfile /var/lib/navidrome/navidrome.toml
WorkingDirectory=/var/lib/navidrome
Restart=on-failure
TimeoutStopSec=20
# Hardening
NoNewPrivileges=yes
PrivateTmp=yes
ProtectSystem=full
ProtectHome=yes
ReadWritePaths=/var/lib/navidrome
[Install]
WantedBy=multi-user.target
Reload systemd, then enable and start the service:
sudo systemctl daemon-reload
sudo systemctl enable --now navidrome
systemctl status navidrome --no-pager
● navidrome.service - Navidrome music server
Loaded: loaded (/etc/systemd/system/navidrome.service; enabled; preset: enabled)
Active: active (running) since ...
Check that it answers on port 4533:
curl -s -o /dev/null -w '%{http_code}\n' http://127.0.0.1:4533/app/
200
If the service does not start, read its logs with sudo journalctl -u navidrome -n 50.
Step 5 - Publishing Navidrome over HTTPS with Nginx
Install Nginx and Certbot, and open the firewall for SSH and web traffic:
sudo apt install -y nginx certbot python3-certbot-nginx
sudo ufw allow OpenSSH
sudo ufw allow 'Nginx Full'
sudo ufw enable
Create a server block:
sudo nano /etc/nginx/sites-available/navidrome
server {
listen 80;
listen [::]:80;
server_name your_domain;
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";
# Send audio to the client as it is produced
proxy_buffering off;
}
}
Enable the site, test the configuration and reload Nginx:
sudo ln -s /etc/nginx/sites-available/navidrome /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx
Request a Let's Encrypt certificate; Certbot adds the HTTPS listener and a redirect from HTTP:
sudo certbot --nginx -d your_domain
Now open https://your_domain in your browser right away. The first person to load a new Navidrome instance creates the administrator account, so do it before sharing the address. Choose a username and a strong password.
Step 6 - Adding music and scanning the library
Navidrome reads tags (artist, album, track number, cover art) from the files themselves, so the folder layout is not critical, but a tidy Artist/Album/Track structure makes the library easier to manage:
/srv/music/Pink Floyd/The Dark Side of the Moon (1973)/01 - Speak to Me.flac
/srv/music/Pink Floyd/The Dark Side of the Moon (1973)/02 - Breathe.flac
Upload music from your computer with rsync:
rsync -avP ~/Music/ your_user@your_server_ip:/srv/music/
Confirm that the service user can read the files:
sudo -u navidrome ls /srv/music
Navidrome scans the library on startup and detects changes automatically. To force a scan, open the activity panel from the icon in the top right corner of the web interface and start a quick or full scan. New albums appear under Albums once the scan completes.
Step 7 - Adding users and connecting Subsonic clients
As administrator, open Settings > Users (the profile menu in the top right) and create one account per listener. Only give administrator rights to accounts that need to manage the server.
Test the Subsonic API with the account you created. This request sends the password in the URL, so use it only for a quick test and clear your shell history afterwards:
curl -s "https://your_domain/rest/ping.view?u=your_user&p=your_password&v=1.16.1&c=curl&f=json"
{"subsonic-response":{"status":"ok","version":"1.16.1","type":"navidrome","serverVersion":"0.xx.x","openSubsonic":true}}
Any Subsonic-compatible client will work. Popular choices are Symfonium and Tempo on Android, Amperfy and play:Sub on iOS, and Feishin or Supersonic on the desktop. In the client, enter https://your_domain as the server URL with your Navidrome username and password.
Navidrome includes default transcoding profiles for MP3, Opus and AAC that use FFmpeg. Most mobile apps let you pick a maximum bitrate for mobile data, and Navidrome transcodes on the fly when the requested bitrate is lower than the file's.
Troubleshooting
The library stays empty. The service user usually cannot read the files. Run sudo -u navidrome ls -R /srv/music | head and, if access is denied, fix the ownership with sudo chown -R "$USER":navidrome /srv/music and sudo chmod -R u=rwX,g=rX,o= /srv/music.
502 Bad Gateway. Navidrome is not running or is listening elsewhere. Check systemctl status navidrome and confirm Address and Port in navidrome.toml match the proxy_pass line.
A client cannot log in. Make sure the client points to https://your_domain without the /app suffix. Some very old clients only support plain password authentication; try a maintained client from the list above first.
Conclusion
Navidrome now runs on Ubuntu 24.04 as a hardened systemd service, reachable over HTTPS through Nginx and ready for any Subsonic client. As next steps, back up /var/lib/navidrome (which holds the database with users, playlists and play counts), enable sharing with EnableSharing = true in navidrome.toml if you want public links, and update by downloading a newer release into /opt/navidrome and restarting the service.
