Sicherheit & Datensicherung
Selbst hosten heißt: Die Verantwortung für die Daten liegt bei dir. Tunetorch macht dir das so einfach wie möglich — es gibt genau ein Verzeichnis, das gesichert werden muss.
Was gesichert werden muss
/app/data. Das ist alles.
/app/data/
├── db/ die Datenbank: Titel, Alben, Interpreten, Konten, Playlists, Statistiken
├── backups/ Sicherungskopien der Datenbank (s. unten)
├── audio/ hochgeladene Originaldateien + Metadaten-Sicherung
├── cover/ Cover in vier Größen
├── interpret_hero/ Künstlerbilder
├── person_hero/ Personenfotos
├── jwt/ Signaturschlüssel der Anmeldung
├── lizenz/ Zustand der Pro-Lizenz
├── redis/ persistente Sperren
└── logs/ Server-Logs
Nicht gesichert werden müssen audio_cache/ (konvertierte Fassungen, jederzeit neu
berechenbar), temp/ und upload_temp/.
Läuft deine Sammlung als eingehängter Ordner (/app/musik), sicherst du diesen wie gewohnt
separat — Tunetorch schreibt dort nie hinein.
Ein Backup anlegen
Die einfachste Variante bei einem Bind-Mount:
docker compose stop tunetorch
tar czf tunetorch-backup-$(date +%F).tar.gz ./tunetorch-daten
docker compose start tunetorch
Für ein Backup im laufenden Betrieb — etwa mit Borg, restic oder rsync — gilt: Die Datenbank arbeitet im WAL-Modus und ist dadurch robust, ein Snapshot mitten in einem Schreibvorgang kann aber unvollständig sein. Am unkritischsten läuft ein Backup nachts, nach den Wartungs-Tasks.
Der nächtliche Task „Datenbank komprimieren“ hilft dem Backup: Er gibt belegten, aber ungenutzten Platz frei und hält den Unterschied zwischen zwei Sicherungen klein.
Wiederherstellen
Verzeichnis zurückspielen, Container starten. Tunetorch erkennt den Datenbank-Stand und zieht Schema-Änderungen selbstständig nach.
Der JWT-Schlüssel gehört mit ins Backup. Fehlt
jwt/, wird beim Start ein neuer erzeugt — und damit werden alle bestehenden Anmeldungen ungültig. Das ist kein Datenverlust, aber alle müssen sich neu anmelden.
Vor jedem Schema-Update sichert Tunetorch selbst
Bringt ein Update eine Änderung am Datenbank-Schema mit, legt Tunetorch vor der Umstellung
eine Kopie der Datenbank unter /app/data/backups/ ab. Bei einem gewöhnlichen Neustart
passiert nichts — nur wenn tatsächlich etwas umgestellt wird.
docker exec -it tunetorch tt db-sicherungen
Name Art Schema Größe
auto-schema23-20260819-1930.db auto 23 11.4 MB
manuell-schema22-20260810-1200.db manuell 22 11.2 MB
auto entsteht vor einer Umstellung und zeigt den Stand davor; die jüngsten zwei bleiben
erhalten. manuell legst du selbst an — mit tt db-sichern — und Tunetorch entfernt diese
Kopien nie.
Zurückspielen, wenn nach einem Update etwas nicht stimmt:
docker exec -u root -it tunetorch tt db-einspielen auto-schema23-20260819-1930.db
Der Befehl sichert zuerst den jetzigen Stand, hält den Server an, spielt die Kopie zurück und
startet ihn wieder. Danach gehört zum Zurückspielen noch das alte Image — sonst stellt der
neue Server beim Start dieselbe Änderung erneut um. In der docker-compose.yml also die
vorherige Version eintragen, statt latest zu verwenden.
Die älteren Tags liegen dafür auf Docker Hub bereit: Ein abgelöster Stand bleibt dort
mindestens ein halbes Jahr erreichbar, und zu jedem Datenbank-Schema bleibt dauerhaft eine
Version. Wer einen bestimmten Stand darüber hinaus vorhalten will, legt sich selbst eine
Kopie an — docker save tunetorch/tunetorch:0.1.0 | gzip > tunetorch-0.1.0.tar.gz, und
zurück mit docker load < tunetorch-0.1.0.tar.gz.
Warum
-u root: Nur damit darf der Befehl den laufenden Server anhalten. Ohne ihn bricht er ab und sagt es.
Drei Dinge, die diese Kopien nicht sind:
- Kein Ersatz für dein Backup. Sie liegen im selben Verzeichnis wie die Datenbank — geht der Datenträger verloren, sind sie mit weg. Sie enthalten außerdem nur die Datenbank, keine Audiodateien und keine Cover.
- Nicht automatisch aktuell. Zwischen zwei Updates entsteht keine neue Kopie. Wer einen
Stand von heute Mittag will, legt ihn mit
tt db-sichernselbst an. - Kein automatisches Zurückrollen. Läuft eine Umstellung schief, bleibt der Server stehen und rührt nichts an. Was zurückgespielt wird, entscheidest du.
Metadaten-Sicherung
Neben jeder hochgeladenen Originaldatei legt Tunetorch eine kleine Textdatei mit den zugehörigen Metadaten ab. Sie wird im laufenden Betrieb nie gelesen — sie ist eine reine Rückversicherung für den Fall, dass die Datenbank verloren geht, die Audiodateien aber noch da sind.
Anmeldung
Tunetorch nutzt HttpOnly-Cookies, keine Token im Browser-Speicher. Ein Skript auf der Seite kommt damit nicht an die Anmeldedaten heran.
| Cookie | Standard-Laufzeit | Zweck |
|---|---|---|
| Access | 15 Minuten | Alle normalen Anfragen inklusive Audio-Streams und Cover. |
| Refresh | 7 Tage | Erneuert den Access-Token im Hintergrund. |
Beide Laufzeiten sind in den Server-Einstellungen anpassbar (Access maximal 1 Tag, Refresh maximal 90 Tage — die Obergrenzen verhindern, dass ein versehentlich hoher Wert die Gültigkeit kompromittierter Anmeldungen unbegrenzt verlängert).
Beim Abmelden werden beide Token serverseitig gesperrt; sie sind sofort wertlos, auch wenn jemand sie abgegriffen hätte. Die Sperrliste liegt persistent auf der Platte und übersteht einen Neustart. In der Android-App übernimmt das das Entfernen einer Server-Verbindung: Sie meldet die Sitzung erst beim Server ab und löscht danach die lokalen Daten — sonst blieben die Token bis zum Ablauf des Refresh-Tokens gültig, obwohl auf dem Gerät nichts mehr davon zu sehen ist.
Über den Schalter Angemeldet bleiben entscheidest du beim Login, ob die Cookies das Schließen des Browsers überleben.
Brute-Force-Schutz
Fehlgeschlagene Anmeldeversuche werden pro IP-Adresse gezählt. Wird das Limit im eingestellten Zeitfenster überschritten, sperrt Tunetorch die Adresse für eine festgelegte Dauer.
| Einstellung | Standard |
|---|---|
| Zeitfenster | 10 Minuten |
| Fehlversuche bis zur Sperre | 10 |
| Sperrdauer | 60 Minuten |
Zusätzlich braucht ein falscher Benutzername genauso lange wie ein falsches Passwort — an der Antwortzeit lässt sich also nicht ablesen, ob ein Konto existiert.
Dafür muss
TT_TRUSTED_PROXIESstimmen. Hinter einem Reverse-Proxy sähe der Server sonst nur dessen IP und würde bei einer Sperre alle Nutzer aussperren. Ein zu hoher Wert macht die Client-IP umgekehrt fälschbar. Siehe Konfiguration.
Härtung im Browser
- Strikte Content-Security-Policy: keine externen Hosts. Schriften und die Diagramm-Bibliothek sind lokal gebündelt, es gibt kein CDN.
X-Frame-Options: DENY— die Oberfläche lässt sich nicht in einen fremden Rahmen einbetten (Clickjacking-Schutz).Referrer-Policy: no-referrer,X-Content-Type-Options: nosniff, HSTS bei aktiviertem HTTPS.- CORS ist standardmäßig aus — Oberfläche und API kommen von derselben Adresse.
- Kein Suchmaschinen-Eintrag: Der Server liefert eine
robots.txt, die alles sperrt, und setzt auf jede AntwortX-Robots-Tag: noindex, nofollow. Deine Bibliothek taucht damit nicht in Suchergebnissen auf — auch keine einzelnen Cover oder Titel. Das gilt automatisch und lässt sich nicht versehentlich abschalten.
Externe Bild-Vorschauen aus der Internet-Bildsuche laufen bewusst über den Server, nicht direkt aus dem Browser — dadurch bleibt die strikte Policy erhalten und dein Browser kontaktiert keine fremden Hosts.
Zugriff aus dem Internet
Willst du von unterwegs hören, brauchst du einen Reverse-Proxy mit gültigem TLS-Zertifikat. Ohne HTTPS:
- verwirft der Browser die sicheren Anmelde-Cookies (die Anmeldung scheint zu scheitern),
- lässt sich die PWA nicht installieren,
- laufen deine Musik und dein Passwort unverschlüsselt über die Leitung.
Ein Beispiel für Caddy und Nginx steht unter Konfiguration.
Alternativen zum offenen Port: ein VPN ins Heimnetz (WireGuard, Tailscale) oder ein Tunnel. Beides umgeht die Portfreigabe komplett.
Datenschutz
- Keine Telemetrie, kein Tracking, keine Werbung. Der Server meldet nichts nach außen.
- Nach draußen gehen nur drei Dinge, alle optional und alle von dir ausgelöst: die Internet-Bildsuche, die MusicBrainz-Anreicherung und die Lizenzprüfung. Letztere überträgt nur die Installations-Kennung; deine Musik oder Nutzungsdaten verlassen den Server nie. Alle drei setzen Pro voraus — eine Free-Installation baut überhaupt keine Verbindung nach draußen auf.
- Persönliche Auswertungen sind an das Konto gebunden und für andere nicht einsehbar. Private Notizen sind auch für den Admin unsichtbar.
- Der Beliebtheitszähler der Titel ist bewusst kontenlos und damit anonym.