Author | Nejat Hakan |
nejat.hakan@outlook.de | |
PayPal Me | https://paypal.me/nejathakan |
Music Streaming Server Navidrome
Introduction
Welcome to your comprehensive guide on self-hosting Navidrome, a modern, lightweight, and powerful open-source music streaming server. In today's digital landscape, where large corporations often mediate our access to music through subscription services, taking control of your personal music library offers unparalleled freedom, privacy, and customization. Navidrome emerges as a stellar solution for this, allowing you to build your own personal "Spotify" using the music files you already own.
This guide is specifically tailored for learners, particularly university students, who are keen to understand not just the "how" but also the "why" behind self-hosting applications like Navidrome. We will delve into the core concepts, starting with the fundamentals of setting up Navidrome using Docker, progressing through intermediate configurations like secure remote access and user management, and finally exploring advanced topics such as security hardening, backups, and performance optimization.
What Exactly is Navidrome?
At its heart, Navidrome is software you run on your own server (which could be anything from a powerful machine to a humble Raspberry Pi) that scans your digital music collection and makes it available for streaming over the internet or your local network. You can access your music through a clean web interface or via a multitude of compatible third-party applications (mobile and desktop) that support the widely adopted Subsonic API.
Key characteristics that make Navidrome appealing include:
- Efficiency: Built with Go and React, it boasts minimal resource consumption (CPU and RAM), making it ideal for low-power devices.
- Modern Interface: Offers a fast, intuitive, and visually appealing web player for browsing and listening.
- Subsonic API Support: This is a major advantage, granting compatibility with dozens of established music players like DSub (Android), Substreamer (Android/iOS), play:Sub (iOS), Clementine (Desktop), and many more.
- Multi-User Capability: Allows you to create separate accounts with individual passwords and permissions, perfect for sharing with family or housemates.
- On-the-Fly Transcoding: Can automatically convert music files to different formats or bitrates during streaming. This is crucial for saving mobile data or ensuring compatibility with specific players, although it does require more CPU power.
- Metadata Driven: Relies heavily on the metadata (tags like artist, album, genre, year, cover art) embedded within your music files (e.g., ID3, Vorbis Comments, MP4 tags) for organization. Accurate tagging is key!
- Playlists & Favorites: Supports standard playlists, smart playlists based on criteria, and marking favorite tracks/albums/artists.
- Scrobbling: Can report your listening history to services like Last.fm and ListenBrainz.
- Open Source & Free: Licensed under the AGPLv3, ensuring it remains free to use and modify, with an active community contributing to its development.
The Rationale for Self-Hosting Music
Why bother setting up your own server when commercial options exist?
- True Ownership: Your music library is yours. It won't disappear because of licensing disputes or a service shutting down. You control the files and the platform.
- Uncompromised Privacy: Your listening habits remain private. No corporate entity is profiling your tastes unless you explicitly opt-in (e.g., scrobbling).
- Infinite Customization: Tailor the server's behavior, manage access precisely, and potentially integrate it with other self-hosted tools.
- Cost-Effective: Avoid recurring subscription fees. The primary costs are the hardware (which you might already own) and your time investment.
- Universal Access to Your Library: Stream your entire collection, including rare B-sides, live recordings, audiobooks, or personal audio files unavailable elsewhere.
- Invaluable Learning: The process itself is a fantastic way to learn practical skills in server administration, Linux, Docker, networking, and security – skills highly relevant in many technical fields.
Assumed Knowledge
This guide progresses in difficulty. While we aim for clarity, some foundational knowledge will significantly enhance your learning experience:
- Linux Command Line Basics: Comfortable using commands like
cd
(change directory),ls
(list files),mkdir
(make directory),nano
orvim
(text editing),sudo
(superuser privileges),chown
/chmod
(permissions). - Basic Networking: Understanding what an IP address and a port number are. Familiarity with the concept of a firewall.
- A Host System: A computer where Navidrome will run. This could be:
- A dedicated physical server.
- A Virtual Private Server (VPS) from a cloud provider.
- A Virtual Machine (VM) on your desktop (using VirtualBox, VMware, etc.).
- A Single Board Computer (SBC) like a Raspberry Pi 4 or newer.
- Your primary desktop/laptop (less ideal for 24/7 availability but fine for testing).
- Docker and Docker Compose (Recommended): This guide heavily favors deployment using Docker for its encapsulation, consistency, and ease of management. We will cover the necessary installation steps.
Prepare to dive in and build your personal music streaming powerhouse with Navidrome!
Basic Setup and Configuration
This section covers the essential first steps to get a functional Navidrome instance running using Docker. We focus on simplicity and understanding the core components.
1. Installing Docker and Docker Compose
Docker is the containerization engine, and Docker Compose helps us define and manage our Navidrome container configuration easily. We'll install them on a typical Debian/Ubuntu-based Linux system. If you're using a different OS (like Fedora, CentOS, Arch, macOS, Windows with WSL2), consult the official Docker documentation for specific installation instructions, but the principles remain the same.
What are we doing? We are installing the necessary software tools that allow us to download, configure, and run Navidrome in an isolated environment called a container.
- Update Package Manager Cache: Ensures you have the latest list of available software packages.
- Install Prerequisite Packages: These packages allow
apt
to use repositories over HTTPS and manage repository keys. - Add Docker's Official GPG Key: This verifies the authenticity of the Docker packages we will download.
# Download the key and save it in a standard location curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg # Note: If using Debian, replace 'ubuntu' with 'debian' in the URL above. # Example for Debian: # curl -fsSL https://download.docker.com/linux/debian/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
- Set Up the Docker Stable Repository: This tells
apt
where to download Docker from.echo \ "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu \ $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null # Note: If using Debian, replace 'ubuntu' with 'debian' in the URL above. # Example for Debian: # echo \ # "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/debian \ # $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
- Install Docker Engine: Update the package list again (to include Docker packages) and install Docker Community Edition (CE), the command-line interface (CLI), and containerd (a container runtime).
- Verify Docker Installation: Run the
hello-world
image. Docker will download it if it's not present locally and run it in a container, printing a confirmation message. You should see output indicating Docker is working correctly. - (Optional but Highly Recommended) Add Your User to the
docker
Group: By default, interacting with the Docker daemon requires root privileges (usingsudo
). Adding your user to thedocker
group grants permission to run Docker commands withoutsudo
. IMPORTANT: You MUST log out and log back in for this group change to take effect. After logging back in, test by runningdocker run hello-world
withoutsudo
. - Install Docker Compose: Docker Compose is distributed as a separate binary. We'll download the latest stable release from GitHub. Always check the Docker Compose GitHub releases page for the latest version number.
# Find the latest version from: https://github.com/docker/compose/releases # Replace 'v2.24.5' with the actual latest version if different LATEST_COMPOSE_VERSION="v2.24.5" # Download the binary sudo curl -L "https://github.com/docker/compose/releases/download/${LATEST_COMPOSE_VERSION}/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose # Apply executable permissions to the binary sudo chmod +x /usr/local/bin/docker-compose
- Verify Docker Compose Installation: Check the version number.
This should output the version you just installed (e.g.,
Docker Compose version v2.24.5
).
Now your system is ready with Docker and Docker Compose!
Workshop Install Docker and Docker Compose
Goal: Verify that Docker and Docker Compose are correctly installed and your user can run Docker commands without sudo
.
Steps:
- Open your Linux terminal.
- Check Docker Version: Run
docker --version
. You should see the installed Docker version. - Check Docker Compose Version: Run
docker-compose --version
. You should see the installed Docker Compose version. - Run
hello-world
withoutsudo
: If you added your user to thedocker
group and logged out/in, run: This command should execute successfully without prompting for a password or giving a permission error. If it fails with a permission error, double-check step 7 of the installation and ensure you logged out and back in. If it asks forsudo
, the group change hasn't taken effect or wasn't done correctly. - List Docker Images: See what images are downloaded locally.
You should see the
hello-world
image listed. - List Docker Containers: See currently running containers (there shouldn't be any persistent ones yet) and stopped containers.
You should see the
hello-world
container listed with a status likeExited (0) ...
.
Outcome: You have successfully confirmed that Docker and Docker Compose are installed and operational on your system. You are ready to proceed with deploying Navidrome.
2. Creating the Navidrome docker-compose.yml
File
Docker Compose uses a YAML file (conventionally named docker-compose.yml
) to define the services (containers), volumes (persistent storage), and network settings for our application.
What are we doing? We are creating a configuration file that tells Docker exactly how to set up and run Navidrome.
-
Choose a Directory: Decide where you want to store your Navidrome configuration and data. A common practice is to create a dedicated directory, for example, in your user's home directory or under
/opt
. Let's use~/navidrome
.# Create the main directory mkdir ~/navidrome # Create a subdirectory for Navidrome's persistent data mkdir ~/navidrome/data # Navigate into the main directory cd ~/navidrome
~/navidrome
: This will hold ourdocker-compose.yml
file.~/navidrome/data
: This directory on your host system will be mounted into the Navidrome container. Navidrome will store its database, configuration files, cover art cache, etc., inside this directory. This ensures the data persists even if you stop, remove, or update the Navidrome container.
-
Prepare Your Music Directory: Navidrome needs access to your music files. Identify the full path to your music library on the host system. For example, it might be
/srv/music
,/mnt/media/music
, or~/Music
. Make sure the user who will run thedocker-compose
command (likely your own user, if you added yourself to thedocker
group) has read permissions for this directory and all its contents. You might need to adjust permissions usingchmod
andchown
if necessary. We will use/srv/music
as an example path – replace this with your actual music library path. -
Create the
docker-compose.yml
file: Use a text editor (likenano
,vim
, or a graphical editor) to create thedocker-compose.yml
file inside the~/navidrome
directory. -
Add the following content: Carefully copy and paste this configuration, making sure to replace
/srv/music
with the actual path to your music collection.version: "3" services: navidrome: image: deluan/navidrome:latest # Use the official Navidrome image container_name: navidrome # Assign a specific name to the container restart: unless-stopped # Automatically restart Navidrome unless manually stopped user: "1000:1000" # IMPORTANT: Set User/Group ID, see notes below ports: - "4533:4533" # Map host port 4533 to container port 4533 (Navidrome default) environment: # Optional: Set timezone to match your location (e.g., "America/New_York", "Europe/Berlin") # Find yours using `timedatectl list-timezones` TZ: "Etc/UTC" # --- Basic Navidrome Configuration --- # Title shown in the UI header ND_UIWELCOMEMESSAGE: "Welcome to My Music Cloud!" # Scan interval (e.g., "1h" for 1 hour, "15m" for 15 minutes, "24h" for daily) ND_SCANINTERVAL: "1h" # Log level (options: error, warn, info, debug, trace) ND_LOGLEVEL: "info" # Session timeout duration ND_SESSIONTIMEOUT: "24h" # Enable transcoding configuration in the UI (default: false) # Set to "true" if you want users to manage transcoding per player ND_ENABLETRANSCODINGCONFIG: "false" volumes: # Mount the host data directory to the container's data directory - ./data:/data # Mount your music library (read-only recommended for safety) # !!! REPLACE /srv/music with your actual music path !!! - /srv/music:/music:ro
Explanation of the docker-compose.yml
:
version: "3"
: Specifies the Docker Compose file format version.services:
: Defines the containers to be managed.-
navidrome:
: The name we give to our service (can be anything, butnavidrome
is logical).image: deluan/navidrome:latest
: Tells Docker to pull the latest version of the official Navidrome image from Docker Hub.container_name: navidrome
: Gives the running container a fixed, predictable name (navidrome
) which is useful for commands.restart: unless-stopped
: Ensures the container restarts automatically if it crashes or if the Docker daemon restarts (e.g., after a system reboot), unless you explicitly stop it usingdocker stop navidrome
ordocker-compose down
.user: "1000:1000"
: Crucial for Permissions! This tells Docker to run the Navidrome process inside the container as the user with User ID (UID) 1000 and Group ID (GID) 1000.- Why is this important? Navidrome needs to read your music files (mounted at
/music
) and write to its data directory (/data
). By default, Docker might run the container as root (UID 0), which can cause permission issues or be a security risk. - How to find your UID/GID? Open a terminal on your host system and run the command
id $USER
. It will output something likeuid=1000(yourusername) gid=1000(yourusername) groups=...
. Use theuid
andgid
numbers shown.1000:1000
is very common for the first user created on many Linux systems, but verify yours and update thedocker-compose.yml
file if necessary. - Ensure that this UID/GID has read access to your music library (
/srv/music
in the example) and read/write access to the Navidrome data directory (~/navidrome/data
). You might needsudo chown -R 1000:1000 ~/navidrome/data
if you created it as root.
- Why is this important? Navidrome needs to read your music files (mounted at
ports:
: Maps ports between the host machine and the container (HOST:CONTAINER
)."4533:4533"
: Makes Navidrome (which listens on port 4533 inside the container) accessible on port 4533 of your host machine. If port 4533 is already used on your host, you could change the host part (e.g.,"8080:4533"
to access it viahttp://<your-server-ip>:8080
).
environment:
: Sets environment variables inside the container, which Navidrome uses for configuration. We've set a few basic ones:TZ
: Sets the timezone. Important for correct log timestamps. Usetimedatectl list-timezones
on your host to find your timezone identifier.ND_UIWELCOMEMESSAGE
: Custom text displayed in the Navidrome UI.ND_SCANINTERVAL
: How often Navidrome should automatically check your music library for changes.ND_LOGLEVEL
: Controls the verbosity of logs.info
is usually sufficient. Usedebug
ortrace
for troubleshooting.ND_SESSIONTIMEOUT
: How long a user login session remains active.ND_ENABLETRANSCODINGCONFIG
: We'll leave thisfalse
for now; transcoding is covered later.
volumes:
: Maps directories (or specific files) between the host and the container (HOST_PATH:CONTAINER_PATH:OPTIONS
)../data:/data
: Mounts thedata
subdirectory (relative to wheredocker-compose.yml
is, i.e.,~/navidrome/data
) to/data
inside the container. Navidrome stores its database and configuration here. This is essential for data persistence./srv/music:/music:ro
: Mounts your host music library directory (replace/srv/music
!) to/music
inside the container. The:ro
flag makes this mount read-only inside the container. This is a safety measure – Navidrome won't be able to accidentally modify or delete your original music files. Navidrome only needs read access to scan and stream the files.
-
Save and Close the
docker-compose.yml
file (e.g., innano
, pressCtrl+X
, thenY
, thenEnter
).
Workshop Create and Validate docker-compose.yml
Goal: Create the Navidrome docker-compose.yml
file, ensure it's syntactically correct, and understand the mapping of volumes and ports.
Steps:
- Navigate to your chosen directory:
- Verify your UID/GID:
Note down the
uid
andgid
numbers. - Create the
docker-compose.yml
file: Usenano docker-compose.yml
(or your preferred editor). - Paste the YAML content provided in the section above.
- Crucially, edit the file:
- Change
user: "1000:1000"
to match your actual UID/GID if it's different. - Change
- /srv/music:/music:ro
to use the correct full path to your music library on the host machine. - (Optional) Change the
TZ
environment variable to your timezone.
- Change
- Save and close the file.
- Validate the YAML syntax: Docker Compose can check the file for basic errors. Run this command in the same directory (
~/navidrome
): If the file is syntactically correct, it will print the resolved configuration. If there are errors (like incorrect indentation, missing colons), it will report them. Fix any reported errors and rundocker-compose config
again until it succeeds. - Check Directory Permissions:
- Ensure the
./data
directory exists:ls -ld ./data
- Ensure your user (the UID/GID specified in the
user:
directive) owns the./data
directory:sudo chown -R YourUID:YourGID ./data
(replaceYourUID:YourGID
with your numbers, e.g.,1000:1000
). - Ensure your user (the UID/GID) has read access to your music directory:
ls -ld /path/to/your/music
(replace with your actual path). If not, you may need to adjust permissions usingchmod
orchown
, but be careful modifying system-wide permissions. Adding your user to a group that owns the music (e.g.,audio
ormedia
) might be a better approach on some systems.
- Ensure the
Outcome: You have a validated docker-compose.yml
file tailored to your system (user permissions and music path), ready to launch Navidrome. You understand how the volumes
section links your host directories to the container.
3. Launching Navidrome and Initial Setup
With the configuration file ready, we can now start Navidrome.
What are we doing? We are telling Docker Compose to read our docker-compose.yml
file, download the Navidrome image (if not already present), create and start the container according to our specifications.
- Navigate to the Directory: Make sure your terminal is in the directory containing the
docker-compose.yml
file (~/navidrome
in our example). -
Start Navidrome: Use the
docker-compose up
command. The-d
flag runs the container in "detached" mode (in the background).- Docker Compose will read the
docker-compose.yml
. - It will check if the
deluan/navidrome:latest
image exists locally. If not, it will download ("pull") it from Docker Hub. This might take a few moments depending on your internet speed. - It will create the network (if not already existing).
- It will create and start the
navidrome
container based on the image and configuration. - You should see output indicating the
navidrome
container is starting or has started.
- Docker Compose will read the
-
Check Container Status: Verify that the container is running.
You should see thenavidrome
container listed withState
asUp
andPorts
showing0.0.0.0:4533->4533/tcp
(or similar). -
View Logs (Optional but useful): Check the Navidrome logs to see startup messages or potential errors.
-f
follows the log output in real-time. PressCtrl+C
to stop following.- Look for messages indicating Navidrome started successfully and is listening on port 4533. You might also see initial scanning messages if it detects your music library immediately.
-
Access the Navidrome Web UI: Open a web browser on a computer on the same network as your Navidrome server and navigate to:
http://<your-server-ip>:4533
- Replace
<your-server-ip>
with the actual IP address of the machine running Docker and Navidrome. You can usually find this using the commandip addr show
orhostname -I
on the server. - If you are running Docker on the same machine you are browsing from, you can use
http://localhost:4533
orhttp://127.0.0.1:4533
. - Firewall Note: If you have a firewall enabled on the server (like
ufw
on Ubuntu), you might need to allow incoming connections on port 4533:sudo ufw allow 4533/tcp
.
- Replace
-
Create Administrator Account: The first time you access Navidrome, it will prompt you to create an administrator account. Choose a strong username and password. Remember these credentials!
-
Initial Music Scan: After creating the admin user, Navidrome should automatically start scanning the music library you specified (
/music
inside the container, which maps to your host directory like/srv/music
).- You can monitor the scan progress in the Navidrome logs (
docker-compose logs -f
) or wait for the UI to start showing your artists, albums, and tracks. - The duration of the first scan depends heavily on the size of your music library and the performance of your server (CPU and disk I/O). It can range from minutes to hours for very large collections.
- Subsequent scans (triggered automatically based on
ND_SCANINTERVAL
or manually) will be much faster as Navidrome only looks for changes.
- You can monitor the scan progress in the Navidrome logs (
Workshop Launch Navidrome and First Login
Goal: Start the Navidrome container, access its web interface, create the administrator user, and initiate the first music scan.
Steps:
- Open a terminal on your server and navigate to the
~/navidrome
directory. - Run the command to start Navidrome in the background:
- Verify the container is running:
Confirm the
State
isUp
. - Check the logs briefly:
Look for any immediate error messages. You should see lines indicating the server is starting. If you see permission errors related to
/music
or/data
, revisit theuser:
setting indocker-compose.yml
and the directory permissions workshop. - Find your server's IP address: Use
ip addr show
orhostname -I
. Note the IP address (e.g.,192.168.1.100
). - (If applicable) Allow port 4533 through the firewall: If using
ufw
, runsudo ufw status
to check if it's active. If active, runsudo ufw allow 4533/tcp
. - Open a web browser on another computer on the same network (or the same computer if applicable).
- Navigate to
http://<your-server-ip>:4533
, replacing<your-server-ip>
with the address found in step 5. - You should see the Navidrome setup screen. Enter a desired username and a strong password for your administrator account. Click "Create Admin User".
- Log in using the credentials you just created.
- Observe the UI. Depending on your library size, you might see a "Scanning" indicator, or artists/albums may already be appearing. Explore the Settings -> Library section to see scan status.
- Play a track! Once some music appears, click on an album or track and hit the play button in the bottom player bar to confirm basic functionality.
Outcome: You have successfully launched Navidrome using Docker Compose, accessed its web UI, created the necessary admin account, and verified that it's scanning your music library. Your basic Navidrome instance is now operational on your local network.
Intermediate Configuration and Usage
Now that Navidrome is running, let's explore more configuration options, user management, and how to securely access it from outside your home network using a reverse proxy.
4. Understanding Navidrome Configuration Options
Navidrome offers extensive configuration options, primarily controlled via environment variables set in your docker-compose.yml
file or through a dedicated configuration file (though environment variables are generally preferred with Docker). You can find the full list on the official Navidrome documentation website.
What are we doing? We are learning how to fine-tune Navidrome's behavior beyond the initial setup by modifying environment variables in the docker-compose.yml
file.
Key Configuration Areas (using Environment Variables):
ND_MUSICFOLDER
(Default:/music
): Path inside the container where Navidrome looks for music. We already mapped our host music folder to/music
using volumes, so usually, you don't need to change this variable.ND_DATAFOLDER
(Default:/data
): Path inside the container where Navidrome stores its database, cached artwork, etc. We mapped./data
to this, so no change needed here either.ND_SCANINTERVAL
: How often Navidrome automatically rescans the music folder for changes (e.g.,15m
,1h
,24h
). Set according to how often you add music. A manual scan can always be triggered from the UI (Settings -> Library -> Scan Library Now).ND_LOGLEVEL
: Controls log verbosity (error
,warn
,info
,debug
,trace
).info
is a good default. Usedebug
for troubleshooting.ND_SESSIONTIMEOUT
: How long web UI and API sessions remain valid (e.g.,24h
,7d
).ND_ENABLETRANSCODINGCONFIG
(Default:false
): Set totrue
to allow users (with permission) to configure transcoding settings per player in the UI (Settings -> Players). Useful if different devices need different bitrates.ND_DEFAULTTRANSCODING
(Default:raw
): The default transcoding profile applied if a specific player hasn't been configured.raw
means no transcoding by default. Other options often include bitrate limits like192k
. RequiresND_ENABLETRANSCODINGCONFIG
to betrue
for UI configuration.ND_TRANSCODINGCACHESIZE
(Default:100M
): Maximum size for the transcoding cache (e.g.,500M
,2G
). Transcoded files are cached to avoid re-transcoding the same track multiple times. Increase if you have disk space and frequently use transcoding.ND_LASTFM_ENABLED
,ND_LASTFM_APIKEY
,ND_LASTFM_SECRET
,ND_LASTFM_USER
,ND_LASTFM_PASSWORD
: Variables to enable Last.fm scrobbling (details in Advanced section).ND_LISTENBRAINZ_ENABLED
,ND_LISTENBRAINZ_USERTOKEN
: Variables to enable ListenBrainz scrobbling (details in Advanced section).ND_REVERSEPROXYWHITELIST
: Important for reverse proxy setups. A comma-separated list of CIDR blocks (IP address ranges) that are trusted to send proxy headers likeX-Forwarded-For
. Usually set to your reverse proxy's internal Docker network address range (e.g.,172.16.0.0/12
).ND_BASEURL
: If accessing Navidrome through a reverse proxy under a subpath (e.g.,https://yourdomain.com/navidrome
), set this to the subpath (e.g.,/navidrome
).
Applying Configuration Changes:
- Edit
docker-compose.yml
: Open~/navidrome/docker-compose.yml
with your text editor. - Modify Environment Variables: Add or change variables under the
environment:
section for thenavidrome
service. Ensure correct YAML indentation (usually two spaces underenvironment:
). - Save the file.
- Recreate the Container: Navigate to the
~/navidrome
directory in your terminal and run:up -d
: Ensures the container starts in detached mode.--force-recreate
: Tells Docker Compose to stop and remove the existingnavidrome
container and create a new one using the updated configuration. Crucially, because we mounted the/data
volume, your database and settings will be preserved. Only the container itself is replaced.
Example: Change the scan interval to 30 minutes and the log level to debug:
# Inside docker-compose.yml
version: "3"
services:
navidrome:
image: deluan/navidrome:latest
container_name: navidrome
restart: unless-stopped
user: "1000:1000" # Use your UID:GID
ports:
- "4533:4533"
environment:
TZ: "Etc/UTC"
ND_UIWELCOMEMESSAGE: "Welcome to My Music Cloud!"
# --- Changed settings ---
ND_SCANINTERVAL: "30m" # Changed from 1h
ND_LOGLEVEL: "debug" # Changed from info
# --- End of changed settings ---
ND_SESSIONTIMEOUT: "24h"
ND_ENABLETRANSCODINGCONFIG: "false"
volumes:
- ./data:/data
- /srv/music:/music:ro # Replace with your music path
After saving, run cd ~/navidrome && docker-compose up -d --force-recreate
. Check the logs (docker-compose logs
) to verify the log level has increased (more messages).
Workshop Modify Configuration and Recreate Container
Goal: Practice changing Navidrome's configuration via environment variables and applying the changes by recreating the container.
Steps:
- Navigate to the
~/navidrome
directory. - Edit the
docker-compose.yml
file (nano docker-compose.yml
). - Locate the
environment:
section. - Change the
ND_UIWELCOMEMESSAGE
to something different, like"My Awesome Navidrome!"
. - Add a new environment variable to change the number of search results shown per page (default is 50):
Make sure indentation is correct (aligned with other
environment: TZ: "Etc/UTC" # --- Changed setting --- ND_UIWELCOMEMESSAGE: "My Awesome Navidrome!" # --- New setting --- ND_SEARCHRESULTAMOUNT: "25" # --- Existing settings --- ND_SCANINTERVAL: "1h" # Or whatever you had ND_LOGLEVEL: "info" # Or whatever you had ND_SESSIONTIMEOUT: "24h" ND_ENABLETRANSCODINGCONFIG: "false"
ND_
variables). - Save and close the file.
- Apply the changes: Wait for the command to complete.
- Verify the changes:
- Refresh the Navidrome Web UI (
http://<your-server-ip>:4533
). You should see the new welcome message in the top-left corner. - Perform a search in the Navidrome UI. Check if the number of results displayed per page is now 25 (you might need a library large enough to exceed this).
- Refresh the Navidrome Web UI (
- Check the logs (optional): Run
docker-compose logs
to see if Navidrome reports using the new configuration values during startup (it might not explicitly log every variable, but look for any related messages or errors).
Outcome: You have successfully modified Navidrome's configuration using environment variables in docker-compose.yml
and applied these changes without losing persistent data by recreating the container.
5. Managing Users and Permissions
Navidrome supports multiple users, allowing you to share your music library without sharing your admin password. You can control whether users can change their password, configure players (transcoding), share tracks, and more.
What are we doing? Learning how to create new user accounts and manage their privileges within the Navidrome web interface.
- Log in as Administrator: Access the Navidrome Web UI (
http://<your-server-ip>:4533
) and log in with the admin account you created initially. - Navigate to User Management: Click on your username in the top-right corner, then select "Users".
- Create a New User:
- Click the "Add User" button.
- Enter a unique "Username" for the new user.
- Enter a strong "Password" for the user.
- Confirm the password.
- Configure Permissions: Select the checkboxes to grant specific permissions to this user:
- Administrator: Grants full administrative privileges (use with caution!). Only give this to trusted users who need to manage the server settings or other users.
- Allow user to change their password: Recommended for non-admin users.
- Allow downloads: Permits the user to download original music files through the Web UI or compatible clients.
- Allow configuration of players: If
ND_ENABLETRANSCODINGCONFIG
is set totrue
in yourdocker-compose.yml
, this allows the user to access the "Settings -> Players" menu to define transcoding settings for specific clients/devices they use. - Allow sharing: Enables the user to create shareable links for tracks or albums (requires further server configuration, often involving a reverse proxy, to be accessible externally).
- Allow playlist creation/editing: Controls whether the user can manage their own playlists.
- Allow editing of favorites/ratings: Controls whether the user can mark favorites or rate tracks.
- Access All Music Folders: (Relevant if you configure multiple music folders, less common for basic setups). Grants access to all music sources.
- Save User: Click "Save" to create the new user account.
- Editing/Deleting Users: You can click on an existing username in the list to edit their details and permissions or click the trash icon to delete the user account.
Best Practices:
- Use strong, unique passwords for all accounts.
- Grant administrator privileges sparingly.
- For regular users, typically allow password changes, playlist creation, and favorites/ratings. Decide on downloads and sharing based on your trust level and use case.
- Only enable player configuration permission if you've enabled the corresponding
ND_ENABLETRANSCODINGCONFIG
environment variable and the user understands how to use it.
Workshop Create and Test a New User
Goal: Create a non-administrator user account, log in as that user, and verify their permissions.
Steps:
- Log in to Navidrome using your administrator account.
- Go to Users: Click Username -> Users.
- Add a new user:
- Click "Add User".
- Username:
testuser
- Password: Choose a secure password (e.g.,
TestP@ssw0rd!
) - Confirm Password: Enter the same password.
- Permissions:
- Uncheck "Administrator".
- Check "Allow user to change their password".
- Check "Allow playlist creation/editing".
- Check "Allow editing of favorites/ratings".
- Uncheck "Allow downloads".
- Uncheck "Allow configuration of players".
- Uncheck "Allow sharing".
- Click "Save".
- Log Out: Click your admin username -> Log Out.
- Log In as the New User: Use the username
testuser
and the password you set. - Test Permissions:
- Try accessing Users: Click
testuser
username. You should not see a "Users" option, confirming no admin rights. - Try changing password: Click
testuser
username -> Settings -> Password. You should be able to change the password here. - Try creating a playlist: Go to "Playlists" in the left sidebar, click "+ New Playlist". You should be able to create one.
- Try adding a favorite: Find a track or album and click the heart icon. It should work.
- Try downloading: Find a track, click the three dots (...) menu. You should not see a "Download" option (or it should be greyed out/non-functional).
- Try accessing Player Settings: Click
testuser
username -> Settings. You should not see a "Players" section.
- Try accessing Users: Click
- Log out as
testuser
.
Outcome: You have successfully created a restricted user account, logged in as that user, and verified that the permissions set by the administrator are correctly enforced in the UI.
6. Setting Up a Reverse Proxy for Secure Remote Access
Currently, Navidrome is only accessible on your local network via http://<server-ip>:4533
. To access it securely from anywhere over the internet using a custom domain name (e.g., https://music.yourdomain.com
) and HTTPS encryption, you need a reverse proxy.
What is a Reverse Proxy? A reverse proxy is a server that sits in front of one or more web servers (like Navidrome). It receives requests from clients (your browser, mobile app) and forwards them to the appropriate backend server. Key benefits include:
- HTTPS/SSL Termination: The reverse proxy handles the encryption/decryption, so Navidrome doesn't have to. It can manage SSL certificates (often automatically using Let's Encrypt).
- Custom Domain Names: Allows you to use
music.yourdomain.com
instead ofIP:Port
. - Load Balancing: Can distribute requests across multiple instances of an application (not relevant for a single Navidrome instance).
- Security: Can provide an additional layer of security, hiding the backend server's IP and port, and potentially integrating with authentication or web application firewalls.
- Centralized Access: You can run multiple web services on the same server, each accessible via different subdomains or paths, all managed by the single reverse proxy listening on standard ports 80 (HTTP) and 443 (HTTPS).
Popular Reverse Proxy Options (often run in Docker):
- Nginx Proxy Manager (NPM): Very user-friendly web interface for managing proxy hosts and SSL certificates. Great for beginners.
- Traefik: Powerful, cloud-native proxy with automatic service discovery (integrates well with Docker labels). Steeper learning curve than NPM.
- Caddy: Known for its simplicity and automatic HTTPS by default. Configuration is done via a Caddyfile.
We will demonstrate using Nginx Proxy Manager (NPM) as it's beginner-friendly. The principles apply to other proxies, but the specific configuration steps differ.
Prerequisites:
- Domain Name: You need a domain name (e.g.,
yourdomain.com
) registered. - DNS Configuration: You need to configure a DNS A record (or CNAME) pointing your desired subdomain (e.g.,
music.yourdomain.com
) to the public IP address of your server. How you do this depends on your domain registrar (GoDaddy, Namecheap, Cloudflare, etc.). - Ports 80 and 443 Forwarded: If your server is behind a home router, you need to configure port forwarding on your router to send incoming traffic on ports 80 (for HTTP validation) and 443 (for HTTPS) to the internal IP address of the server running the reverse proxy.
Setting up Nginx Proxy Manager with Docker Compose:
- Create NPM Directories: Similar to Navidrome, create directories for NPM's configuration and data.
-
Create
docker-compose.yml
for NPM: Create~/npm/docker-compose.yml
with the following content:version: '3.8' services: app: image: 'jc21/nginx-proxy-manager:latest' container_name: npm restart: unless-stopped ports: # Public HTTP Port: - '80:8080' # Public HTTPS Port: - '443:443' # Admin Web Port: - '81:8181' environment: # These are the important settings required for NPM to function: DB_SQLITE_FILE: "/data/database.sqlite" # Set to '1' to migrate existing letsencrypt certificates from older versions #DISABLE_IPV6: 'true' # Uncomment if you don't have IPv6 connectivity volumes: - ./data:/data - ./letsencrypt:/etc/letsencrypt
- Ports: Maps host ports 80, 443 to internal NPM ports. It also exposes port 81 on the host, mapping to NPM's admin interface on 8181. Make sure ports 80, 443, and 81 are free on your host (or change the host-side port, e.g.,
8080:8080
,8443:443
,8181:8181
, but remember you'll need to forward 80/443 on your router to these custom host ports if used). - Volumes: Persists NPM's data (users, hosts, settings) and Let's Encrypt certificates.
- Ports: Maps host ports 80, 443 to internal NPM ports. It also exposes port 81 on the host, mapping to NPM's admin interface on 8181. Make sure ports 80, 443, and 81 are free on your host (or change the host-side port, e.g.,
-
Start NPM:
- Access NPM Admin UI: Open your browser to
http://<your-server-ip>:81
. - Default Login: Log in with the default credentials:
- Email:
admin@example.com
- Password:
changeme
- Email:
- Change Credentials: Immediately change the email address and password to secure ones.
Configuring NPM to Proxy Navidrome:
- Log in to NPM Admin UI (
http://<your-server-ip>:81
). - Go to Hosts -> Proxy Hosts.
- Click "Add Proxy Host".
-
Details Tab:
- Domain Names: Enter the subdomain you configured in DNS (e.g.,
music.yourdomain.com
). - Scheme: Select
http
. - Forward Hostname / IP: Enter the IP address of your server (the one running Docker). Do not use
localhost
or127.0.0.1
here unless NPM is running outside Docker on the same host. Use the server's actual network IP (e.g.,192.168.1.100
). - Forward Port: Enter the port Navidrome is exposed on (e.g.,
4533
). - Cache Assets: Optional, can slightly improve performance.
- Block Common Exploits: Recommended, enable this.
- Websockets Support: Crucial! Enable this toggle. Navidrome uses websockets for real-time communication (like playback progress).
- Domain Names: Enter the subdomain you configured in DNS (e.g.,
-
SSL Tab:
- SSL Certificate: Select "Request a new SSL Certificate".
- Force SSL: Enable this to automatically redirect HTTP requests to HTTPS.
- HTTP/2 Support: Enable this for better performance.
- Email Address for Let's Encrypt: Enter your email address (Let's Encrypt uses this for renewal notices).
- I Agree: Check the box to agree to the Let's Encrypt Terms of Service.
- Click Save.
-
Wait for Certificate: NPM will now attempt to obtain an SSL certificate from Let's Encrypt using the DNS record you set up and port 80 access. This might take a minute or two. The status should change from "Offline" to "Online" if successful. If it fails, check:
- Your DNS record is correct and has propagated (use
nslookup music.yourdomain.com
or an online DNS checker). - Port 80 is correctly forwarded from your router to the server running NPM.
- Your server's firewall allows incoming traffic on port 80.
- Your DNS record is correct and has propagated (use
Accessing Navidrome Securely:
- You should now be able to access Navidrome via
https://music.yourdomain.com
. - Traffic is encrypted between your browser/app and NPM.
- Traffic between NPM and Navidrome (e.g.,
192.168.1.100:4533
) is typically unencrypted on your local network, which is generally considered acceptable in a home environment.
(Optional) Update Navidrome Configuration for Reverse Proxy: While not strictly necessary with the above NPM setup, if you encounter issues with redirects or incorrect source IPs in logs, you might need to tell Navidrome it's behind a proxy.
- Find NPM's Docker Network IP Range:
- Find the network name used by NPM (usually
npm_default
if you randocker-compose up
in the~/npm
directory):docker network ls
- Inspect the network to find its subnet:
docker network inspect npm_default
(look for the "Subnet" under "IPAM" -> "Config"). It might be something like172.20.0.0/16
.
- Find the network name used by NPM (usually
- Edit Navidrome's
docker-compose.yml
: Add/modify theND_REVERSEPROXYWHITELIST
environment variable. - Recreate Navidrome Container:
Workshop Set Up Reverse Proxy with NPM
Goal: Install Nginx Proxy Manager, configure it to proxy Navidrome, obtain an SSL certificate, and access Navidrome securely via a custom domain.
Prerequisites Check:
- Do you have a registered domain name?
- Have you created a DNS A record (e.g.,
music.yourdomain.com
) pointing to your server's public IP? - Have you forwarded ports 80 and 443 from your router to your server's internal IP?
Steps:
- Install NPM: Follow steps 1-3 in the "Setting up Nginx Proxy Manager" section above (create directories, create
docker-compose.yml
, rundocker-compose up -d
). - Access NPM Admin: Open
http://<your-server-ip>:81
. - Initial Login & Secure: Log in with
admin@example.com
/changeme
. Immediately change the details and password. - Add Proxy Host for Navidrome:
- Go to Hosts -> Proxy Hosts -> Add Proxy Host.
- Details Tab:
- Domain Names:
music.yourdomain.com
(use your actual subdomain) - Scheme:
http
- Forward Hostname / IP:
<your-server-internal-ip>
(e.g.,192.168.1.100
) - Forward Port:
4533
- Enable:
Block Common Exploits
- Enable:
Websockets Support
- Domain Names:
- SSL Tab:
- SSL Certificate:
Request a new SSL Certificate
- Enable:
Force SSL
- Enable:
HTTP/2 Support
- Email Address: Your real email address
- Enable:
I Agree...
- SSL Certificate:
- Click Save.
- Monitor Certificate Acquisition: Watch the status indicator for your host in the NPM list. It should turn green ("Online") within a couple of minutes. If it stays "Offline" or shows an error, double-check prerequisites (DNS, port forwarding). Check the NPM logs (
cd ~/npm && docker-compose logs -f
) for detailed error messages from Let's Encrypt. - Test Access: Open a new browser tab and navigate to
https://music.yourdomain.com
(using your actual domain). You should see the Navidrome login page, and the browser should show a valid padlock icon indicating a secure HTTPS connection. - Test Login: Log in to Navidrome via the HTTPS domain to ensure everything works.
- (Optional) Whitelist Proxy: If needed, perform the optional steps to find the NPM network subnet and add
ND_REVERSEPROXYWHITELIST
to Navidrome's configuration.
Outcome: You have successfully set up Nginx Proxy Manager and configured it to provide secure, encrypted access to your Navidrome instance from the internet using a custom domain name.
Advanced Topics
This section delves into more complex aspects of managing your Navidrome server, including security, backups, integrations, and troubleshooting.
7. Security Hardening
While a reverse proxy with HTTPS provides essential transport security, further steps can enhance the overall security posture of your Navidrome instance and the host server.
What are we doing? Implementing additional security measures to protect against unauthorized access, brute-force attacks, and potential vulnerabilities.
Key Hardening Techniques:
-
Strong Passwords & User Management:
- Enforce strong, unique passwords for the host OS, Docker, Navidrome admin, and all user accounts.
- Regularly review Navidrome user accounts and remove any that are no longer needed.
- Grant administrator privileges only when absolutely necessary.
-
Firewall Configuration (
ufw
):- Ensure a host-based firewall (like
ufw
- Uncomplicated Firewall on Debian/Ubuntu) is enabled and configured correctly. - Default Deny Policy: Set the default policy to deny all incoming traffic:
sudo ufw default deny incoming
. - Allow Specific Ports: Explicitly allow only necessary incoming ports:
sudo ufw allow ssh
(or your custom SSH port) - Essential for server access.sudo ufw allow 80/tcp
- Required by the reverse proxy (NPM) for HTTP validation (Let's Encrypt).sudo ufw allow 443/tcp
- Required by the reverse proxy (NPM) for HTTPS traffic.sudo ufw allow 81/tcp
- Required to access the NPM admin interface (or your chosen admin port). Consider restricting this port to only your local network or specific trusted IPs if possible:sudo ufw allow from 192.168.1.0/24 to any port 81 proto tcp
(replace with your LAN subnet).- Do NOT allow port 4533 (Navidrome's direct port) from the internet. Access should only go through the reverse proxy (port 443).
- Enable Firewall:
sudo ufw enable
- Check Status:
sudo ufw status verbose
- Ensure a host-based firewall (like
-
Fail2Ban:
- Fail2Ban scans log files (like SSH logs, web server logs) and bans IP addresses that show malicious signs (too many password failures, seeking exploits, etc.). It integrates with the system firewall (
ufw
,iptables
) to block offending IPs temporarily or permanently. - Installation:
sudo apt update && sudo apt install fail2ban
- Configuration: Fail2ban configuration is done via
.local
files that override the defaults in.conf
files (so updates don't overwrite your settings).- Copy the main configuration:
sudo cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local
- Edit
jail.local
:sudo nano /etc/fail2ban/jail.local
- Customize
[DEFAULT]
settings: Adjustbantime
(how long an IP is banned, e.g.,1h
,1d
),findtime
(window for counting retries),maxretry
(number of failures before ban). - Enable Jails: Find sections corresponding to services you want to protect (e.g.,
[sshd]
,[nginx-http-auth]
). Ensureenabled = true
for those sections. - NPM Integration: Nginx Proxy Manager logs failed authentication attempts to its Docker container logs. You can configure Fail2ban to monitor these logs. This is more advanced and involves:
- Creating a custom Fail2ban filter for NPM logs.
- Creating a custom Fail2ban jail definition in
jail.local
that uses the filter and points to the NPM log file (which might require mounting the NPM log file or directory to the host or using a Docker log driver that Fail2ban can access). Consult Fail2ban and NPM documentation for specific implementations.
- Customize
- Copy the main configuration:
- Restart Fail2ban:
sudo systemctl restart fail2ban
- Check Status:
sudo fail2ban-client status
andsudo fail2ban-client status <jail_name>
(e.g.,sudo fail2ban-client status sshd
).
- Fail2Ban scans log files (like SSH logs, web server logs) and bans IP addresses that show malicious signs (too many password failures, seeking exploits, etc.). It integrates with the system firewall (
-
Regular Updates:
- Keep the host operating system up-to-date:
sudo apt update && sudo apt upgrade -y
. - Keep Docker and Docker Compose updated (follow official Docker documentation).
- Regularly update Navidrome and your reverse proxy (NPM) Docker images:
Consider using specific version tags (e.g.,
# In the navidrome directory cd ~/navidrome docker-compose pull # Pulls the latest image defined in docker-compose.yml (e.g., :latest) docker-compose up -d --force-recreate # Recreates container with the new image # In the npm directory cd ~/npm docker-compose pull docker-compose up -d --force-recreate
deluan/navidrome:0.50.1
) instead of:latest
in yourdocker-compose.yml
for more predictable updates, checking release notes before upgrading. Tools like Watchtower can automate container updates, but use them cautiously in production environments.
- Keep the host operating system up-to-date:
-
Docker Security:
- Run as Non-Root User: We already configured Navidrome to run as a specific non-root user (
user: "UID:GID"
). This limits the container's potential impact if compromised. Do the same for other containers where possible. - Limit Capabilities: For highly sensitive environments, explore dropping unnecessary Linux capabilities from containers.
- Network Segmentation: Use Docker custom networks to isolate containers. By default, Docker Compose creates a network for each project, which is good practice. Avoid using the default
bridge
network extensively. - Read-Only Mounts: Mount volumes as read-only (
:ro
) whenever write access isn't strictly necessary (like our music library mount).
- Run as Non-Root User: We already configured Navidrome to run as a specific non-root user (
Workshop Implement Basic Firewall Rules and Check Updates
Goal: Configure basic firewall rules using ufw
and practice checking for and applying container updates.
Steps:
- Check
ufw
Status: If inactive, proceed with setup. If active, review existing rules carefully before changing. - Set Default Policy (If Inactive/Safe):
- Allow Essential Ports:
- Enable
ufw
: Confirm with 'y' if prompted. Your SSH session should remain active if you allowed the SSH port correctly. - Verify Rules: Check that the rules match what you intended.
- Check for Navidrome Image Updates:
This will check Docker Hub for a newer version of the
deluan/navidrome:latest
image (or the specific version you tagged). It will report if a newer image was downloaded or if it's already up-to-date. - Check for NPM Image Updates:
Checks for updates to the
jc21/nginx-proxy-manager:latest
image. - Apply Updates (If any were downloaded):
- If
navidrome
updated: - If
npm
updated:
- If
- Test Functionality: After applying updates, briefly test accessing Navidrome via its HTTPS domain and the NPM admin UI to ensure they restarted correctly.
Outcome: You have configured basic firewall rules on your host using ufw
to limit incoming connections to essential services. You have also learned how to check for and apply updates to your Docker containers safely.
8. Backup and Restore Strategy
Data loss can happen due to hardware failure, accidental deletion, or software issues. A robust backup strategy is crucial for any self-hosted service, especially one containing user data and configuration like Navidrome.
What are we doing? Planning and implementing a method to regularly back up Navidrome's essential data and configuration, enabling recovery in case of disaster.
What Needs Backing Up?
- Navidrome Data Volume: This is the most critical part. It contains the Navidrome database (users, playlists, ratings, play counts, settings), cover art cache, and other application state. In our setup, this corresponds to the
~/navidrome/data
directory on the host. docker-compose.yml
File: This file defines how your Navidrome service is configured (environment variables, ports, volumes, user ID). You need this to recreate the container correctly. Our file is~/navidrome/docker-compose.yml
.- (Optional but Recommended) Music Files: Navidrome doesn't store your music, it just reads it. However, your music files themselves should be backed up independently using your preferred method (external drives, cloud storage, NAS sync, etc.). This is outside the scope of backing up Navidrome's data, but essential for your library.
- (If using Reverse Proxy) Reverse Proxy Configuration: If using NPM, you need to back up its data volume (
~/npm/data
and~/npm/letsencrypt
). If using Traefik or Caddy, back up their configuration files and certificate stores.
Backup Methods:
- Manual Copy: The simplest method is to periodically stop the containers and manually copy the relevant directories to a backup location (e.g., external drive, network share).
- Pros: Simple to understand.
- Cons: Manual effort, easy to forget, requires downtime.
- Scripted
rsync
: Use thersync
command-line utility in a script to copy the data directories efficiently to a backup location. Can be automated usingcron
.- Pros: Efficient (only copies changes), scriptable, widely available.
- Cons: Requires scripting knowledge, potential for inconsistencies if containers are not stopped during backup (though often acceptable for Navidrome's SQLite DB if done quickly).
- Docker Volume Backup Tools: Tools specifically designed to back up Docker volumes (e.g.,
docker-volume-backup
,restic
with Docker integration).- Pros: Can handle volume backups directly, some offer advanced features like deduplication and encryption (restic).
- Cons: May have a steeper learning curve, introduces another tool dependency.
Implementing a Scripted rsync
Backup:
This is a common and effective approach.
- Choose Backup Location: Decide where backups will be stored (e.g.,
/mnt/backups/navidrome
, a USB drive, a remote server via SSH). Ensure the location has sufficient space. Let's use/mnt/backups/navidrome
. - Create a Backup Script: Create a file, e.g.,
~/navidrome_backup.sh
. -
Add Script Content:
#!/bin/bash # --- Configuration --- NAVIDROME_COMPOSE_DIR="$HOME/navidrome" # Directory with docker-compose.yml NAVIDROME_DATA_DIR="$NAVIDROME_COMPOSE_DIR/data" # Navidrome data directory on host NPM_COMPOSE_DIR="$HOME/npm" # NPM compose directory (if using NPM) NPM_DATA_DIR="$NPM_COMPOSE_DIR/data" # NPM data directory NPM_LE_DIR="$NPM_COMPOSE_DIR/letsencrypt" # NPM certs directory BACKUP_BASE_DIR="/mnt/backups" # Base directory for backups BACKUP_DEST_NAVIDROME="$BACKUP_BASE_DIR/navidrome" BACKUP_DEST_NPM="$BACKUP_BASE_DIR/npm" TIMESTAMP=$(date +"%Y%m%d_%H%M%S") LOG_FILE="$BACKUP_BASE_DIR/backup_log_${TIMESTAMP}.txt" # --- Functions --- log() { echo "$(date +"%Y-%m-%d %H:%M:%S") - $1" | tee -a "$LOG_FILE" } # --- Pre-Checks --- log "Starting backup process..." if [ ! -d "$NAVIDROME_COMPOSE_DIR" ]; then log "ERROR: Navidrome compose directory not found: $NAVIDROME_COMPOSE_DIR" exit 1 fi if [ ! -d "$NAVIDROME_DATA_DIR" ]; then log "ERROR: Navidrome data directory not found: $NAVIDROME_DATA_DIR" exit 1 fi if [ ! -d "$NPM_COMPOSE_DIR" ]; then log "WARNING: NPM compose directory not found: $NPM_COMPOSE_DIR. Skipping NPM backup." SKIP_NPM=true else SKIP_NPM=false if [ ! -d "$NPM_DATA_DIR" ]; then log "ERROR: NPM data directory not found: $NPM_DATA_DIR" exit 1 fi if [ ! -d "$NPM_LE_DIR" ]; then log "ERROR: NPM letsencrypt directory not found: $NPM_LE_DIR" exit 1 fi fi if [ ! -d "$BACKUP_BASE_DIR" ]; then log "ERROR: Backup base directory not found: $BACKUP_BASE_DIR" exit 1 fi mkdir -p "$BACKUP_DEST_NAVIDROME" if [ "$SKIP_NPM" = false ]; then mkdir -p "$BACKUP_DEST_NPM" fi # --- Optional: Stop Containers (Safer for DB consistency) --- # log "Stopping Navidrome container..." # cd "$NAVIDROME_COMPOSE_DIR" && docker-compose stop navidrome >> "$LOG_FILE" 2>&1 # if [ "$SKIP_NPM" = false ]; then # log "Stopping NPM container..." # cd "$NPM_COMPOSE_DIR" && docker-compose stop app >> "$LOG_FILE" 2>&1 # fi # sleep 5 # Give containers time to stop gracefully # --- Perform Backup using rsync --- log "Backing up Navidrome config file..." rsync -av --delete "$NAVIDROME_COMPOSE_DIR/docker-compose.yml" "$BACKUP_DEST_NAVIDROME/" >> "$LOG_FILE" 2>&1 log "Backing up Navidrome data directory..." rsync -av --delete "$NAVIDROME_DATA_DIR/" "$BACKUP_DEST_NAVIDROME/data/" >> "$LOG_FILE" 2>&1 # Note the trailing slash on the source ($NAVIDROME_DATA_DIR/) - this copies the *contents* if [ "$SKIP_NPM" = false ]; then log "Backing up NPM config file..." rsync -av --delete "$NPM_COMPOSE_DIR/docker-compose.yml" "$BACKUP_DEST_NPM/" >> "$LOG_FILE" 2>&1 log "Backing up NPM data directory..." rsync -av --delete "$NPM_DATA_DIR/" "$BACKUP_DEST_NPM/data/" >> "$LOG_FILE" 2>&1 log "Backing up NPM letsencrypt directory..." rsync -av --delete "$NPM_LE_DIR/" "$BACKUP_DEST_NPM/letsencrypt/" >> "$LOG_FILE" 2>&1 fi # --- Optional: Restart Containers --- # log "Starting Navidrome container..." # cd "$NAVIDROME_COMPOSE_DIR" && docker-compose start navidrome >> "$LOG_FILE" 2>&1 # if [ "$SKIP_NPM" = false ]; then # log "Starting NPM container..." # cd "$NPM_COMPOSE_DIR" && docker-compose start app >> "$LOG_FILE" 2>&1 # fi log "Backup process completed." echo "Log file: $LOG_FILE" exit 0
- Explanation:
- Sets variables for source directories and backup destination.
- Includes basic checks and logging.
- Uses
rsync -av --delete
:a
: Archive mode (preserves permissions, ownership, timestamps, etc.).v
: Verbose output.--delete
: Deletes files in the destination that no longer exist in the source (keeps backup synchronized). Use with caution - ensure your source data is what you want.
- Trailing Slashes: Note
rsync -av "$SOURCE_DIR/" "$DEST_DIR/"
copies the contents ofSOURCE_DIR
intoDEST_DIR
. Without the trailing slash on the source, it would copySOURCE_DIR
itself intoDEST_DIR
. - Stopping Containers: The script includes commented-out sections (
# log "Stopping..."
etc.) to stop and start the containers. Uncommenting these lines ensures maximum data consistency (especially for the database) but introduces downtime during the backup. For Navidrome's SQLite database, backing up while running is often okay, but stopping is safer. Decide based on your tolerance for risk vs. downtime.
- Explanation:
-
Make Script Executable:
- Run Manually: Test the script:
Check the output and the log file (
/mnt/backups/backup_log_*.txt
). Verify the files are copied correctly to/mnt/backups/navidrome
and/mnt/backups/npm
. - Automate with Cron: Schedule the script to run automatically.
- Edit the crontab:
crontab -e
(select an editor if prompted). - Add a line to run the script, e.g., daily at 3:00 AM:
- Replace
/home/yourusername
with the actual path to the script. 0 3 * * *
means: 0th minute, 3rd hour, every day of month, every month, every day of week.> /dev/null 2>&1
redirects standard output and standard error to/dev/null
, preventing cron emails. The script itself logs to a file.
- Replace
- Save and close the crontab.
- Edit the crontab:
Restore Process:
- Stop Existing Containers (if any):
- Clear Existing Data (Use with extreme caution!): Optionally, remove the potentially corrupted existing data directories before restoring:
Alternatively, rename the old directories (e.g.,
# DANGER ZONE: Make sure you have a good backup first! # rm -rf ~/navidrome/data/* # rm -f ~/navidrome/docker-compose.yml # rm -rf ~/npm/data/* # rm -rf ~/npm/letsencrypt/* # rm -f ~/npm/docker-compose.yml
mv ~/navidrome/data ~/navidrome/data.old
). - Restore from Backup: Use
rsync
orcp
to copy the backed-up files back to their original locations.# Example using rsync rsync -av /mnt/backups/navidrome/docker-compose.yml ~/navidrome/ rsync -av /mnt/backups/navidrome/data/ ~/navidrome/data/ # If restoring NPM rsync -av /mnt/backups/npm/docker-compose.yml ~/npm/ rsync -av /mnt/backups/npm/data/ ~/npm/data/ rsync -av /mnt/backups/npm/letsencrypt/ ~/npm/letsencrypt/
- Verify Permissions: Ensure the restored
~/navidrome/data
directory (and~/npm/*
directories if applicable) have the correct ownership and permissions for theuser:
specified in thedocker-compose.yml
files (e.g.,sudo chown -R 1000:1000 ~/navidrome/data
). - Start Containers:
- Test: Access Navidrome and check if your users, playlists, settings, etc., are restored.
Workshop Manually Backup and Restore Navidrome Data
Goal: Simulate a failure scenario by manually backing up Navidrome's essential files, removing them, and then restoring them.
Important: This workshop involves removing data. Ensure you understand the steps. We are only touching the Navidrome data
and compose
file, not your actual music files or NPM data for simplicity.
Steps:
- Create a temporary backup directory:
- Stop Navidrome:
-
Backup the data and compose file:
cp ~/navidrome/docker-compose.yml ~/navidrome_manual_backup/ cp -a ~/navidrome/data ~/navidrome_manual_backup/ # -a preserves permissions/ownership
- Verify the files/directory exist in
~/navidrome_manual_backup
. Usels -l ~/navidrome_manual_backup
andls -l ~/navidrome_manual_backup/data
.
- Verify the files/directory exist in
-
Simulate Data Loss (DANGER): Remove the original files:
# Be absolutely sure the backup in step 3 was successful! rm -f ~/navidrome/docker-compose.yml rm -rf ~/navidrome/data
- Verify they are gone:
ls ~/navidrome
. Thedata
directory anddocker-compose.yml
should be missing.
- Verify they are gone:
-
Restore from Backup:
-
Verify Restoration:
- Check that
~/navidrome/docker-compose.yml
exists again. - Check that
~/navidrome/data
exists and contains files (ls -l ~/navidrome/data
). - Crucially, check ownership:
ls -ld ~/navidrome/data
. Does the owner/group match theuser: "UID:GID"
in yourdocker-compose.yml
? If not (e.g., it showsroot:root
), fix it:sudo chown -R YourUID:YourGID ~/navidrome/data
(replaceYourUID:YourGID
).
- Check that
-
Restart Navidrome:
- Test: Access the Navidrome web UI. Log in as your admin user. Are your settings, users (if you created any beyond admin), and library state (scan progress, playlists, favorites) as they were before the "failure"? Play a track.
- Clean up: Once confirmed, you can remove the temporary backup:
rm -rf ~/navidrome_manual_backup
.
Outcome: You have successfully performed a manual backup and restore of the essential Navidrome configuration and data volume, simulating recovery from data loss. You understand the importance of backing up the correct files and verifying permissions after restoration.
9. Integration with Scrobbling Services
Scrobbling services like Last.fm and ListenBrainz keep a record of your music listening history. Navidrome can automatically send ("scrobble") information about the tracks you play to these services.
What are we doing? Configuring Navidrome to connect to Last.fm or ListenBrainz and automatically update your listening history there.
Prerequisites:
- An account with Last.fm or ListenBrainz.
- For Last.fm: You need an API key and secret. Go to https://www.last.fm/api/account/create, fill out the form (application name can be "Navidrome", description can be anything), and get your API Key and Shared Secret.
Configuration (via Environment Variables):
- Edit Navidrome's
docker-compose.yml
:nano ~/navidrome/docker-compose.yml
-
Add Environment Variables: Under the
environment:
section:- For Last.fm:
# --- Last.fm Scrobbling --- ND_LASTFM_ENABLED: "true" ND_LASTFM_APIKEY: "YOUR_LASTFM_API_KEY" # Replace with your key ND_LASTFM_SECRET: "YOUR_LASTFM_SECRET" # Replace with your secret # Optional: If you want ALL users to scrobble to the SAME Last.fm account: # ND_LASTFM_USER: "YourLastfmUsername" # ND_LASTFM_PASSWORD: "YourLastfmPassword" # Note: If ND_LASTFM_USER/PASSWORD are set, individual users cannot configure # their own accounts in the UI. Leave them unset for per-user configuration.
- For ListenBrainz:
You can enable both services simultaneously.
# --- ListenBrainz Scrobbling --- ND_LISTENBRAINZ_ENABLED: "true" # Optional: If you want ALL users to scrobble to the SAME ListenBrainz account: # ND_LISTENBRAINZ_USERTOKEN: "YOUR_LISTENBRAINZ_USER_TOKEN" # Find in ListenBrainz profile # Note: If ND_LISTENBRAINZ_USERTOKEN is set, individual users cannot configure # their own accounts in the UI. Leave it unset for per-user configuration.
- For Last.fm:
-
Save the file.
- Recreate Navidrome Container:
Per-User Scrobbling Configuration (Recommended):
If you didn't set the global ND_LASTFM_USER
/PASSWORD
or ND_LISTENBRAINZ_USERTOKEN
variables, individual users can link their own accounts:
- Log in to Navidrome as the user who wants to enable scrobbling.
- Go to Settings -> Personal.
- Scroll down to the "Scrobbling Services" section.
- For Last.fm:
- Click "Connect to Last.fm".
- You will be redirected to Last.fm to authorize Navidrome.
- Grant access, and you should be redirected back to Navidrome. The status should show your Last.fm username.
- For ListenBrainz:
- Go to your ListenBrainz profile page and find your "User Token".
- Copy the token.
- Paste it into the "ListenBrainz User Token" field in Navidrome's settings.
- Click "Save". The status should show "Enabled".
How it Works: Once configured (either globally or per-user), Navidrome will send data about tracks you play (artist, album, track name) to the respective service after you've listened to a significant portion (usually half the track or 4 minutes, whichever comes first). This updates your profile on Last.fm/ListenBrainz.
Workshop Configure Last.fm Scrobbling
Goal: Enable Last.fm scrobbling in Navidrome and link your personal Last.fm account.
Prerequisites:
- A Last.fm account.
- A Last.fm API Key and Shared Secret (obtained from https://www.last.fm/api/account/create).
Steps:
- Edit Navidrome's
docker-compose.yml
: - Add Last.fm environment variables under
environment:
, replacing the placeholders with your actual API key and secret. Do NOT addND_LASTFM_USER
orND_LASTFM_PASSWORD
for this workshop (we want per-user setup). - Save and close the file.
- Recreate the Navidrome container:
- Log in to Navidrome with your regular (or admin) user account.
- Go to Personal Settings: Click Username -> Settings -> Personal.
- Connect to Last.fm: Scroll down to "Scrobbling Services" and click "Connect to Last.fm".
- Authorize on Last.fm: Follow the prompts on the Last.fm website to grant access to the application (it should use the name you provided when creating the API key).
- Verify Connection: After being redirected back to Navidrome, the Last.fm section in Settings -> Personal should now display your Last.fm username.
- Test Scrobbling: Play a track in Navidrome for at least half its duration or a few minutes.
- Check Last.fm: Go to your profile page on the Last.fm website. The track you just played should appear in your recent listening history (it might take a minute or two to show up).
Outcome: You have successfully enabled Last.fm integration and configured your user account to automatically scrobble played tracks from Navidrome to your Last.fm profile.
10. Troubleshooting Common Issues
Even with careful setup, you might encounter problems. Knowing where to look for clues is essential.
What are we doing? Learning common troubleshooting steps and how to interpret logs and diagnose problems.
Common Problem Areas & Solutions:
-
Container Fails to Start:
- Symptom:
docker-compose ps
shows the containerState
asExited
orRestarting
. - Diagnosis: Check the container logs immediately after trying to start it: Look for error messages near the end of the log output.
- Common Causes & Fixes:
- Port Conflict: Log shows "Error starting userland proxy: listen tcp4 0.0.0.0:4533: bind: address already in use". Another service on your host is using port 4533 (or 80/443/81 for NPM). Stop the other service or change the host-side port mapping in
docker-compose.yml
(e.g.,"8888:4533"
). - Volume Mount Issues: Log shows permission errors related to
/data
or/music
("Permission denied").- Verify the
user: "UID:GID"
indocker-compose.yml
matches the owner of the host directories (~/navidrome/data
,/path/to/music
). Usels -ld ~/navidrome/data
andls -ld /path/to/music
to check ownership. - Use
sudo chown -R UID:GID ~/navidrome/data
to fix data directory ownership if needed. - Ensure the specified UID/GID has read access to the music directory.
- Verify the host paths in the
volumes:
section are correct and exist.
- Verify the
- Incorrect
docker-compose.yml
Syntax: Rundocker-compose config
to validate the file. Fix any reported YAML errors (indentation, colons, etc.). - Database Corruption: Logs might show SQLite errors. This is rarer but could happen after unclean shutdowns. Restoring from backup might be necessary.
- Port Conflict: Log shows "Error starting userland proxy: listen tcp4 0.0.0.0:4533: bind: address already in use". Another service on your host is using port 4533 (or 80/443/81 for NPM). Stop the other service or change the host-side port mapping in
- Symptom:
-
Web UI Not Accessible:
- Symptom: Browser shows "This site can’t be reached" or "Connection refused" when trying to access
http://<server-ip>:4533
orhttps://music.yourdomain.com
. - Diagnosis:
- Is the container running?
docker-compose ps
. If not, see problem 1. - Is the port mapped correctly? Check
docker-compose ps
output for thePORTS
column (e.g.,0.0.0.0:4533->4533/tcp
). - Is there a host firewall blocking the port? Check
sudo ufw status
. Ensure the necessary port (4533 for direct access, 443/80 for reverse proxy) is allowed. - Is the reverse proxy running and configured correctly? (If using domain access). Check NPM logs (
cd ~/npm && docker-compose logs
), ensure the proxy host is "Online" in the NPM UI, check DNS records (nslookup music.yourdomain.com
), check router port forwarding for 80/443. - Are you using the correct IP/domain and port? Double-check the URL.
- (Reverse Proxy Specific) Websocket issue? Ensure "Websockets Support" is enabled in NPM for the Navidrome host. Check browser developer console (F12) for websocket connection errors.
- Is the container running?
- Symptom: Browser shows "This site can’t be reached" or "Connection refused" when trying to access
-
Music Library Not Scanning / Files Missing:
- Symptom: No music appears, or newly added files aren't showing up after waiting for the scan interval.
- Diagnosis:
- Check Navidrome Logs:
docker-compose logs -f navidrome
. Trigger a manual scan (Settings -> Library -> Scan Library Now) and watch the logs for activity or errors. - Verify Volume Mount: Does the
/music
volume indocker-compose.yml
point correctly to your actual music library on the host? Is it read-only (:ro
)? - Check Permissions: Does the
user: "UID:GID"
specified indocker-compose.yml
have read permissions for the music directory and all subdirectories and files on the host? This is a very common issue. Usels -l
on various subdirectories within your music folder to check. You might need to usesudo chmod -R +r /path/to/music
or adjust group permissions. - File Formats: Does Navidrome support the file formats? It supports most common ones (MP3, AAC, FLAC, Ogg Vorbis, OPUS, ALAC, etc.). Check logs for messages about unsupported files.
- Metadata: Navidrome relies heavily on embedded metadata tags. Files with missing or corrupt tags might not scan correctly or show up organized properly. Use a tagging tool (like MusicBrainz Picard, Mp3tag) to ensure files are tagged.
- Scan Interval: Is
ND_SCANINTERVAL
set appropriately? Trigger a manual scan to be sure.
- Check Navidrome Logs:
-
Playback Issues (Web UI or Clients):
- Symptom: Music stutters, stops, or fails to play.
- Diagnosis:
- Check Navidrome Logs: Look for errors related to playback or transcoding during the time of the issue.
- Check Browser Developer Console (F12): Look for network errors or Javascript errors in the "Console" or "Network" tabs when trying to play.
- Network Issues: Is your network connection (between client and server, and server's internet if transcoding requires external codecs) stable and fast enough?
- Transcoding Overload: If transcoding is enabled, is the server CPU overloaded? Use
htop
ordocker stats navidrome
on the host to monitor CPU usage during playback/transcoding. Low-power devices (like Raspberry Pi) might struggle with high-bitrate transcoding. Try disabling transcoding or choosing a lower bitrate profile in player settings (ifND_ENABLETRANSCODINGCONFIG
is true). - Client Compatibility: Is the Subsonic client app compatible and configured correctly (Server URL:
https://music.yourdomain.com
, Username, Password)? Try the Navidrome web UI first to isolate the issue. - (Reverse Proxy Specific) Websocket issue? Ensure websockets are enabled and working through the proxy.
General Troubleshooting Strategy:
- Isolate the Problem: Is it affecting all users or just one? Web UI only or clients too? Specific tracks or all music?
- Check Logs: Start with the logs of the affected component (Navidrome, NPM). Increase log level (
ND_LOGLEVEL: "debug"
) if necessary (remember to recreate the container). - Check Container Status:
docker-compose ps
. Are containers running? - Check Configuration: Review
docker-compose.yml
, NPM settings, firewall rules, DNS. - Check Permissions: File system permissions for data and music volumes are frequent culprits.
- Restart: Sometimes a simple container restart resolves temporary glitches:
docker-compose restart navidrome
. - Search Online: Use specific error messages from logs to search the Navidrome documentation, GitHub issues, or community forums.
Workshop Diagnose a Permission Issue
Goal: Simulate and diagnose a common file permission problem preventing Navidrome from scanning music.
Steps:
- Identify Navidrome's UID/GID: Check your
~/navidrome/docker-compose.yml
for theuser: "UID:GID"
line. Remember these numbers (e.g.,1000:1000
). - Create a Test Music Directory: Create a new, temporary directory outside your main library to avoid modifying permissions on your actual music.
- Modify
docker-compose.yml
: Temporarily change the music volume mount to point to this new directory. Change the line:- /srv/music:/music:ro
to:- /home/yourusername/test_music:/music:ro
(Replaceyourusername
with your actual username) Save and close. - Recreate Navidrome:
- Trigger Scan: Log in to Navidrome Web UI, go to Settings -> Library -> Scan Library Now. Wait a moment. The dummy track should not appear (unless your default permissions are unusually open).
- Check Logs:
Look for permission denied errors related to accessing
/music
or/music/dummy_track.mp3
. You should see messages indicating it cannot read the directory or file. - Simulate Fixing Permissions: Change the ownership of the test directory to match Navidrome's UID/GID.
- Trigger Scan Again: In Navidrome UI, click "Scan Library Now" again.
- Verify: Check the Navidrome UI -> Home or Recently Added. The "dummy_track" (likely shown as "Unknown Artist" / "Unknown Album") should now appear. Check the logs again – the permission errors should be gone.
- Clean Up:
- Stop Navidrome:
docker-compose down
- Edit
~/navidrome/docker-compose.yml
and change the music volume mount back to your original music library path (e.g.,- /srv/music:/music:ro
). Save the file. - Remove the test directory:
rm -rf ~/test_music
- Start Navidrome again:
docker-compose up -d
- Stop Navidrome:
Outcome: You have simulated a realistic permission error, used logs to diagnose it, applied the correct permissions, and verified that Navidrome could then access the files. This highlights the importance of checking file system permissions when scans fail.
Conclusion
Congratulations! You have journeyed through the process of setting up your own personal music streaming server using Navidrome. Starting with the basics of Docker and Docker Compose, you deployed Navidrome, configured initial settings, and learned how to manage users. You then progressed to securing remote access with HTTPS using Nginx Proxy Manager, understanding crucial configuration variables, and delving into advanced topics like security hardening, backup strategies, scrobbling integrations, and systematic troubleshooting.
By self-hosting Navidrome, you've gained:
- Control: Full ownership of your music library and the platform serving it.
- Privacy: Freedom from corporate tracking of your listening habits.
- Customization: The ability to tailor the server to your specific needs.
- Cost Savings: Elimination of recurring streaming subscription fees.
- Knowledge: Valuable hands-on experience with Linux, Docker, networking, reverse proxies, and server management.
The world of self-hosting is vast and rewarding. Navidrome is often just one piece of a larger ecosystem of services you might choose to run. The skills you've developed here – working with Docker, configuring reverse proxies, managing backups, troubleshooting using logs – are transferable and form a solid foundation for exploring other self-hosted applications like media servers (Jellyfin, Plex), file sync (Nextcloud), home automation (Home Assistant), and much more.
Remember that maintaining a self-hosted service requires ongoing attention: keep your system and applications updated, monitor logs occasionally, and ensure your backup strategy is working reliably. The Navidrome documentation and community forums are excellent resources if you encounter issues or want to explore features not covered in depth here.
Enjoy the freedom and satisfaction of streaming your music, your way!