Installation mit Docker

Tunetorch kommt als Docker-Image. Datenbank, Cache und FFmpeg sind schon enthalten, du brauchst also nur Docker, am besten mit Docker Compose.

Schnellstart

Lege eine Datei docker-compose.yml an:

services:
  tunetorch:
    image: tunetorch/tunetorch:latest
    container_name: tunetorch
    restart: unless-stopped
    ports:
      - "5000:5000"
    volumes:
      # Datenverzeichnis. Bitte regelmäßig sichern.
      - ./tunetorch-daten:/app/data

      # Optional: vorhandener Musikordner zum Scannen (immer read-only).
      # - /pfad/zu/deiner/musik:/app/musik:ro

      # Optional: Sammlung für den einmaligen Start-Import.
      # - /pfad/zu/deiner/sammlung:/app/import:ro

    # Passend für den direkten Zugriff per HTTP, wie ihn dieser Schnellstart
    # beschreibt. Hinter einem TLS-Reverse-Proxy beide Zeilen wieder
    # entfernen (siehe unten).
    environment:
      TT_HTTPS: "False"         # kein TLS: Cookies ohne Secure-Flag
      TT_TRUSTED_PROXIES: "0"   # kein Proxy davor
      # TT_PUID: "1000"         # UID des Volume-Eigentümers
      # TT_PGID: "1000"         # GID des Volume-Eigentümers

Starten:

docker compose up -d

Die Weboberfläche erreichst du danach unter http://<server-adresse>:5000. Beim ersten Login meldest du dich mit admin / BITTE_ÄNDERE_MICH an. Tunetorch verlangt sofort ein neues Passwort (siehe Erste Schritte).

Die Volumes im Detail

Pfad im ContainerPflichtZweck
/app/datajaDatenbank, hochgeladene Audiodateien, Cover, Bilder, Logs, Anmelde-Schlüssel, Cache. Dieses Verzeichnis musst du sichern.
/app/musikneinEin bestehender Musikordner, den der Bibliothek-Scan einliest. Immer mit :ro einhängen. Tunetorch schreibt nie in deine Musikbibliothek.
/app/importneinEine bestehende Sammlung für den einmaligen Start-Import. Ebenfalls :ro. Nach dem Import kannst du die Zeile wieder entfernen.

/app/data kannst du als Bind-Mount (./tunetorch-daten:/app/data) oder als benanntes Volume (tunetorch_daten:/app/data) einhängen. Beim Bind-Mount solltest du TT_PUID/TT_PGID auf deinen Host-Benutzer setzen (id -u / id -g), damit du auch vom Host aus hineinschreiben kannst.

Beim Start übergibt der Container /app/data automatisch an die eingestellte UID:GID. Ein Ordner, den root angelegt hat, wird dadurch von selbst beschreibbar. Klappt das nicht (etwa wegen ACLs auf einer Synology), bricht der Start mit einer [entrypoint] FEHLER:-Meldung ab.

Nur Docker, ohne Compose

docker run -d \
  --name tunetorch \
  --restart unless-stopped \
  -p 5000:5000 \
  -v $(pwd)/tunetorch-daten:/app/data \
  tunetorch/tunetorch:latest

Ein bereitgestelltes Image laden

Hast du das Image als Archiv bekommen:

docker load -i tunetorch-<VERSION>.tar.gz

Im Archiv heißt das Image tunetorch:<VERSION>-<arch>, die Compose-Datei oben erwartet aber tunetorch/tunetorch:latest. Du musst es deshalb umbenennen. Sonst scheitert der Start mit „image not found", und der Grund dafür ist nicht zu sehen:

docker tag tunetorch:<VERSION>-amd64 tunetorch/tunetorch:latest

Aktualisieren

docker compose pull
docker compose up -d

Deine Daten in /app/data bleiben erhalten. Änderungen an der Datenbank spielt Tunetorch beim Start selbst ein, du musst nach einem Update nichts von Hand erledigen.

Vor größeren Updates lohnt sich ein Backup des Datenverzeichnisses. Siehe Sicherheit & Datensicherung.

Betrieb hinter einem TLS-Reverse-Proxy

Der Schnellstart oben ist für den direkten Zugriff per HTTP eingestellt. Dafür sind die beiden Zeilen TT_HTTPS: "False" und TT_TRUSTED_PROXIES: "0" da. Läuft Tunetorch hinter einem Reverse-Proxy mit TLS (Caddy, Traefik, Nginx Proxy Manager), entferne beide wieder. Die Standardwerte True und 1 sind für genau diesen Fall gedacht. Der Proxy muss dabei X-Forwarded-Proto: https weitergeben, daran erkennt Tunetorch die verschlüsselte Verbindung.

Der Grund liegt im Umgang der Browser mit Cookies: Mit TT_HTTPS: "True" bekommen die Anmelde-Cookies das Secure-Flag. Rufst du Tunetorch dann über http:// auf, verwirft der Browser sie ohne Meldung. Die Anmeldung scheint fehlzuschlagen, obwohl der Server sie angenommen hat. Im Server-Log steht dann eine Warnung, die genau das beschreibt.

Die Falle bei der Ersteinrichtung: Über http://localhost:5000 akzeptieren Chrome, Edge und Firefox Secure-Cookies trotzdem, weil localhost für sie als sicher gilt. Wer Tunetorch direkt auf dem Server einrichtet, merkt eine falsche Einstellung deshalb nicht. Erst der Zugriff von einem zweiten Gerät über die LAN-Adresse scheitert.

Wenn du die Wahl hast, nimm TLS. TT_HTTPS: "False" ist die Lösung fürs Heimnetz ohne Zertifikat, nicht die bessere Betriebsart.

