Docker guide

Bring Quven Server to Docker

A complete guide to running Quven Server on Linux with Docker Compose, protecting its data and choosing the right hardware acceleration for your host.

By Domenico Aiello Updated 3 September 2026 Verified 1 September 2026

The official Quven Server image runs on Linux AMD64 and ARM64. It sits beside your library, carries its state from one release to the next, leaves every media file where it was, and it can use the host’s hardware acceleration. This guide takes you from an empty directory to a linked server, and then through the optional GPU profiles and upgrades.

This is the Server-only edition. It doesn’t include the desktop client and it doesn’t host the web app. You’ll need Docker Engine on Linux with Docker Compose v2. Docker Desktop isn’t supported, because Quven reaches its clients through host networking and LAN discovery, and Docker Desktop can’t offer either.

Start from a repeatable foundation

Give Quven its own directory and download the Compose files for release 1.1.22. They’re versioned, so the same configuration will keep pointing at the same image after a newer release appears.

mkdir -p quven && cd quven
curl -fsSLO https://quven.tv/docker/1.1.22/compose.yaml
curl -fsSL https://quven.tv/docker/1.1.22/env.example -o .env

Open .env and set QUVEN_MEDIA_DIR to the absolute path of your library. It already points at ghcr.io/nickayl/quven:v1.1.22; keep the versioned tag. If you replace it with latest, a restart can pull a new version without you asking for it.

The quven-data volume holds the database, the configuration and the logs, so you can recreate the container without losing any of them. Your media comes in writable, because Quven writes the subtitles it generates back beside the film. That directory has to be writable by uid 10001, the user the container runs as.

When Quven transcribes, translates, recognises or edits a subtitle, it keeps the result in its own store inside the data volume, and every client plays it from there. It also writes a copy beside the video, so the text travels with the film if you move it to another machine or hand the folder to somebody else. If uid 10001 can’t write to that directory, the copy fails and the only trace is a warning in the server log. The subtitle itself is unaffected and plays normally; it simply isn’t in the folder next to the film.

If you would rather the server never touched your library, set QUVEN_MEDIA_READ_ONLY=true in .env and recreate the container with docker compose up -d. Quven then catalogues and plays your media without writing anything into it, and the only thing you give up is that second copy. It’s a trade between a guarantee and a convenience, and which one is worth more depends on your setup.

Quven follows symbolic links inside a library, so a media folder that holds links into a mounted remote is read as the films it points at. There’s one condition, and it catches people out: the container has to see the target at the same path the link names. A link reading /mnt/decypharr/film.mkv means nothing inside a container that was only handed /media, and every one of those links will be reported as unreachable at the end of the scan.

Mount the target as well, under the path it is named by, the same way you mounted the media root:

      - type: bind
        source: /mnt/decypharr
        target: /mnt/decypharr

Where should the second mount go? Under volumes: beside the first one, in the same service. If you would rather check before scanning a whole library, run docker compose exec quven ls /mnt/decypharr and see whether the container can read what your links point at.

Bring the server online

You should ask Compose to validate the configuration first, then pull the image and start the service. The last command creates the secure link to your Quven Account.

docker compose config
docker compose pull
docker compose up -d
docker compose ps
curl --fail --silent --show-error http://127.0.0.1:5181/health/container -o /dev/null
docker compose exec quven /app/Quven.Local.Server account link

Open the URL that account link prints, sign in to your Quven Account and approve the server. Native clients should now find it on the LAN, or you can point them at http://<server-ip>:5181. With Pro, app.quven.tv reaches it through the managed relay as well.

Where do libraries get added? From the Quven desktop app on any computer on the same network, or from app.quven.tv if you have Pro. A TV or a phone can’t create them. It can only play what a desktop has already set up. So a server that only ever meets a television client stays empty; install the desktop app on some computer in the house first. When it asks, pick your folders below /media: a host library at /srv/media shows up inside Quven as /media.

The image runs as UID/GID 10001, drops Linux capabilities, blocks privilege escalation and keeps its root filesystem read-only, so a compromised process can’t do much. Those protections are part of the product, and you shouldn’t turn the service into a privileged container to get around a host permission problem.

Give video to the right hardware

Play one title with the base profile first. That proves the network, the library and the account path before a GPU enters the picture. Then add one override, the one that matches an interface you have actually seen on the host.

Choose one profile only. The options below are alternatives: NVIDIA, Intel/AMD or ARM. Don’t run every block or combine overrides, except where the Raspberry Pi profile explicitly requires the V4L2 base.

NVIDIA profile

