Navidrome Self-Hosted: One Container, Two Gotchas
Self-hosting Navidrome: the one-container compose file, the UID and GID that decides whether it can read your music, and why bad tags stay bad.

⚡ The short version
Navidrome is one container with its database inside it, so the install is a ten-line compose file. The two things that cost you an evening are neither of them in that file: the numeric user the container runs as, which decides whether it can read your music at all, and your tags, which Navidrome reads exclusively and will never fix for you.
The guides for this are all the same shape: paste the compose file, screenshot the album grid, stop. What they leave out is why your library is still empty twenty minutes later, and why the compilation you ripped years ago arrives as one album per track.
Everything below about self-hosting Navidrome comes from the project’s own documentation source and from the container registry, read on 21 September 2026. The website repository was at commit c3b4044, dated 20 September 2026. The latest stable tag that day was v0.64.0, filtered out of all 120 tags the repository publishes; none carry a release-candidate suffix.
What Do You Get for One Container?
A web player, and a server that speaks a protocol other people’s apps already know.
That second half is the reason to pick Navidrome. It implements the Subsonic API, so any client built for Subsonic or OpenSubsonic connects to it. Counting the entries in the catalogue the project keeps in its website repository on 21 September 2026 gives 90 apps — 39 against Subsonic, 39 against OpenSubsonic, 12 built specifically for Navidrome, and 72 of the 90 free. By platform:
| Platform | Apps listed |
|---|---|
| Android | 32 |
| iOS | 32 |
| macOS | 28 |
| Linux | 26 |
| Windows | 18 |
| Web | 16 |
Those are the project’s own entries rather than an independent survey, and an entry says a client exists, not that it is good. The shape is the point: you are not depending on one vendor’s app staying maintained, which is the failure that ends most self-hosted media setups.
What you do not get is a music manager. Navidrome streams and organises; it does not fetch, rename, retag or tidy anything.
What Goes in the Compose File?
One service, two volumes, one port. Here it is with the tag pinned:
services:
navidrome:
image: deluan/navidrome:0.64.0
user: "1000:1000"
ports:
- "4533:4533"
restart: unless-stopped
volumes:
- "./data:/data"
- "/srv/music:/music:ro"
Three things in there are load-bearing. (4533 is simply the default port, and a Navidrome-specific enough number that it rarely collides.)
The tag has no v on it. The git tag is v0.64.0 and the Docker tag is 0.64.0; asking the registry for deluan/navidrome:v0.64.0 on 21 September 2026 returned a 404, and 0.64.0 returned a manifest. The project’s own example uses latest, and pinning saves you an upgrade you did not choose.
/data needs read and write access, because that is where the database and the caches are created. /music needs read access only, and mounting it :ro costs nothing because Navidrome never writes there anyway.
And the user directive is the one line people delete, which is the next section.
Why Is Your Library Empty After the First Scan?
Because the container cannot read your music. Navidrome fails at permissions in two ways that look nothing alike.
If the data folder is not writable, the container dies at startup with an unopenable database file and a panic, so you find out immediately.
If the music folder is not readable, everything appears to work. The server starts, the web interface loads, you log in, and the library is empty. What the project documents for this is a permission error on /music plus a warning that the target folder does not exist — which it does. The container user simply cannot open it.
The fix is ownership, not configuration. Run id -u and id -g, put the same pair in the user directive, and make the folders match:
mkdir -p ./data
sudo chown -R $(id -u):$(id -g) ./data
sudo chmod -R a+rX /srv/music
The capital X sets execute on directories only, making a folder traversable without marking every FLAC file executable. Use it rather than chown when other programs share the folder.
PUID and PGID do nothing here. They are a LinuxServer.io image convention, and the official Navidrome image ignores them. The project says so in its Docker installation page. If you copied a compose file from a guide that sets them, they are decoration and your permissions problem is still there.
The other tempting fix is deleting the user line altogether. That works, because the container then runs as root and root can read anything. The documentation says not to do it in production, and the server carries a setting, EnforceNonRootUser, that makes it refuse to start as root rather than quietly run privileged. It ships disabled. If you have followed this site’s server hardening guide, turning it on matches the rest of that posture.
Will Navidrome Tidy a Badly Tagged Library?
No. It reads your tags exactly as they are and shows you the result.
Navidrome organises a library entirely from metadata tags. It does not group by folder, it does not infer that a directory of MP3s is an album, and it has no browse-by-folder mode — the project has explicitly declined to add one and says it does not support untagged libraries at all. That is the exact opposite of how Jellyfin reads a library, where the folder and file names are what the scanner matches on. Coming from a server that fixed your sloppy naming for you, budget an evening for tagging before you blame the install.
Two failures follow directly from that:
- A compilation explodes into one album per track. Tracks by different artists in one folder are not an album as far as Navidrome is concerned. The fix is the compilation flag on every track —
TCMP=1for ID3,COMPILATION=1for FLAC — or a shared Album Artist of “Various Artists”. - An artist name gets split in half. Navidrome splits multi-artist tags on separator characters, which does the wrong thing to a name that legitimately contains one.
Scanner.ArtistSplitExceptionsexists for this, and the project’s own example of a name to protect is AC/DC.
The tool to fix any of it is not Navidrome — the project recommends MusicBrainz Picard and beets by name. Its reason for refusing the job is a good one: an internet-facing server with write access to your library is one exploit away from deleting it, and a server that cannot write to /music cannot be made to.
How Does It Notice New Music?
Immediately, by watching the folder — and the scheduled scan you might expect is off by default.
Three defaults decide the behaviour, all read from the configuration options page on 21 September 2026:
| Setting | Default | What it means |
|---|---|---|
Scanner.WatcherWait |
5s |
A filesystem watcher picks up changes and waits five seconds before scanning, so a half-copied file is not indexed |
Scanner.ScanOnStartup |
true |
Every restart triggers a scan |
Scanner.Schedule |
0 |
Periodic scanning is disabled; the watcher is the mechanism |
That is right for a folder you drop files into locally and wrong for one where the watcher cannot see changes — a network share, or a filesystem that does not deliver events. If new albums only appear after a restart, that is the tell, and Scanner.Schedule with a cron expression is the answer rather than restarting on a timer.
One default surprises people the other way. Scanner.PurgeMissing is never, so deleting a file does not remove it from the database; the track is marked missing and stays visible. That protects you when a drive is briefly unmounted, and it means a library you genuinely pruned needs the setting changed to tidy itself up.
Tunnel, Proxy or Private Network?
The answer for music is not the same as the answer for video, and it is not as clean a call either.
This site’s Jellyfin guide says plainly that Cloudflare Tunnel does not fit a video server, because Cloudflare’s terms restrict serving video through a public hostname on the free plans. Whether audio is covered too is worth reading the clause for. Cloudflare’s video-delivery policy page, checked in its documentation source on 21 September 2026, says that on Free, Pro and Business plans, if your application appears to be serving videos or a disproportionate amount of large files without the appropriate paid service, Cloudflare may redirect your content or take other action.
Audio is not named, and the second half of that sentence is not about video at all. Cloudflare publishes no threshold for “disproportionate”, so a large lossless library streamed all day sits somewhere on an undefined line while a handful of MP3 playlists plainly does not. That is the honest answer and it is not a comfortable one.
| Route | Restriction on media | What it costs you |
|---|---|---|
| Cloudflare Tunnel public hostname | Video restricted; large files restricted without a published threshold | Cloudflare terminates TLS and holds your plaintext |
| Tailscale or another private network | None | Every device that listens needs the client installed |
| Reverse proxy on your own host | None | An open port, a certificate to renew, and the server is publicly addressable |
For a library only your household listens to, the private network is the cleanest of the three and the restriction question never arises. For anything public-facing, Navidrome expects to sit behind a proxy and has two settings for it: ND_BASEURL when it lives under a subpath, and binding Address to localhost so the embedded server is unreachable except through the proxy.
Which Defaults Should You Know About?
Two, and neither is a defect — they are the kind of default you want decided rather than discovered.
Transcoding configuration is disabled in the UI. Those settings define the command line that gets run, which is remote code execution wearing a helpful hat, and the project disabled UI editing for exactly that reason. ND_ENABLETRANSCODINGCONFIG turns it back on; turn it off again when you are done.
Anonymous usage reporting is on by default. Navidrome sends instance data such as version, uptime and build settings to a collector the project runs itself, no third party involved and every field documented, with nothing identifying attached. If you self-host specifically so that nothing phones home, ND_ENABLEINSIGHTSCOLLECTOR set to false is the switch.
What Does the Built-In Backup Actually Save?
The database, and nothing else. Navidrome has had a built-in backup since the 0.54 series, configured with three environment variables:
environment:
ND_BACKUP_PATH: /backup
ND_BACKUP_SCHEDULE: "0 0 * * *"
ND_BACKUP_COUNT: 7
volumes:
- ./backup:/backup
That gives you a nightly dump and seven kept copies. What it holds is users, play counts, playlists, ratings and favourites — the things that exist nowhere but on that server.
It does not back up your music, and it does not back up your configuration. The project's documentation says so directly. Restoring is also destructive: the restore command wipes the existing database before copying the backup in, and it must be run with the server stopped. Treat the music library as a separate job with a separate schedule.
For the library itself the same rules as any other mounted data apply: the mechanics are in backing up Docker volumes, and how many copies to keep is in the self-hosting backup strategy. The Navidrome-specific note is that because the server never writes to /music, the two backups are genuinely independent jobs — unusual, and convenient.
Frequently Asked Questions About Navidrome
Does Navidrome need a database container?
No. Navidrome is a single image with an embedded database, written into the data folder you mount. There is no PostgreSQL service, no Redis or Valkey broker and no separate worker. Checked against the project’s Docker installation page on 21 September 2026, where the compose example is one service, two volumes and one port.
Why is my Navidrome library empty after the first scan?
Almost always because the container user cannot read the music folder. The project’s documentation names this as a distinct failure from an unwritable data folder: the server starts, the web interface loads, and the logs show a permission denied error on the music path while the library stays empty. Give the UID and GID in the user directive read and execute access to that folder.
Do PUID and PGID work with Navidrome?
No. Those two variables are a LinuxServer image convention and Navidrome’s official image ignores them entirely. The project lists them as one of two things people often try that do not work, and says to use Docker’s own user directive instead, set to the numeric UID and GID that owns the data folder and can read the music.
Can Navidrome fix or edit my music tags?
It cannot, and that is deliberate rather than a missing feature. Navidrome never writes to your music folder or to the files in it, and the project gives the reason as security: an internet-facing server that could write to the library would be one exploit away from destroying it. Tag your files first with MusicBrainz Picard or beets, both of which the project recommends by name.
Does the built-in backup cover my music files?
No. The backup feature exports the database only, which means users, play counts, playlists and ratings. The project’s documentation states plainly that it does not back up the music or the configuration. Your music library needs its own backup, and restoring a Navidrome backup wipes the current database, so it has to be done with the server stopped.
Can a Raspberry Pi run Navidrome?
Yes, including old ones. The published image index for the latest tag lists linux/386, linux/amd64, linux/arm/v6, linux/arm/v7, linux/arm64 and linux/riscv64, read from the registry on 21 September 2026. The armv6 entry covers the original Pi and the Pi Zero. The project’s overview claims it runs well on that hardware; that claim is the project’s, not a measurement made here.
Product links on this site are plain links. We earn nothing from them — see our disclosure policy.