Mehr dazu unter Konfiguration.

Synology DSM

Auf Synology-Systemen gehört ein freigegebener Ordner oft nicht 1000:1000, sondern zum Beispiel 1026:100. Prüfe die Werte auf dem Host mit ls -ln im Volume-Verzeichnis und trage sie ein:

    environment:
      TT_PUID: "1026"
      TT_PGID: "100"

Wenn eine ACL den automatischen Eigentümerwechsel überstimmt, gib dem Benutzer mit dieser UID in der File Station zusätzlich ausdrücklich Schreibrecht.

Zwei weitere Eigenheiten von DSM kosten beim ersten Start oft Zeit: Port 5000 gehört der DSM-Oberfläche (wähle einen anderen Host-Port), und ein freigegebener Ordner, den du als /app/import oder /app/musik einhängst, ist für den Container nicht automatisch lesbar. Dass du ihn selbst in der File Station öffnen kannst, heißt dabei nichts. Beides samt Prüfbefehl steht auf der Seite Synology NAS (DSM).

Speicher für DLNA-Casting (optional)

Nutzt du DLNA-Casting mit Lautheits-Angleichung oder einem Ziel-Format, legt der Server kurzlebige Kopien des laufenden Titels an. Wo, entscheidet er selbst: am liebsten im Arbeitsspeicher, sonst auf dem Datenträger. Du musst dafür also nichts einstellen.

Hat dein Server reichlich RAM, kannst du die Kopien gezielt in den Arbeitsspeicher legen und so der SD-Karte oder SSD Schreibvorgänge ersparen:

    shm_size: "1g"

Das ist eine Obergrenze, keine Reservierung. Solange der Platz nicht gebraucht wird, kostet er nichts. Auf einem Raspberry Pi ist RAM allerdings knapper als Schreibzyklen, dort ist die Voreinstellung meist die bessere Wahl.

CD-Laufwerk durchreichen (optional)

Für das CD-Rippen braucht der Container Zugriff auf ein CD-Laufwerk am Server, eingebaut oder per USB. Die nötigen Programme sind schon im Image, es fehlen nur diese Zeilen:

    volumes:
      - /dev:/dev
    device_cgroup_rules:
      - "b 11:* rmw"
    group_add:
      - "24"

Danach schaltest du das CD-Rippen in den Server-Einstellungen ein. Meldet die Oberfläche „Kein Zugriff auf das Laufwerk", stimmt fast immer die Zahl bei group_add nicht.

Auf einer Synology NAS helfen diese Zeilen in der Regel nicht: DSM bringt den Treiber für CD-Laufwerke nicht mit, und Tunetorch sieht deshalb kein Laufwerk. Wie du das prüfst und was du stattdessen tun kannst, steht unter Synology NAS (DSM).

Nutzt du zusätzlich DLNA-Casting? Mit /dev:/dev sieht der Container den Arbeitsspeicher-Ordner des Hosts, und shm_size (siehe oben) wirkt nicht mehr. Die Casting-Kopien landen dann im RAM. Auf einem Raspberry Pi hältst du sie mit dieser Zeile unter environment: auf dem Datenträger:

      TT_DLNA_TMPFS: "/app/data/temp/dlna"

Raspberry Pi: Achte auf die Stromversorgung. Ein USB-Laufwerk braucht beim Anlaufen der CD kurz mehr Strom, als die USB-Buchsen des Pi liefern. Das zeigt sich nicht als klare Fehlermeldung, sondern als Lesefehler oder als Laufwerk, das mitten im Rip verschwindet. Abhilfe schafft ein Laufwerk mit eigenem Netzteil oder ein aktiver USB-Hub, also einer mit eigenem Netzteil. Ein Y-Kabel an zwei Buchsen des Pi hilft nicht. Auch ein passiver Verteiler, an den du zusätzlich ein Handy-Netzteil steckst, ist keine Lösung: Darin sind die Stromleitungen verbunden, und das Netzteil speist dann auch in den Pi zurück.

Startet dein Pi von einer USB-SSD, gilt das doppelt. SSD und Laufwerk teilen sich dann den Strom der USB-Buchsen. Bricht die Spannung beim Anlaufen der CD ein, kann der Pi kurz seine SSD verlieren und hängen bleiben: Er antwortet noch auf Ping, aber nicht mehr auf SSH oder die Oberfläche. Häng in diesem Fall nur das Laufwerk an den Hub und die SSD weiter direkt an den Pi. Am Hub wäre er eine zusätzliche Stelle, an der dir das Startmedium wegbrechen kann.

Ob die Versorgung reicht, prüfst du nach einem Rip auf dem Pi mit vcgencmd get_throttled. throttled=0x0 heißt: Die Spannung ist seit dem Start nie eingebrochen.

Gesundheitsprüfung

Das Image bringt einen HEALTHCHECK mit, der alle 30 Sekunden prüft, ob der Server antwortet. docker ps zeigt den Container dadurch als healthy oder unhealthy. So erkennst du auch einen hängenden Server, den restart: unless-stopped allein nicht bemerken würde.

Der Start dauert je nach Hardware bis zu einer Minute (auf einem NAS waren es 44 Sekunden), weil Redis, Datenbankprüfung und Server nacheinander hochfahren. In dieser Zeit gilt der Container noch nicht als healthy, und ein „Bad Gateway“ vom Reverse-Proxy ist normal. Es verschwindet von selbst. Bleibt es, liegt die Ursache woanders, siehe Fehlerbehebung.

docker ps
docker compose logs -f tunetorch

Nächster Schritt

Zurück zur Dokumentations-Übersicht