Skip to content
Author Nejat Hakan
eMail 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 or vim (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.

  1. Update Package Manager Cache: Ensures you have the latest list of available software packages.
    sudo apt update
    
  2. Install Prerequisite Packages: These packages allow apt to use repositories over HTTPS and manage repository keys.
    sudo apt install -y apt-transport-https ca-certificates curl software-properties-common gnupg lsb-release
    
  3. 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
    
  4. 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
    
  5. 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).
    sudo apt update
    sudo apt install -y docker-ce docker-ce-cli containerd.io
    
  6. 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.
    sudo docker run hello-world
    
    You should see output indicating Docker is working correctly.
  7. (Optional but Highly Recommended) Add Your User to the docker Group: By default, interacting with the Docker daemon requires root privileges (using sudo). Adding your user to the docker group grants permission to run Docker commands without sudo.
    sudo usermod -aG docker $USER
    
    IMPORTANT: You MUST log out and log back in for this group change to take effect. After logging back in, test by running docker run hello-world without sudo.
  8. 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
    
  9. Verify Docker Compose Installation: Check the version number.
    docker-compose --version
    
    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:

  1. Open your Linux terminal.
  2. Check Docker Version: Run docker --version. You should see the installed Docker version.
  3. Check Docker Compose Version: Run docker-compose --version. You should see the installed Docker Compose version.
  4. Run hello-world without sudo: If you added your user to the docker group and logged out/in, run:
    docker run hello-world
    
    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 for sudo, the group change hasn't taken effect or wasn't done correctly.
  5. List Docker Images: See what images are downloaded locally.
    docker images
    
    You should see the hello-world image listed.
  6. List Docker Containers: See currently running containers (there shouldn't be any persistent ones yet) and stopped containers.
    docker ps -a
    
    You should see the hello-world container listed with a status like Exited (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.

  1. 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 our docker-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.
  2. 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 the docker-compose command (likely your own user, if you added yourself to the docker group) has read permissions for this directory and all its contents. You might need to adjust permissions using chmod and chown if necessary. We will use /srv/music as an example path – replace this with your actual music library path.

  3. Create the docker-compose.yml file: Use a text editor (like nano, vim, or a graphical editor) to create the docker-compose.yml file inside the ~/navidrome directory.

    nano docker-compose.yml
    

  4. 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, but navidrome 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 using docker stop navidrome or docker-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 like uid=1000(yourusername) gid=1000(yourusername) groups=.... Use the uid and gid numbers shown. 1000:1000 is very common for the first user created on many Linux systems, but verify yours and update the docker-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 need sudo chown -R 1000:1000 ~/navidrome/data if you created it as root.
    • 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 via http://<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. Use timedatectl 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. Use debug or trace for troubleshooting.
      • ND_SESSIONTIMEOUT: How long a user login session remains active.
      • ND_ENABLETRANSCODINGCONFIG: We'll leave this false 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 the data subdirectory (relative to where docker-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., in nano, press Ctrl+X, then Y, then Enter).

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:

  1. Navigate to your chosen directory:
    cd ~/navidrome # Or wherever you decided to place it
    
  2. Verify your UID/GID:
    id $USER
    
    Note down the uid and gid numbers.
  3. Create the docker-compose.yml file: Use nano docker-compose.yml (or your preferred editor).
  4. Paste the YAML content provided in the section above.
  5. 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.
  6. Save and close the file.
  7. Validate the YAML syntax: Docker Compose can check the file for basic errors. Run this command in the same directory (~/navidrome):
    docker-compose config
    
    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 run docker-compose config again until it succeeds.
  8. 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 (replace YourUID: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 using chmod or chown, but be careful modifying system-wide permissions. Adding your user to a group that owns the music (e.g., audio or media) might be a better approach on some systems.

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.

  1. Navigate to the Directory: Make sure your terminal is in the directory containing the docker-compose.yml file (~/navidrome in our example).
    cd ~/navidrome
    
  2. Start Navidrome: Use the docker-compose up command. The -d flag runs the container in "detached" mode (in the background).

    docker-compose up -d
    

    • 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.
  3. Check Container Status: Verify that the container is running.

    docker-compose ps
    # Or use the standard Docker command:
    docker ps
    
    You should see the navidrome container listed with State as Up and Ports showing 0.0.0.0:4533->4533/tcp (or similar).

  4. View Logs (Optional but useful): Check the Navidrome logs to see startup messages or potential errors.

    docker-compose logs -f
    # Or: docker logs -f navidrome
    

    • -f follows the log output in real-time. Press Ctrl+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.
  5. 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 command ip addr show or hostname -I on the server.
    • If you are running Docker on the same machine you are browsing from, you can use http://localhost:4533 or http://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.
  6. 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!

  7. 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.

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:

  1. Open a terminal on your server and navigate to the ~/navidrome directory.
  2. Run the command to start Navidrome in the background:
    docker-compose up -d
    
  3. Verify the container is running:
    docker-compose ps
    
    Confirm the State is Up.
  4. Check the logs briefly:
    docker-compose logs
    
    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 the user: setting in docker-compose.yml and the directory permissions workshop.
  5. Find your server's IP address: Use ip addr show or hostname -I. Note the IP address (e.g., 192.168.1.100).
  6. (If applicable) Allow port 4533 through the firewall: If using ufw, run sudo ufw status to check if it's active. If active, run sudo ufw allow 4533/tcp.
  7. Open a web browser on another computer on the same network (or the same computer if applicable).
  8. Navigate to http://<your-server-ip>:4533, replacing <your-server-ip> with the address found in step 5.
  9. You should see the Navidrome setup screen. Enter a desired username and a strong password for your administrator account. Click "Create Admin User".
  10. Log in using the credentials you just created.
  11. 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.
  12. 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. Use debug for troubleshooting.
  • ND_SESSIONTIMEOUT: How long web UI and API sessions remain valid (e.g., 24h, 7d).
  • ND_ENABLETRANSCODINGCONFIG (Default: false): Set to true 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 like 192k. Requires ND_ENABLETRANSCODINGCONFIG to be true 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 like X-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:

  1. Edit docker-compose.yml: Open ~/navidrome/docker-compose.yml with your text editor.
  2. Modify Environment Variables: Add or change variables under the environment: section for the navidrome service. Ensure correct YAML indentation (usually two spaces under environment:).
  3. Save the file.
  4. Recreate the Container: Navigate to the ~/navidrome directory in your terminal and run:
    docker-compose up -d --force-recreate
    
    • up -d: Ensures the container starts in detached mode.
    • --force-recreate: Tells Docker Compose to stop and remove the existing navidrome 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:

  1. Navigate to the ~/navidrome directory.
  2. Edit the docker-compose.yml file (nano docker-compose.yml).
  3. Locate the environment: section.
  4. Change the ND_UIWELCOMEMESSAGE to something different, like "My Awesome Navidrome!".
  5. Add a new environment variable to change the number of search results shown per page (default is 50):
        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"
    
    Make sure indentation is correct (aligned with other ND_ variables).
  6. Save and close the file.
  7. Apply the changes:
    docker-compose up -d --force-recreate
    
    Wait for the command to complete.
  8. 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).
  9. 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.

  1. Log in as Administrator: Access the Navidrome Web UI (http://<your-server-ip>:4533) and log in with the admin account you created initially.
  2. Navigate to User Management: Click on your username in the top-right corner, then select "Users".
  3. 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.
  4. 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 to true in your docker-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.
  5. Save User: Click "Save" to create the new user account.
  6. 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:

  1. Log in to Navidrome using your administrator account.
  2. Go to Users: Click Username -> Users.
  3. 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".
  4. Log Out: Click your admin username -> Log Out.
  5. Log In as the New User: Use the username testuser and the password you set.
  6. 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.
  7. 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 of IP: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:

  1. Domain Name: You need a domain name (e.g., yourdomain.com) registered.
  2. 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.).
  3. 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:

  1. Create NPM Directories: Similar to Navidrome, create directories for NPM's configuration and data.
    mkdir ~/npm
    mkdir ~/npm/data
    mkdir ~/npm/letsencrypt
    cd ~/npm
    
  2. 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.
  3. Start NPM:

    docker-compose up -d
    

  4. Access NPM Admin UI: Open your browser to http://<your-server-ip>:81.
  5. Default Login: Log in with the default credentials:
    • Email: admin@example.com
    • Password: changeme
  6. Change Credentials: Immediately change the email address and password to secure ones.

Configuring NPM to Proxy Navidrome:

  1. Log in to NPM Admin UI (http://<your-server-ip>:81).
  2. Go to Hosts -> Proxy Hosts.
  3. Click "Add Proxy Host".
  4. 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 or 127.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).
  5. 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.
  6. 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.

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.

  1. Find NPM's Docker Network IP Range:
    • Find the network name used by NPM (usually npm_default if you ran docker-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 like 172.20.0.0/16.
  2. Edit Navidrome's docker-compose.yml: Add/modify the ND_REVERSEPROXYWHITELIST environment variable.
    # Inside ~/navidrome/docker-compose.yml
    # ... other settings ...
    environment:
      # ... other env vars ...
      ND_REVERSEPROXYWHITELIST: "172.20.0.0/16" # Replace with YOUR NPM network subnet
      # If accessing via a subpath like /navidrome, also add:
      # ND_BASEURL: "/navidrome"
    
  3. Recreate Navidrome Container:
    cd ~/navidrome
    docker-compose up -d --force-recreate
    

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:

  1. Install NPM: Follow steps 1-3 in the "Setting up Nginx Proxy Manager" section above (create directories, create docker-compose.yml, run docker-compose up -d).
  2. Access NPM Admin: Open http://<your-server-ip>:81.
  3. Initial Login & Secure: Log in with admin@example.com / changeme. Immediately change the details and password.
  4. 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
    • 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...
    • Click Save.
  5. 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.
  6. 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.
  7. Test Login: Log in to Navidrome via the HTTPS domain to ensure everything works.
  8. (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:

  1. 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.
  2. 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
  3. 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: Adjust bantime (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]). Ensure enabled = 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.
    • Restart Fail2ban: sudo systemctl restart fail2ban
    • Check Status: sudo fail2ban-client status and sudo fail2ban-client status <jail_name> (e.g., sudo fail2ban-client status sshd).
  4. 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:
      # 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
      
      Consider using specific version tags (e.g., deluan/navidrome:0.50.1) instead of :latest in your docker-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.
  5. 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).

Workshop Implement Basic Firewall Rules and Check Updates

Goal: Configure basic firewall rules using ufw and practice checking for and applying container updates.

Steps:

  1. Check ufw Status:
    sudo ufw status
    
    If inactive, proceed with setup. If active, review existing rules carefully before changing.
  2. Set Default Policy (If Inactive/Safe):
    sudo ufw default deny incoming
    sudo ufw default allow outgoing # Usually the default, allows server to reach out
    
  3. Allow Essential Ports:
    sudo ufw allow ssh # Or your custom SSH port number
    sudo ufw allow 80/tcp # For NPM/Let's Encrypt
    sudo ufw allow 443/tcp # For NPM/HTTPS
    sudo ufw allow 81/tcp # For NPM Admin UI (Consider restricting source IP later)
    
  4. Enable ufw:
    sudo ufw enable
    
    Confirm with 'y' if prompted. Your SSH session should remain active if you allowed the SSH port correctly.
  5. Verify Rules:
    sudo ufw status verbose
    
    Check that the rules match what you intended.
  6. Check for Navidrome Image Updates:
    cd ~/navidrome
    docker-compose pull navidrome
    
    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.
  7. Check for NPM Image Updates:
    cd ~/npm
    docker-compose pull app
    
    Checks for updates to the jc21/nginx-proxy-manager:latest image.
  8. Apply Updates (If any were downloaded):
    • If navidrome updated:
      cd ~/navidrome
      docker-compose up -d --force-recreate
      
    • If npm updated:
      cd ~/npm
      docker-compose up -d --force-recreate
      
  9. 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?

  1. 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.
  2. 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.
  3. (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.
  4. (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 the rsync command-line utility in a script to copy the data directories efficiently to a backup location. Can be automated using cron.
    • 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.

  1. 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.
    sudo mkdir -p /mnt/backups/navidrome
    # Ensure your user has write permissions or run the backup script as root/sudo
    sudo chown $USER:$USER /mnt/backups/navidrome
    
  2. Create a Backup Script: Create a file, e.g., ~/navidrome_backup.sh.
    nano ~/navidrome_backup.sh
    
  3. 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 of SOURCE_DIR into DEST_DIR. Without the trailing slash on the source, it would copy SOURCE_DIR itself into DEST_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.
  4. Make Script Executable:

    chmod +x ~/navidrome_backup.sh
    

  5. Run Manually: Test the script:
    ~/navidrome_backup.sh
    
    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.
  6. 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:
      # m h  dom mon dow   command
      0 3 * * * /home/yourusername/navidrome_backup.sh > /dev/null 2>&1
      
      • 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.
    • Save and close the crontab.

Restore Process:

  1. Stop Existing Containers (if any):
    cd ~/navidrome && docker-compose down
    cd ~/npm && docker-compose down # If restoring NPM too
    
  2. Clear Existing Data (Use with extreme caution!): Optionally, remove the potentially corrupted existing data directories before restoring:
    # 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
    
    Alternatively, rename the old directories (e.g., mv ~/navidrome/data ~/navidrome/data.old).
  3. Restore from Backup: Use rsync or cp 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/
    
  4. Verify Permissions: Ensure the restored ~/navidrome/data directory (and ~/npm/* directories if applicable) have the correct ownership and permissions for the user: specified in the docker-compose.yml files (e.g., sudo chown -R 1000:1000 ~/navidrome/data).
  5. Start Containers:
    cd ~/navidrome && docker-compose up -d
    cd ~/npm && docker-compose up -d # If restoring NPM
    
  6. 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:

  1. Create a temporary backup directory:
    mkdir ~/navidrome_manual_backup
    
  2. Stop Navidrome:
    cd ~/navidrome
    docker-compose down
    
  3. 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. Use ls -l ~/navidrome_manual_backup and ls -l ~/navidrome_manual_backup/data.
  4. 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. The data directory and docker-compose.yml should be missing.
  5. Restore from Backup:

    cp ~/navidrome_manual_backup/docker-compose.yml ~/navidrome/
    cp -a ~/navidrome_manual_backup/data ~/navidrome/
    

  6. 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 the user: "UID:GID" in your docker-compose.yml? If not (e.g., it shows root:root), fix it: sudo chown -R YourUID:YourGID ~/navidrome/data (replace YourUID:YourGID).
  7. Restart Navidrome:

    cd ~/navidrome
    docker-compose up -d
    

  8. 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.
  9. 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):

  1. Edit Navidrome's docker-compose.yml: nano ~/navidrome/docker-compose.yml
  2. 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:
            # --- 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.
      
      You can enable both services simultaneously.
  3. Save the file.

  4. Recreate Navidrome Container:
    cd ~/navidrome
    docker-compose up -d --force-recreate
    

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:

  1. Log in to Navidrome as the user who wants to enable scrobbling.
  2. Go to Settings -> Personal.
  3. Scroll down to the "Scrobbling Services" section.
  4. 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.
  5. 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:

Steps:

  1. Edit Navidrome's docker-compose.yml:
    nano ~/navidrome/docker-compose.yml
    
  2. Add Last.fm environment variables under environment:, replacing the placeholders with your actual API key and secret. Do NOT add ND_LASTFM_USER or ND_LASTFM_PASSWORD for this workshop (we want per-user setup).
          environment:
            # ... other variables ...
            # --- Last.fm Scrobbling ---
            ND_LASTFM_ENABLED: "true"
            ND_LASTFM_APIKEY: "YOUR_ACTUAL_API_KEY"
            ND_LASTFM_SECRET: "YOUR_ACTUAL_SHARED_SECRET"
    
  3. Save and close the file.
  4. Recreate the Navidrome container:
    cd ~/navidrome
    docker-compose up -d --force-recreate
    
  5. Log in to Navidrome with your regular (or admin) user account.
  6. Go to Personal Settings: Click Username -> Settings -> Personal.
  7. Connect to Last.fm: Scroll down to "Scrobbling Services" and click "Connect to Last.fm".
  8. 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).
  9. Verify Connection: After being redirected back to Navidrome, the Last.fm section in Settings -> Personal should now display your Last.fm username.
  10. Test Scrobbling: Play a track in Navidrome for at least half its duration or a few minutes.
  11. 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:

  1. Container Fails to Start:

    • Symptom: docker-compose ps shows the container State as Exited or Restarting.
    • Diagnosis: Check the container logs immediately after trying to start it:
      cd ~/navidrome # Or ~/npm if it's the proxy
      docker-compose logs
      # Or for a specific container:
      docker logs navidrome
      
      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" in docker-compose.yml matches the owner of the host directories (~/navidrome/data, /path/to/music). Use ls -ld ~/navidrome/data and ls -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.
      • Incorrect docker-compose.yml Syntax: Run docker-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.
  2. Web UI Not Accessible:

    • Symptom: Browser shows "This site can’t be reached" or "Connection refused" when trying to access http://<server-ip>:4533 or https://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 the PORTS 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.
  3. 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 in docker-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 in docker-compose.yml have read permissions for the music directory and all subdirectories and files on the host? This is a very common issue. Use ls -l on various subdirectories within your music folder to check. You might need to use sudo 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.
  4. 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 or docker 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 (if ND_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:

  1. Isolate the Problem: Is it affecting all users or just one? Web UI only or clients too? Specific tracks or all music?
  2. 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).
  3. Check Container Status: docker-compose ps. Are containers running?
  4. Check Configuration: Review docker-compose.yml, NPM settings, firewall rules, DNS.
  5. Check Permissions: File system permissions for data and music volumes are frequent culprits.
  6. Restart: Sometimes a simple container restart resolves temporary glitches: docker-compose restart navidrome.
  7. 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:

  1. Identify Navidrome's UID/GID: Check your ~/navidrome/docker-compose.yml for the user: "UID:GID" line. Remember these numbers (e.g., 1000:1000).
  2. Create a Test Music Directory: Create a new, temporary directory outside your main library to avoid modifying permissions on your actual music.
    mkdir ~/test_music
    # Create a dummy file inside (content doesn't matter)
    touch ~/test_music/dummy_track.mp3
    
  3. Modify docker-compose.yml: Temporarily change the music volume mount to point to this new directory.
    nano ~/navidrome/docker-compose.yml
    
    Change the line: - /srv/music:/music:ro to: - /home/yourusername/test_music:/music:ro (Replace yourusername with your actual username) Save and close.
  4. Recreate Navidrome:
    cd ~/navidrome
    docker-compose up -d --force-recreate
    
  5. 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).
  6. Check Logs:
    docker-compose logs navidrome
    
    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.
  7. Simulate Fixing Permissions: Change the ownership of the test directory to match Navidrome's UID/GID.
    # Use the UID:GID you found in step 1
    sudo chown -R 1000:1000 ~/test_music
    # Also ensure read permissions are set (though chown often suffices)
    sudo chmod -R u+r ~/test_music
    
  8. Trigger Scan Again: In Navidrome UI, click "Scan Library Now" again.
  9. 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.
  10. 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

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!