====== Navidrome Musik-Streaming auf Ubuntu Server ======
{{:ubuntu:navidrome-logo.png|}}
===== Navidrome Server Software =====
> https://www.navidrome.org/
> https://www.navidrome.org/docs/installation/linux/
> https://github.com/navidrome/navidrome/releases
===== Installation =====
==== Volumes und Partitionierung ====
Um alles unterzubekommen, sollte man sich bereits bei der Installation des Servers Gedanken dazu machen, wie das Partitions- bzw. Festplattenlayout aussehen soll.
Folgende Fragen sind zu berücksichtigen:
* Wo soll die music library liegen? Soll es mehrere geben?
* Wo soll das Arbeitsverzeichnis von Navidrome gespeichert werden? --> Datenbank
* Wohin mit dem Cache der Applikation? --> Transcoding, Bilddaten (cover arts, album arts)
{{:ubuntu:volume_layout_navidrome.png|}}
/dev/sda1 EFI /boot/efi ext4
/dev/sda2 /boot ext4
/dev/sda3 LVM PV
└─ vg0
├─ lv-swap swap
├─ lv-root /
├─ lv-home /home
├─ lv-var /var
└─ lv-srv /srv
===== Installation der Anwendung =====
==== Service-User anlegen ====
useradd -r -s /usr/sbin/nologin navidrome
==== Anwendung installieren ====
**apt** nutzen, um Abhängigkeiten aufzulösen!
apt install ./navidrome_0.61.2_linux_amd64.deb
==== Logrotate ====
/var/log/navidrome.log
{
rotate 14
daily
missingok
notifempty
delaycompress
compress
create 640 navidrome navidrome
postrotate
if service navidrome status > /dev/null 2>&1; then \
touch /var/log/navidrome.log; \
chown navidrome:navidrome /var/log/navidrome.log; \
service navidrome restart > /dev/null 2>&1; \
fi;
endscript
sharedscripts
}
==== Daten wiederherstellen (bei Migration) ====
rm -rf /var/lib/navidrome
tar -xzvf /tmp/navidrome-backup.tar.gz -C /
chown -R navidrome:navidrome /var/lib/navidrome
==== Config erstellen oder übernehmen ====
> https://www.navidrome.org/docs/usage/configuration/options/
mv navidrome.toml /etc/navidrome/navidrome.toml
chown -R navidrome:navidrome /etc/navidrome/navidrome.toml
==== Verzeichnisse übernehmen / anlegen ====
cat /etc/navidrome/navidrome.toml |grep '\"/'
mkdir -p /srv/LOSSLESS_AUDIO
mkdir -p /srv/LOSSY_AUDIO
mkdir -p /srv/PLAYLISTS_NAVIDROME
mkdir -p /srv/BACKUP_NAVIDROME
chown -R navidrome:navidrome /srv/BACKUP_NAVIDROME
chown -R navidrome:navidrome /srv/PLAYLISTS_NAVIDROME
==== Spezialfall music library ====
Um die Bibliothek automatisiert auf dem Laufenden halten zu können, lege ich einen weiteren Service-User an und vergebe entsprechende Berechtigungen:
* navidrome --> lesen
* audioadmin --> lesen+schreiben
=== Gruppen erstellen und berechtigen ===
adduser audioadmin
groupadd losslessaudio
usermod -aG losslessaudio audioadmin
usermod -aG losslessaudio navidrome
chown -R audioadmin:losslessaudio /srv/LOSSLESS_AUDIO
chmod -R 750 /srv/LOSSLESS_AUDIO
chmod g+s /srv/LOSSLESS_AUDIO
=== Default Berechtigungen setzen ===
apt install acl
setfacl -d -m u::rwX,g::rX,o::--- /srv/LOSSLESS_AUDIO
==== Service-User der Anwendung zuweisen ====
vi /etc/systemd/system/navidrome.service
[Unit]
Description=Navidrome Music Server and Streamer compatible with Subsonic/Airsonic
After=remote-fs.target network.target
AssertPathExists=/var/lib/navidrome
[Install]
WantedBy=multi-user.target
[Service]
User=
Group=
Type=simple
ExecStart=/opt/navidrome/navidrome --configfile "/etc/navidrome/navidrome.toml"
WorkingDirectory=/var/lib/navidrome
TimeoutStopSec=20
KillMode=process
Restart=on-failure
# See https://www.freedesktop.org/software/systemd/man/systemd.exec.html
DevicePolicy=closed
NoNewPrivileges=yes
PrivateTmp=yes
PrivateUsers=yes
ProtectControlGroups=yes
ProtectKernelModules=yes
ProtectKernelTunables=yes
RestrictAddressFamilies=AF_UNIX AF_INET AF_INET6
RestrictNamespaces=yes
RestrictRealtime=yes
SystemCallFilter=~@clock @debug @module @mount @obsolete @reboot @setuid @swap
ReadWritePaths=/var/lib/navidrome
# You can uncomment the following line if you're not using the jukebox This
# will prevent navidrome from accessing any real (physical) devices
#PrivateDevices=yes
# You can change the following line to `strict` instead of `full` if you don't
# want navidrome to be able to write anything on your filesystem outside of
# /var/lib/navidrome.
ProtectSystem=full
# You can uncomment the following line if you don't have any media in /home/*.
# This will prevent navidrome from ever reading/writing anything there.
#ProtectHome=true
# You can customize some Navidrome config options by setting environment variables here. Ex:
#Environment=ND_BASEURL="/navidrome"
systemctl daemon-reload
systemctl start navidrome.service
systemctl status navidrome.service
systemctl cat navidrome|grep -i user
User=navidrome
WantedBy=multi-user.target
===== Aktualisierung / Update der Server-Applikation =====
Welche Version läuft?
navidrome --version
Ist das Backup gelaufen?
Den Link zur aktuellen Version holen und das Release laden:
> https://github.com/navidrome/navidrome/releases
wget -c https://github.com/navidrome/navidrome/releases/download/v0.60.0/navidrome_0.60.0_linux_amd64.deb
systemctl stop navidrome
dpkg -i navidrome_0.60.0_linux_amd64.deb
(Reading database ... 153778 files and directories currently installed.)
Preparing to unpack navidrome_0.60.0_linux_amd64.deb ...
Unpacking navidrome (0.60.0) over (0.59.0) ...
Setting up navidrome (0.60.0) ...
apt -f install
Gibt es Neuerungen, die Änderungen an der Konfiguration mit sich ziehen?
vi /etc/navidrome/navidrome.toml
Server wieder starten:
systemctl start navidrome
systemctl status navidrome
● navidrome.service - Your Personal Streaming Service
Loaded: loaded (/etc/systemd/system/navidrome.service; enabled; preset: enabled)
Active: active (running) since Fri 2026-02-06 20:28:44 CET; 6s ago
Main PID: 5985 (navidrome)
Tasks: 14 (limit: 19083)
Memory: 159.4M (peak: 293.1M)
CPU: 1.723s
CGroup: /system.slice/navidrome.service
└─5985 /usr/bin/navidrome service execute -c /etc/navidrome/navidrome.toml
Feb 06 20:28:44 server systemd[1]: Started navidrome.service - Your Personal Streaming Service.
Feb 06 20:28:44 server navidrome[5985]: _ _ _ _
Feb 06 20:28:44 server navidrome[5985]: | \ | | (_) | |
Feb 06 20:28:44 server navidrome[5985]: | \| | __ ___ ___ __| |_ __ ___ _ __ ___ ___
Feb 06 20:28:44 server navidrome[5985]: | . ` |/ _` \ \ / / |/ _` | '__/ _ \| '_ ` _ \ / _ \
Feb 06 20:28:44 server navidrome[5985]: | |\ | (_| |\ V /| | (_| | | | (_) | | | | | | __/
Feb 06 20:28:44 server navidrome[5985]: \_| \_/\__,_| \_/ |_|\__,_|_| \___/|_| |_| |_|\___|
Feb 06 20:28:44 server navidrome[5985]: Version: 0.60.0 (0c8f2a55
===== Apache2 als Reverse-Proxy =====
==== Installation der Pakete ====
apt update
apt install apache2 libapache2-mod-security2
Module im Apache aktivieren:
a2enmod proxy proxy_http proxy_wstunnel headers rewrite ssl
Dual Stack aktivieren --> ''/etc/apache2/ports.conf''.
Listen 80
Listen [::]:80
Listen 443
Listen [::]:443
Apache-Version nicht bekannt geben --> ''/etc/apache2/conf-enabled/security.conf''
# ServerTokens
# This directive configures what you return as the Server HTTP response
# Header. The default is 'Full' which sends information about the OS-Type
# and compiled in modules.
# Set to one of: Full | OS | Minimal | Minor | Major | Prod
# where Full conveys the most information, and Prod the least.
#ServerTokens Minimal
ServerTokens Prod
#ServerTokens Full
===== ModSecurity-Konfiguration für Apache2 Reverse Proxy vor Navidrome =====
==== Ziel der Konfiguration ====
* Schutz vor typischen Webangriffen (SQLi, XSS, RCE etc.)
* Keine unnötigen False Positives für Navidrome
* API-/Streaming-kompatibel
* Sinnvolles Logging
==== 1. Basis: ModSecurity aktivieren ====
a2enmod security2
systemctl restart apache2
Einbindung in Apache unter ''vi /etc/apache2/mods-enabled/security2.conf''
# Default Debian dir for modsecurity's persistent data
SecDataDir /var/cache/modsecurity
# Include all the *.conf files in /etc/modsecurity.
# Keeping your local configuration in that directory
# will allow for an easy upgrade of THIS file and
# make your life easier
IncludeOptional /etc/modsecurity/modsecurity.conf
#IncludeOptional /etc/modsecurity/other-rules.conf
IncludeOptional /etc/modsecurity/crs/crs-setup.conf
IncludeOptional /etc/modsecurity/crs/rules/*.conf
# Include OWASP ModSecurity CRS rules if installed
# IncludeOptional /usr/share/modsecurity-crs/*.load
# Defense against CVE-2021-44228
SecRuleUpdateTargetById 932130 "REQUEST_HEADERS:User-Agent"
SecRuleUpdateTargetById 932130 "REQUEST_HEADERS:Referer"
==== 2. Hauptkonfiguration ====
Datei:
/etc/modsecurity/modsecurity.conf
Wichtige Anpassungen:
SecRuleEngine On
# Body handling (wichtig für API!)
SecRequestBodyAccess On
SecResponseBodyAccess Off
# Limits (Navidrome kann größere Requests haben, z.B. Uploads)
SecRequestBodyLimit 104857600
SecRequestBodyNoFilesLimit 1048576
# JSON Support (sehr wichtig für Navidrome API)
SecRequestBodyProcessor JSON
# Logging
SecAuditEngine RelevantOnly
SecAuditLog /var/log/apache2/modsec_audit.log
SecAuditLogParts ABIJDEFHZ
# Weniger aggressiv bei Streaming
SecResponseBodyMimeType text/plain text/html text/xml application/json
# Encoding
SecDefaultAction "phase:2,log,auditlog,deny,status:403"
==== 3. OWASP Core Rule Set (empfohlen) ====
Installieren:
apt install modsecurity-crs
Dann aktivieren:
cp /usr/share/modsecurity-crs/crs-setup.conf.example /etc/modsecurity/crs-setup.conf
Apache Config ergänzen (z. B. in /etc/apache2/mods-enabled/security2.conf):
IncludeOptional /etc/modsecurity/crs-setup.conf
IncludeOptional /usr/share/modsecurity-crs/rules/*.conf
==== 3a. Option: Core Ruleset von Github (aktueller) ====
Benötigte Version klonen. In der Kombi Apache2 + Modsec2 unter Ubuntu 24.04 ist die v3.3.5 am sinnvollsten.
git clone https://github.com/coreruleset/coreruleset.git owasp-crs
cd owasp-crs
git fetch --tags
git checkout -b v3.3.5 tags/v3.3.5
cp crs-setup.conf.example crs-setup.conf
vi crs-setup.conf
Nun kann die ''crs-setup.conf'' auf die eigenen Bedürfnisse angepasst werden. Ich ändere am Default allerdings nichts.
Wichtiger ist es, das Ruleset auch korrekt einzubinden.
vi /etc/apache2/mods-enabled/security2.conf
vi /etc/modsecurity/modsecurity.conf
==== 4. WICHTIG: Ausnahmen für Navidrome ====
Navidrome nutzt:
* /rest/* API
* JSON Requests
* Query-Parameter intensiv
* Streaming (Range Requests)
Ohne Anpassung gibt es False Positives.
==== 5. Custom Rules für Navidrome ====
Neue Datei:
/etc/modsecurity/navidrome-exclusions.conf
# Navidrome API weniger restriktiv behandeln
SecRule REQUEST_URI "@beginsWith /rest/" \
"id:1000001,phase:1,pass,nolog,ctl:ruleEngine=DetectionOnly"
# JSON API toleranter machen
SecRule REQUEST_HEADERS:Content-Type "application/json" \
"id:1000002,phase:1,pass,nolog,ctl:requestBodyProcessor=JSON"
# Range Requests erlauben (für Streaming)
SecRule REQUEST_HEADERS:Range ".*" \
"id:1000003,phase:1,pass,nolog,ctl:ruleRemoveByTag=attack-protocol"
# False positives reduzieren (SQLi / XSS bei API)
SecRule REQUEST_URI "@beginsWith /rest/" \
"id:1000004,phase:1,pass,nolog,ctl:ruleRemoveByTag=attack-sqli,ctl:ruleRemoveByTag=attack-xss"
# Große Downloads erlauben
SecRule REQUEST_URI "@beginsWith /rest/stream" \
"id:1000005,phase:1,pass,nolog,ctl:responseBodyAccess=Off"
oder
# =========================================================
# Navidrome CRS Minimal Exclusions - Optimiert 2026
# =========================================================
# (1) SQL Injection False Positives
SecRule REQUEST_URI "@beginsWith /rest/" \
"id:1100001,phase:1,pass,nolog,\
ctl:ruleRemoveById=942100,\
ctl:ruleRemoveById=942110,\
ctl:ruleRemoveById=942150"
# (2) XSS False Positives
SecRule REQUEST_URI "@beginsWith /rest/" \
"id:1100002,phase:1,pass,nolog,\
ctl:ruleRemoveById=941100,\
ctl:ruleRemoveById=941160"
# (3) Protocol Enforcement
SecRule REQUEST_URI "@beginsWith /rest/" \
"id:1100003,phase:1,pass,nolog,\
ctl:ruleRemoveById=920230,\
ctl:ruleRemoveById=920240"
# (4) Streaming (Range Requests)
SecRule REQUEST_URI "@beginsWith /rest/stream" \
"id:1100004,phase:1,pass,nolog,\
ctl:ruleRemoveById=920200"
# (5) Typische Parameter entschärfen
SecRule REQUEST_URI "@beginsWith /rest/" \
"id:1100005,phase:1,pass,nolog,chain"
SecRule ARGS_NAMES "^(u|t|s|f|c)$" \
"ctl:ruleRemoveById=942100"
# (6) JSON Requests korrekt parsen
SecRule REQUEST_HEADERS:Content-Type "application/json" \
"id:1100006,phase:1,pass,nolog,\
ctl:requestBodyProcessor=JSON"
# (7) CoverArt / Artist Images
SecRule REQUEST_URI "@beginsWith /rest/getCoverArt" \
"id:1100010,phase:1,pass,nolog,ctl:responseBodyAccess=Off"
SecRule REQUEST_URI "@beginsWith /rest/getCoverArt" \
"id:1100011,phase:3,pass,nolog,ctl:responseBodyAccess=Off"
SecRule REQUEST_URI "@beginsWith /rest/getCoverArt" \
"id:1100012,phase:1,pass,nolog,\
ctl:ruleRemoveById=941100,\
ctl:ruleRemoveById=920200,\
ctl:ruleRemoveById=920420,\
ctl:ruleRemoveById=920430,\
ctl:ruleRemoveById=933100"
# (8) Artist API POST/DELETE WebUI
SecRule REQUEST_URI "@beginsWith /api/artist" \
"id:1100013,phase:1,pass,nolog,chain"
SecRule REQUEST_METHOD "@rx ^(POST|DELETE)$" \
"ctl:ruleRemoveById=941100"
# (9) Anomaly Scoring feinjustieren (Warnung vermeiden)
SecAction "id:1100014,phase:1,pass,nolog,t:none,\
setvar:tx.inbound_anomaly_score_threshold=10,\
setvar:tx.outbound_anomaly_score_threshold=5,\
tag:'navidrome-exclusions'"
Einbinden:
Include /etc/modsecurity/navidrome-exclusions.conf
==== 6. Apache VirtualHost (Reverse Proxy) ====
Beispiel:
ServerName music.example.de
ServerAlias music.example.net
DocumentRoot /var/www/navidrome/html
ErrorLog /var/www/navidrome/logs/error.log
CustomLog /var/www/navidrome/logs/access.log combined
ProxyPreserveHost On
Protocols http/1.1
#ProxyPass "/.well-known/" "!"
# WebSocket-Unterstützung
RewriteEngine On
RewriteCond %{HTTP:Upgrade} =websocket [NC]
RewriteRule /(.*) ws://127.0.0.1:4533/$1 [P,L]
# Alles andere Proxy
ProxyPass / http://127.0.0.1:4533/ nocanon
ProxyPassReverse / http://127.0.0.1:4533/
RequestHeader set X-Forwarded-Proto "https"
RequestHeader set X-Forwarded-Port "443"
RequestHeader set X-Forwarded-For "%{REMOTE_ADDR}s"
Header always set X-XSS-Protection "1; mode=block"
KeepAlive On
MaxKeepAliveRequests 100
KeepAliveTimeout 5
ProxyTimeout 300
Include /etc/letsencrypt/options-ssl-apache.conf
Include /etc/modsecurity/navidrome-exclusions.conf
SSLCertificateFile /etc/letsencrypt/live/music.example.de/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/music.example.de/privkey.pem
Header always set Strict-Transport-Security "max-age=31536000"
==== 7. Test & Debug ====
Logs prüfen:
tail -f /var/log/apache2/modsec_audit.log
Typische Probleme:
* 403 bei API Calls → Rule greift zu aggressiv
* Streaming bricht → Range Requests blockiert
* Login geht nicht → JSON / POST blockiert
==== 8. Empfohlene Betriebsmodi ====
^ Phase ^ Einstellung ^
| Test | DetectionOnly |
| Produktion | On + gezielte Exclusions |