With the NVIDIA Container Toolkit installed, add the dedicated profile and recreate the service:

curl -fsSLO https://quven.tv/docker/1.1.22/compose.nvidia.yaml
docker compose -f compose.yaml -f compose.nvidia.yaml config
docker compose -f compose.yaml -f compose.nvidia.yaml up -d

The 1.1.22 profile asks for the GPU with runtime: nvidia, which every Compose release accepts once the Container Toolkit has registered its runtime (nvidia-ctk runtime configure --runtime=docker). A host set up for CDI instead of that runtime drops the key and asks with gpus: all, which older Compose releases reject outright; that’s why it isn’t the published default. Keep NVIDIA_DRIVER_CAPABILITIES as published. Without the video capability the injected driver carries no NVENC, and the server will encode in software without telling you.

Intel or AMD profile

For an Intel or AMD GPU, identify the render node and pass the host’s render and video group IDs into the container:

curl -fsSLO https://quven.tv/docker/1.1.22/compose.vaapi.yaml
echo 'QUVEN_RENDER_GID='"$(getent group render | cut -d: -f3)" >> .env
echo 'QUVEN_VIDEO_GID='"$(getent group video | cut -d: -f3)" >> .env
docker compose -f compose.yaml -f compose.vaapi.yaml config
docker compose -f compose.yaml -f compose.vaapi.yaml up -d

If the right GPU isn’t /dev/dri/renderD128, set QUVEN_DRI_RENDER_DEVICE in .env. Keep the path identical inside and outside the container. Disguising one render node as another makes every later diagnosis ambiguous.

Advanced Raspberry Pi or ARM profile

This is an advanced setup. If Quven already plays your library well, you don’t need to add anything.

Hosts that expose V4L2 M2M codecs can use compose.v4l2m2m.yaml. A Raspberry Pi 4 can also add compose.raspberry-pi.yaml for HEVC Request API decode. Both profiles require the real device paths the system reports, and they refuse to start when the setup is incomplete.

Don’t guess device nodes, and don’t expose all of /dev. On a different ARM board or NAS, inspect the available interfaces with v4l2-ctl --list-devices first. The base profile remains the safe choice, and it will keep software decode available when acceleration can’t be used.

Upgrade without gambling the library

A good upgrade is uneventful. Download the new versioned bundle, read it, note the digest currently in use, and only then run docker compose pull and docker compose up -d.

Before every upgrade, and while the service is stopped, copy the quven-data volume together with .env and the Compose files, because those three things are your way home and you should never delete them during an update or a rollback, however routine it looks. The copy matters because a release can change the database schema, and an older image can’t read a database a newer one has already migrated. Restoring the previous digest in QUVEN_IMAGE therefore means restoring the database beside it, either from your own copy of the volume or from the snapshot the server writes under backups/quven-pre-migration-<timestamp>.db inside it before it applies schema changes. The five most recent snapshots are kept.

After every change, check health and play both a direct-play title and one that must transcode.

Verify what you are running

The Quven image is signed and carries an SPDX attestation. Cosign lets you verify the exact release before it reaches your library:

curl -fsSLO https://quven.tv/docker/1.1.22/cosign-public-key.pem
cosign verify --key cosign-public-key.pem ghcr.io/nickayl/quven:v1.1.22
cosign verify-attestation --key cosign-public-key.pem --type spdxjson ghcr.io/nickayl/quven:v1.1.22

The public 1.1.22 manifest contains the image-index digest and each platform digest. Keep it beside the configuration you approved.

Frequently asked questions

Can I run it with Docker Desktop?

No. Quven reaches its clients through host networking and LAN discovery, which Docker Desktop doesn’t provide. You need Docker Engine on Linux with Docker Compose v2.

Should I pin the version or follow latest?

Pin it. The Compose bundle is tied to a published release, so restarting the server can’t quietly turn into an upgrade, and the published digest tells you what actually arrived.

Will Quven write to my media folder?

Only the subtitles it generates for you, beside the film they belong to. Nothing else goes there, and a scan writes nothing at all. If you would sooner it never touched the folder, set QUVEN_MEDIA_READ_ONLY=true in .env and recreate the container. Quven keeps those subtitles in its own volume and serves them either way, so all you lose is the copy that travels with the file.

Which hardware profile do I add?

One, and only after you’ve seen the matching interface on the host. Play a title on the base service first, then add the NVIDIA, Intel/AMD or ARM override that fits what you observed. Running several at once produces a configuration that looks convenient and fails on the first difficult file.

Bring your library home.

Free for home use and yours to run on your own hardware. Install it in minutes.