Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/rivenmedia/riven-ts/llms.txt

Use this file to discover all available pages before exploring further.

Docker Compose is the fastest and most reliable way to run Riven TS. The stack is three containers — Riven itself, a PostgreSQL 17 database (riven-db), and a Redis 8 cache (riven-cache) — wired together with a single Compose file. The only host-level prerequisite beyond Docker is a FUSE mount point, which lets Riven’s virtual file system be visible outside the container so your media server can read it.
Prefer to skip Docker entirely? See Running from Source.

Prerequisites

Before you begin, confirm that you have:
  • A Linux host with FUSE support and /dev/fuse available
  • Docker Engine 24+ with Compose V2 (docker compose, not docker-compose)
  • A debrid service account (Real-Debrid, AllDebrid, TorBox, or another provider supported by StremThru)
  • A running media server — Plex or Jellyfin
  • A TMDB API key (free at themoviedb.org)
Riven mounts its virtual file system with FUSE, which requires the SYS_ADMIN capability and access to /dev/fuse. There is no supported way to run it without these. Rootless Docker and container runtimes that drop SYS_ADMIN will not work.

Installation

1

Prepare the host mount point

Riven mounts the VFS inside its container and propagates it back to the host through a bind mount. For this to work, the host mount point must use shared propagation — otherwise the FUSE mount created inside the container is invisible outside it.A systemd unit is the most reliable way to guarantee the propagation mode survives reboots:
/etc/systemd/system/riven-mount.service
[Unit]
Description=Make Riven VFS bind mount shared
After=local-fs.target
Before=docker.service

[Service]
Type=oneshot
ExecStart=/usr/bin/mount --bind /mnt/riven /mnt/riven
ExecStart=/usr/bin/mount --make-rshared /mnt/riven
RemainAfterExit=yes

[Install]
WantedBy=multi-user.target
Create the directory, reload systemd, and start the unit:
sudo mkdir -p /mnt/riven
sudo systemctl daemon-reload
sudo systemctl enable --now riven-mount.service
Confirm the propagation mode is shared before continuing:
findmnt -o TARGET,PROPAGATION /mnt/riven
# TARGET       PROPAGATION
# /mnt/riven   shared
2

Create data directories

Riven writes logs and its generated ranking config to mounted volumes. The container runs as UID/GID 1000; the directories must be owned by that user or Riven will fail to write on startup:
mkdir -p docker-data/riven
sudo chown -R 1000:1000 docker-data
3

Create your environment files

The stack uses two environment files. Create a .env file for host-level variables (the VFS mount path, UID/GID, and database password):
.env
PUID=1000
PGID=1000
DATABASE_PASSWORD=CHANGEME
HOST_VFS_MOUNT_PATH=/mnt/riven
Then create .env.riven for Riven’s own settings — the RIVEN_SETTING__* and RIVEN_PLUGIN_SETTING__* variables:
.env.riven
# ── Core ──────────────────────────────────────────────────────────────────

## PostgreSQL connection URL — host "riven-db" is the Compose service name
RIVEN_SETTING__databaseUrl="postgresql+psycopg2://postgres:CHANGEME@riven-db/riven"

## Redis connection URL — host "riven-cache" is the Compose service name
RIVEN_SETTING__redisUrl="redis://riven-cache:6379"

## Container-side path of the VFS volume mount
RIVEN_SETTING__vfsMountPath="/mount"

## Bind the GraphQL API to all interfaces so it is reachable outside the container
## (defaults to localhost, which is unreachable from the host)
RIVEN_SETTING__gqlHost="0.0.0.0"

## Log verbosity: debug | info | warn | error
RIVEN_SETTING__logLevel="info"

## Plugins to enable (tmdb and tvdb are always active and do not need listing)
RIVEN_SETTING__enabledPlugins=["seerr","stremthru","torrentio","plex"]

# ── Metadata ──────────────────────────────────────────────────────────────

RIVEN_PLUGIN_SETTING__REPO_PLUGIN_TMDB__apiKey="your-tmdb-api-key"

# ── Debrid (via StremThru) ────────────────────────────────────────────────
## Set the key for whichever service you use:

RIVEN_PLUGIN_SETTING__REPO_PLUGIN_STREMTHRU__realdebridApiKey="your-rd-key"
# RIVEN_PLUGIN_SETTING__REPO_PLUGIN_STREMTHRU__alldebridApiKey="your-ad-key"
# RIVEN_PLUGIN_SETTING__REPO_PLUGIN_STREMTHRU__torboxApiKey="your-tb-key"

