Riven

Getting Started

Install and run Riven TS with Docker.

Prerequisites

  • Linux host with FUSE support and /dev/fuse available
  • Docker Engine 24+ with Compose V2
  • A debrid service account (Real-Debrid, AllDebrid, TorBox, …)
  • A media server (Plex or Jellyfin)
  • A TMDB API key (free at themoviedb.org)

Riven mounts its virtual file system with FUSE, which needs the SYS_ADMIN capability and /dev/fuse. There is no way to run it without them.

Prefer to skip the manual setup? The Compose Generator produces the same files from a form. Prefer not to use Docker at all? See Running from Source.

Prepare the host mount

Riven mounts the VFS inside the container and shares it back to the host, which only works if the mount point uses shared propagation. A systemd unit is the most reliable way to guarantee this survives reboots:

/etc/systemd/system/riven-mount.service
[Unit]
Description=Make Riven data 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
sudo mkdir -p /mnt/riven
sudo systemctl daemon-reload
sudo systemctl enable --now riven-mount.service

findmnt -o TARGET,PROPAGATION /mnt/riven  # must print "shared"

Create the data directories

Riven writes logs and its generated ranking config to disk. The container runs as UID/GID 1000, so the directories must be owned by that user or Riven will fail to start:

mkdir -p logs data
sudo chown -R 1000:1000 logs data

Create your docker-compose.yml

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
    ports:
      - 3000:3000
    volumes:
      - ./logs:/app/logs
      - ./data:/app/data
      - /mnt/riven:/mount:rshared,z
    depends_on:
      postgres:
        condition: service_healthy
      redis:
        condition: service_healthy

  postgres:
    image: postgres:17-alpine
    container_name: riven-postgres
    restart: unless-stopped
    environment:
      POSTGRES_USER: riven
      POSTGRES_PASSWORD: CHANGEME
      POSTGRES_DB: riven
    volumes:
      - postgres_data:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U riven"]
      interval: 5s
      timeout: 5s
      retries: 5

  redis:
    image: redis:8-alpine
    container_name: riven-redis
    restart: unless-stopped
    command: redis-server --maxmemory-policy noeviction --appendonly yes
    volumes:
      - redis_data:/data
    healthcheck:
      test: ["CMD-SHELL", "redis-cli ping | grep PONG"]
      interval: 5s
      timeout: 5s
      retries: 5

volumes:
  postgres_data:
  redis_data:

There is no latest tag. Use :main to track the current build, or pin a released version such as :1.2.3.

Create your .env file

.env
# Core
RIVEN_SETTING__databaseUrl="postgres+psycopg2://riven:CHANGEME@postgres:5432/riven"
RIVEN_SETTING__redisUrl="redis://redis:6379"

# Must match the container-side path of the VFS volume above
RIVEN_SETTING__vfsMountPath="/mount"

# Bind the GraphQL API to all interfaces so it is reachable outside the
# container. It defaults to localhost, which is only useful for local runs.
RIVEN_SETTING__gqlHost="0.0.0.0"

# If you want to bind mount this file from the host, create it first;
# otherwise Docker will mount a directory named riven-ranking-config.json.
RIVEN_SETTING__rankingConfigPath="/app/data/riven-ranking-config.json"
RIVEN_SETTING__logLevel="info"

# Plugins to enable. tmdb and tvdb are always on and don't need listing.
RIVEN_SETTING__enabledPlugins=["seerr","stremthru","torrentio","plex"]

# Metadata (required)
RIVEN_PLUGIN_SETTING__REPO_PLUGIN_TMDB__apiKey="your-tmdb-api-key"

# Debrid store, via StremThru — set the key for the service you pay for
RIVEN_PLUGIN_SETTING__REPO_PLUGIN_STREMTHRU__realdebridApiKey="your-rd-key"

# Content source
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"

See Configuration for every core setting, and Plugins for what each plugin accepts.

Start Riven

docker compose up -d
docker compose logs -f riven

Riven bootstraps, connects to PostgreSQL and Redis, registers its plugins, mounts the VFS, and serves the GraphQL API on port 3000. Confirm it is reachable:

curl -X POST http://localhost:3000 \
  -H 'content-type: application/json' \
  -d '{"query":"{ __typename }"}'

Point your media server at the VFS

Add /mnt/riven as a library:

  • Plex: Add Library → Movies/TV Shows → Browse for media folder
  • Jellyfin: Dashboard → Libraries → Add Media Library

If the media server also runs in Docker, mount the same path with rslave propagation — /mnt/riven:/mount:rslave,z — and set the plugin's plexLibraryPath / jellyfinLibraryPath to the container-side path.

What's Next?

On this page