Security & backup

Self-hosting means your data lives with you, and so does the responsibility for it. Tunetorch makes that as easy as possible for you. There's exactly one directory you need to back up, and the server sends nothing to the outside on its own.

Privacy

Tunetorch collects no telemetry. The server sends neither usage statistics nor crash reports to us or to third parties. There's no tracking and no advertising, not in the Android app either. Music, playlists, listening history, statistics and accounts live in the database on your server, and only there.

The server only connects to the outside for features you switch on yourself. There are exactly these four, and the table names every service they contact:

ConnectionWhenTo whomWhat is sentRequirement
Online image searchWhen you search in the image dialogMusicBrainz, Cover Art Archive (Internet Archive), Wikidata, Wikimedia CommonsThe search term, i.e. the name of the artist or albumPro
MusicBrainz enrichmentWhen you look up an artist or a CD, or click “Check on MusicBrainz” in a split-up suggestionMusicBrainz, plus Wikidata, Wikimedia Commons and Wikipedia for the photo and biography, and when ripping CDs the Cover Art Archive (Internet Archive) for the coverThe name of the artist or album, or the CD's ID; when checking a split-up suggestion, the artist together with the track or album name. The Cover Art Archive only receives the MusicBrainz ID of the chosen releasePro
Licence checkWhen you enter the Pro code and once a day after thattunetorch.deOnly your installation's ID and a key that binds the licence to your serverPro
AccurateRipOnce per CD when ripping CDsAccurateRipOnly the CD's ID, calculated from its table of contentsCD ripping switched on

Your music, your library and your usage data go along with none of them.

CD ripping is off out of the box. When you switch it on, the interface explicitly asks first, and the AccurateRip check can be switched off separately. It's included without Pro too, because it safeguards the quality of the rip. So a Free installation without CD ripping doesn't open a single connection to the internet.

In the browser, too, everything stays with you: the interface loads nothing from third-party servers. Images from the online image search are fetched by the server, not by your browser.

Within your server:

What needs backing up

/app/data. Nothing more.

/app/data/
├── db/                   the database: tracks, albums, artists, accounts, playlists, statistics
├── backups/              backup copies of the database (see below)
├── audio/                uploaded original files + metadata backup
├── cover/                cover art in four sizes
├── interpret_hero/       artist images
├── person_hero/          photos of people
├── jwt/                  signing keys for sign-in
├── lizenz/               state of the Pro licence
├── redis/                persistent blocks
└── logs/                 server logs

You don't need to back up audio_cache/ (converted versions that can be recreated at any time), temp/ and upload_temp/.

If your collection lives in a mounted folder (/app/musik), back that up separately as usual. Tunetorch never writes to it.

Making a backup

With a bind mount, the simplest way is this:

docker compose stop tunetorch
tar czf tunetorch-backup-$(date +%F).tar.gz ./tunetorch-daten
docker compose start tunetorch

If you back up while it's running, with Borg, restic or rsync for example, you should know: the database works in WAL mode and is robust because of it. A snapshot taken in the middle of a write can still be incomplete. A backup is safest at night, after the maintenance tasks.

The nightly “Compact the database” task helps the backup. It frees unused storage and keeps the difference between two backups small.

Restoring

Put the directory back and start the container. Tunetorch recognises the state of the database and applies any necessary changes itself.

The sign-in key belongs in the backup. If jwt/ is missing, Tunetorch creates a new one on start-up, and all existing sign-ins become invalid. No data is lost, but everyone has to sign in again.

Tunetorch backs up by itself before every schema update

If an update changes the structure of the database, Tunetorch stores a copy of the database beforehand under /app/data/backups/. That doesn't happen on a normal restart, only when something really changes.

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

(The tool's output is in German: Art is the kind of copy, Größe the size.)

auto copies are created before a change and show the state before it. The two newest are kept. manuell (manual) copies you create yourself with tt db-sichern, and Tunetorch never deletes them.

Restoring if something isn't right after an update:

docker exec -u root -it tunetorch tt db-einspielen auto-schema23-20260819-1930.db

The command first backs up the current state, stops the server, restores the copy and starts the server again. After that you still need the old image. Otherwise the new server applies the same change again straight away on start-up. So enter the previous version in the docker-compose.yml instead of latest.

Older versions are available on Docker Hub for this: a superseded version stays available there for at least six months, and one version for each database structure stays there for good. If you want to keep a particular version for longer, save it yourself: docker save tunetorch/tunetorch:0.1.0 | gzip > tunetorch-0.1.0.tar.gz, and back with docker load < tunetorch-0.1.0.tar.gz.

Why -u root: only that way is the command allowed to stop the running server. Without it, it aborts and tells you why.

These copies are not three things:

Backup from the interface

You can also create a manuell copy without the command line: Server settings → System & maintenance → Database backup → Create backup now. Below it, all existing copies are listed with time, type and size. That's worthwhile before larger changes, for example before you press Apply all in the metadata assistant; its confirmation offers you the same button. Only admins have the right to do this.

Restoring and downloading are deliberately only possible on the server. To restore, Tunetorch pauses briefly, which the interface can't do by itself. And the copy contains the whole database including sign-in data, so it doesn't belong behind a download link. The list shows the matching tt db-einspielen command right away.

Metadata backup

Next to each uploaded original file, Tunetorch stores a small text file with its metadata. Tunetorch never reads it during operation. It's only a safety net in case the database is lost but the music files are still there.

Sign-in

Tunetorch stores the sign-in in protected cookies (HttpOnly), not in the browser's storage. A script on the page therefore can't get at your sign-in data.

CookieDefault lifetimePurpose
Access15 minutesAll normal requests, including music and cover art.
Refresh7 daysRenews the access token in the background.

The refresh lifetime counts from your last use, not from signing in: open Tunetorch again within that time and you get a fresh sign-in and stay signed in. You are only signed out after that long without using it at all.

Both lifetimes can be changed in the server settings (access at most 1 day, refresh at most 90 days). The upper limits prevent an accidentally high value from keeping a stolen sign-in valid for as long as it likes.

When you sign out, the server blocks both tokens. They're worthless immediately, even if someone had intercepted them. The blocklist lives on disk and survives a restart. In the Android app this happens when you remove a server connection: it first signs you out on the server and then deletes the data on the device. Otherwise the tokens would stay valid until they expire, even though nothing of them can be seen on the device any more.

With the Stay signed in switch you decide when signing in whether you stay signed in after closing the browser.

Brute-force protection

Failed sign-in attempts are counted per IP address. If there are too many within the set period, Tunetorch blocks the address for a certain time.

SettingDefault
Time window10 minutes
Failed attempts until blocked10
Block duration60 minutes

In addition, the response to a wrong username takes just as long as to a wrong password. So the response time doesn't reveal whether an account exists.

For this, TT_TRUSTED_PROXIES has to be right. Behind a reverse proxy the server would otherwise only see the proxy's IP and lock everyone out with a block. If the value is too high, on the other hand, the caller's IP can be faked. See Configuration.

Hardening in the browser

Previews from the online image search go through the server, not directly through the browser. That keeps the strict policy in place, and your browser makes no contact with third-party servers.

Access from the internet

If you want to listen on the go, you need a reverse proxy with a valid TLS certificate. Without HTTPS

An example for Caddy and Nginx is under Configuration.

Instead of opening a port, you can also use a VPN into your home network (WireGuard, Tailscale) or a tunnel. Then you don't need any port forwarding at all.

Where to go next

Back to the documentation overview