# ── Content source (Seerr / Overseerr / Jellyseerr) ───────────────────────

RIVEN_PLUGIN_SETTING__REPO_PLUGIN_SEERR__url="http://seerr:5055"
RIVEN_PLUGIN_SETTING__REPO_PLUGIN_SEERR__apiKey="your-seerr-key"

# ── Media server ──────────────────────────────────────────────────────────

RIVEN_PLUGIN_SETTING__REPO_PLUGIN_PLEX__plexToken="your-plex-token"
RIVEN_PLUGIN_SETTING__REPO_PLUGIN_PLEX__plexServerUrl="http://plex:32400"
Replace every CHANGEME and placeholder value before starting. The DATABASE_PASSWORD in .env must match the password embedded in RIVEN_SETTING__databaseUrl in .env.riven. See Configuration for the full list of core settings, and Plugins for per-plugin options.
4

Create docker-compose.yml

Create a docker-compose.yml in the same directory. The rshared volume flag on the mount path is required — it tells Docker to propagate the FUSE mount bidirectionally:
docker-compose.yml
services:
  riven:
    image: ghcr.io/rivenmedia/riven-ts:main
    container_name: riven
    restart: unless-stopped
    tty: true
    cap_add:
      - SYS_ADMIN
    security_opt:
      - apparmor:unconfined
    devices:
      - /dev/fuse
    env_file: .env.riven
    ports:
      - 3000:3000
    volumes:
      - ./docker-data/riven/logs:/app/logs
      - ./docker-data/riven/riven-ranking-config.json:/app/riven-ranking-config.json
      - ${HOST_VFS_MOUNT_PATH}:/mount:rshared
    depends_on:
      riven-db:
        condition: service_healthy
      riven-cache:
        condition: service_healthy

  riven-db:
    image: postgres:17-alpine
    container_name: riven-db
    restart: unless-stopped
    environment:
      PGDATA: /var/lib/postgresql/data/pgdata
      POSTGRES_USER: postgres
      POSTGRES_PASSWORD: ${DATABASE_PASSWORD}
      POSTGRES_DB: riven
    volumes:
      - riven-db:/var/lib/postgresql/data/pgdata
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U postgres"]
      interval: 10s
      timeout: 5s
      retries: 5

  riven-cache:
    image: redis:8-alpine
    container_name: riven-cache
    restart: unless-stopped
    command: redis-server --maxmemory-policy noeviction --appendonly yes
    user: "1000:1000"
    volumes:
      - ./docker-data/riven-cache:/data
    healthcheck:
      test: ["CMD", "redis-cli", "ping"]
      interval: 5s
      timeout: 3s
      retries: 10

volumes:
  riven-db:
There is no latest image tag. Use :main to track the current build, or pin a released semver tag such as :1.2.3.
The riven-ranking-config.json volume entry mounts a file, not a directory. Create it on the host before running docker compose up, otherwise Docker will create a directory at that path and Riven will fail to write the config:
touch docker-data/riven/riven-ranking-config.json
5

Start Riven

Bring up the stack in detached mode and tail the Riven logs to watch the bootstrap sequence:
docker compose up -d
docker compose logs -f riven
Riven connects to PostgreSQL and Redis, runs any pending database migrations, registers its plugins, mounts the FUSE VFS, and starts the GraphQL API server on port 3000. Confirm it is reachable:
curl -X POST http://localhost:3000 \
  -H 'content-type: application/json' \
  -d '{"query":"{ __typename }"}'
# {"data":{"__typename":"Query"}}
6

Point your media server at the VFS

Add /mnt/riven as a library root in your media server:
  1. Open Plex Web → SettingsLibraries
  2. Click Add Library, choose Movies or TV Shows
  3. Under Add folders, click Browse for media folder and select /mnt/riven
  4. Click Add Library
If your media server also runs in Docker, mount the same path into that container using rslave propagation — for example /mnt/riven:/media:rslave — and update the plugin’s plexLibraryPath or jellyfinLibraryPath to the container-side path.

What’s next?

Configure plugins

Set up your content sources, debrid provider, and media server integrations in detail.

Production deployment

Reverse proxy setup, TLS, update strategies, and health monitoring.

Troubleshooting

Solutions for common FUSE, networking, and permission issues.

Running from source

Skip Docker and run Riven directly on your host with Node.js and pnpm.

Build docs developers (and LLMs) love