Installing with Docker

Tunetorch comes as a Docker image. The database, cache and FFmpeg are already included, so all you need is Docker, ideally with Docker Compose.

Quick start

Create a file called docker-compose.yml:

services:
  tunetorch:
    image: tunetorch/tunetorch:latest
    container_name: tunetorch
    restart: unless-stopped
    ports:
      - "5000:5000"
    volumes:
      # Data directory. Please back it up regularly.
      - ./tunetorch-daten:/app/data

      # Optional: existing music folder to scan (always read-only).
      # - /path/to/your/music:/app/musik:ro

      # Optional: collection for the one-off initial import.
      # - /path/to/your/collection:/app/import:ro

    # Suitable for direct access over HTTP, as described in this quick
    # start. Behind a TLS reverse proxy, remove both lines again
    # (see below).
    environment:
      TT_HTTPS: "False"         # no TLS: cookies without the Secure flag
      TT_TRUSTED_PROXIES: "0"   # no proxy in front
      # TT_PUID: "1000"         # UID of the volume owner
      # TT_PGID: "1000"         # GID of the volume owner

Start it:

docker compose up -d

You'll then find the web interface at http://<server-address>:5000. The first time, sign in with admin / BITTE_ÄNDERE_MICH. Tunetorch asks for a new password straight away (see Getting started).

The volumes in detail

Path in the containerRequiredPurpose
/app/datayesDatabase, uploaded audio files, cover art, images, logs, sign-in keys, cache. This is the directory you need to back up.
/app/musiknoAn existing music folder that the library scan reads in. Always mount it with :ro. Tunetorch never writes to your music library.
/app/importnoAn existing collection for the one-off initial import. Also :ro. You can remove the line again after the import.

You can mount /app/data as a bind mount (./tunetorch-daten:/app/data) or as a named volume (tunetorch_daten:/app/data). With a bind mount, set TT_PUID/TT_PGID to your host user (id -u / id -g) so that you can write to it from the host as well.

On start-up, the container hands /app/data over to the configured UID:GID. A folder created by root therefore becomes writable by itself. If that doesn't work (because of ACLs on a Synology, for example), the start aborts with an [entrypoint] FEHLER: message (German for “error”).

Docker only, without Compose

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

Loading a supplied image

If you received the image as an archive:

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

In the archive the image is called tunetorch:<VERSION>-<arch>, but the Compose file above expects tunetorch/tunetorch:latest. So you have to rename it. Otherwise the start fails with “image not found”, and nothing tells you why:

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

Updating

docker compose pull
docker compose up -d

Your data in /app/data is kept. Tunetorch applies database changes itself on start-up, so there's nothing to do by hand after an update.

Before larger updates, a backup of the data directory is worth it. See Security & backup.

Running behind a TLS reverse proxy

The quick start above is set up for direct access over HTTP. That's what the two lines TT_HTTPS: "False" and TT_TRUSTED_PROXIES: "0" are for. If Tunetorch runs behind a reverse proxy with TLS (Caddy, Traefik, Nginx Proxy Manager), remove both again. The defaults True and 1 are meant for exactly this case. The proxy has to pass on X-Forwarded-Proto: https; that's how Tunetorch recognises the encrypted connection.

The reason lies in how browsers handle cookies: with TT_HTTPS: "True", the sign-in cookies get the Secure flag. If you then open Tunetorch over http://, the browser silently discards them. The sign-in seems to fail, even though the server accepted it. The server log then contains a warning that describes exactly this.

The trap during initial setup: over http://localhost:5000, Chrome, Edge and Firefox accept Secure cookies anyway, because they treat localhost as secure. If you set up Tunetorch directly on the server, you therefore won't notice a wrong setting. Only access from a second device via the LAN address fails.

If you have the choice, use TLS. TT_HTTPS: "False" is the solution for a home network without a certificate, not the better way to run it.

More on this under Configuration.

Synology DSM

On Synology systems, a shared folder often doesn't belong to 1000:1000 but to, say, 1026:100. Check the values on the host with ls -ln in the volume directory and enter them:

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

If an ACL overrides the automatic change of owner, also explicitly give the user with this UID write permission in File Station.

Two more DSM quirks often cost time on the first start: port 5000 belongs to the DSM interface (choose a different host port), and a shared folder that you mount as /app/import or /app/musik is not automatically readable for the container. That you can open it yourself in File Station means nothing here. Both, including a command to check, are on the Synology NAS (DSM) page.

Storage for DLNA casting (optional)

If you use DLNA casting with loudness matching or a target format, the server creates short-lived copies of the current track. It decides where by itself: preferably in memory, otherwise on disk. So there's nothing to set up for this.

If your server has plenty of RAM, you can deliberately put the copies in memory and spare the SD card or SSD some writes:

    shm_size: "1g"

This is an upper limit, not a reservation. As long as the space isn't needed, it costs nothing. On a Raspberry Pi, though, RAM is scarcer than write cycles, so the default is usually the better choice there.

Passing through a CD drive (optional)

For ripping CDs, the container needs access to a CD drive on the server, built in or connected via USB. The programs it needs are already in the image; only these lines are missing:

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

Then switch CD ripping on in the server settings. If the interface reports “No access to the drive”, the number under group_add is almost always wrong.

On a Synology NAS, these lines usually don't help: DSM doesn't ship the driver for CD drives, so Tunetorch doesn't see a drive. How to check this and what you can do instead is described under Synology NAS (DSM).

Do you also use DLNA casting? With /dev:/dev, the container sees the host's memory folder, and shm_size (see above) no longer has any effect. The casting copies then end up in RAM. On a Raspberry Pi, this line under environment: keeps them on disk:

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

Raspberry Pi: mind the power supply. When the CD spins up, a USB drive briefly needs more power than the Pi's USB ports deliver. That doesn't show up as a clear error message, but as read errors or as a drive that disappears in the middle of a rip. The fix is a drive with its own power supply or a powered USB hub, meaning one with its own power supply. A Y-cable across two of the Pi's ports doesn't help. A passive splitter with a phone charger plugged into its second port isn't a solution either: Its power lines are connected, so the charger also feeds power back into the Pi.

If your Pi boots from a USB SSD, this matters twice over. The SSD and the drive then share the power of the USB ports. If the voltage drops while the CD spins up, the Pi can briefly lose its SSD and hang: It still answers pings, but no longer responds to SSH or the interface. In that case, connect only the drive to the hub and keep the SSD directly on the Pi. Connected through the hub, the SSD would have one more point where your boot drive can drop out.

To check whether the power supply is sufficient, run vcgencmd get_throttled on the Pi after a rip. throttled=0x0 means the voltage hasn't dropped once since start-up.

Health check

The image includes a HEALTHCHECK that checks every 30 seconds whether the server responds. docker ps therefore shows the container as healthy or unhealthy. That way you also spot a hung server that restart: unless-stopped alone wouldn't notice.

Depending on the hardware, start-up takes up to a minute (on one NAS it was 44 seconds), because Redis, the database check and the server start one after another. During that time the container doesn't count as healthy yet, and a “Bad Gateway” from the reverse proxy is normal. It goes away by itself. If it stays, the cause lies elsewhere; see Troubleshooting.

docker ps
docker compose logs -f tunetorch

Next step

Back to the documentation overview