# Riven mounts a debrid-backed library into Plex over FUSE

> Riven is a self hosted media library manager that pulls titles through Real Debrid or AllDebrid and exposes them to Plex, Jellyfin and Emby as a mounted filesystem, and the part that takes real work is the mount propagation configuration rather than the application itself. It suits homelab users who want a debrid library without running the indexers themselves.

**rivenmedia/riven** — Handle your Media Library with ease!

- Repository: https://github.com/rivenmedia/riven
- Website: https://riven.tv
- Stars: 820 · Forks: 104
- Language: Python
- License: GPL-3.0
- Published: 2026-10-20 · Updated: 2026-10-20 · Language: en
- Canonical page: https://hysenlabs.com/projects/rivenmedia-riven

## A library view, not a download client

Riven is described as Plex torrent streaming through Debrid and third party services like Overseerr and Mdblist, with the tag line telling you to handle your media library with ease. The distinction that matters is what Riven is not. It does not seed, and it does not index the way a traditional stack does. It sits in front of a debrid provider, resolves a title through the scraping and content services, and presents the result to your media server as a filesystem. From the media server's point of view the files are local, which is why the Plex integration looks like a normal library rather than a plugin. The description in the project metadata makes the same point in one line, describing it as a media server that handles torrenting through debrid services and third party integrations such as Overseerr and Mdblist.

## The service matrix, and which of it you actually need

The README lists what is supported in four rows, and reading them tells you how much of the stack you have to run yourself. The debrid services row covers Real Debrid and All Debrid, which are the actual source of the content. The content services row lists Plex Watchlist, Overseerr, Mdblist, Listrr and Trakt, which is where watchlists and requests come from. The scraping services row covers Comet, Jackett, Torrentio, Orionoid, Mediafusion, Prowlarr, Zilean and Rarbg, and these are the components that turn a title into a magnet link. The media servers row lists Plex, Jellyfin and Emby. The architecture is therefore a pipeline across four different kinds of service, and the practical consequence is that the number of credentials you have to collect is large. A minimal setup is a debrid account, one scraping service and one media server, and the environment file shows the shape of that configuration, with `RIVEN_PLEX_ENABLED`, `RIVEN_PLEX_TOKEN` and `RIVEN_PLEX_URL` alongside the equivalents for Jellyfin and Emby.

## Self hosting: copy the compose file and change the paths

Installation is a copy and edit rather than a script. The README asks you to find a place on the hard drive that will act as the mount, and to copy the contents of `docker-compose.yml` into your own file. The compose file defines the `riven` service on port 8080, with `SYS_ADMIN` added as a capability, `apparmor:unconfined` as a security option, a shared memory size of 1024m and the `/dev/fuse` device mapped in, because the library is exposed as a FUSE filesystem. A `riven_postgres` service runs `postgres:17-alpine`, and the application container waits for the database to report healthy before starting. The environment points the app at the database with `RIVEN_DATABASE_HOST` and `RIVEN_FORCE_ENV=true`. The two volumes are the data directory and the mount, and the mount one carries the flags that decide whether the container sees the host mount at all.

## The shared bind mount, and why the flags are not optional

The README is emphatic about one detail. When adding `/mount` to any container, you must add `:rshared,z` to the end of the volume mount, and the example shows the shape:

```yaml
volumes:
  - /path/to/riven/data:/riven/data
  - /path/to/riven/mount:/mount:rshared,z
```

On the host, the directory has to be a shared bind mount, marked as such once per boot:

```bash
sudo mkdir -p /path/to/riven/mount
sudo mount --bind /path/to/riven/mount /path/to/riven/mount
sudo mount --make-rshared /path/to/riven/mount
```

and you check it with `findmnt -T /path/to/riven/mount -o TARGET,PROPAGATION`, expecting `shared` or `rshared`. The README then gives two ways to make it survive a reboot, a systemd one-shot unit that runs before `docker.service` and an `fstab` entry using the `bind,rshared` options. Two further notes come with it. Keep the FUSE mount configured with `allow_other`, which the Dockerfile handles by setting `user_allow_other` in `/etc/fuse.conf`, and on SELinux systems add `:z` to the bind mount if you need it.

## When Plex shows an empty mount after a restart

The README devotes a troubleshooting section to the failure where Plex's library path looks empty inside the Plex container after Riven or RivenVFS restarts, and it says up front that this is almost always mount propagation or timing rather than a bug in the application. The diagnosis has four parts. Confirm the host path is shared, then confirm propagation inside the Plex container, where the container must also receive mount events recursively, so its bind needs `rslave` or `rshared` rather than `rshared`. The check is `docker exec -it plex sh -c 'findmnt -T /mount -o TARGET,PROPAGATION,OPTIONS,FSTYPE'`, and the propagation should be `rslave` or `rshared` with the filesystem type showing fuse. Third, Riven's own settings must point at the container path, typically `/mount`, and not the host path, so that both Riven and Plex refer to the same in-container path.

## Stale FUSE mounts and the expected empty window

The fourth troubleshooting step is about leftovers. If a previous FUSE instance did not unmount cleanly on the host, a stale mount can block a remount, and the fix is to clear it with `sudo fusermount -uz /path/to/riven/mount` or `sudo umount -l /path/to/riven/mount`, then start Riven again. The README is also candid about a behaviour that looks like a fault. When Riven stops, the FUSE mount unmounts and `/mount` may briefly appear empty inside the container, and it becomes FUSE again when Riven remounts. With proper propagation on the host and in the container, and the right startup order, Plex should see the content return without a restart, and enabling Plex's Automatically scan my library option helps it pick up changes. The Plex library requirements are strict in the meantime, since movies libraries need the `movies` and `anime_movies` categories and shows libraries need `shows` and `anime_shows`.

## The cache settings and the stack underneath

The virtual filesystem has its own settings, and the environment file names them. `cache_dir` is the directory for on-disk cache files and should be a user-writable path, and `cache_max_size_mb` is the maximum cache size for the VFS cache. The variables in the environment file are more granular, with `RIVEN_FILESYSTEM_CACHE_DIR`, `RIVEN_FILESYSTEM_CACHE_MAX_SIZE_MB` set to 1024, `RIVEN_FILESYSTEM_CACHE_TTL_SECONDS` at 7200, `RIVEN_FILESYSTEM_CACHE_EVICTION` set to LRU with TTL as the alternative, cache metrics on, a chunk size of 8MB and a fetch ahead of one chunk. The application itself is Python on FastAPI with uvicorn, SQLAlchemy and alembic against Postgres, `pyfuse3` for the filesystem, `plexapi` for the media server side, apprise for notifications, and OpenTelemetry with a Prometheus exporter for metrics. The licence is GPL-3.0, the published releases are v0.23.4, v0.23.5 and v0.23.6 from August 2025, and the last push was on 2026-06-27.

## Conclusion

Adopt Riven when you want a debrid backed library in your media servers and you would rather not run the indexers and download clients yourself, since it covers Real Debrid and AllDebrid, several scraping services and three media server targets in one container. Do not adopt it if your library is local files rather than a debrid catalogue, since the whole design is about a FUSE view over streamed content. Verify first that your host can run the FUSE mount and that the propagation settings are right, because the README treats an empty mount inside Plex as a propagation problem rather than an application bug, and note that the published releases are 0.23.x while the project metadata says 1.0.0.

## FAQ

### Which debrid and media server services does Riven support?

The debrid services are Real Debrid and All Debrid, the content services are Plex Watchlist, Overseerr, Mdblist, Listrr and Trakt, the scraping services are Comet, Jackett, Torrentio, Orionoid, Mediafusion, Prowlarr, Zilean and Rarbg, and the media servers are Plex, Jellyfin and Emby.

### Why does Plex show an empty /mount after Riven restarts?

The README says it is almost always mount propagation or timing. The host directory must be a shared bind mount, the Plex container must receive mount events recursively with an `rslave` or `rshared` bind, and Riven's filesystem mount path must be set to the in-container path such as `/mount` rather than the host path.

### How do I make the mount shared automatically on boot?

The README offers a systemd one-shot unit that runs the bind mount and `mount --make-rshared` before `docker.service`, enabled with `sudo systemctl enable --now riven-bind-shared.service`, or an fstab entry using the `bind,rshared` options on the same path.

### What licence is Riven released under?

GPL-3.0, in a `LICENSE.md` file at the repository root. The last listed release is v0.23.6 from 2025-08-24, and the last push to the repository was on 2026-06-27.

## Sources

- [License: GPL-3.0](https://github.com/rivenmedia/riven/blob/main/LICENSE)
- [Project website](https://riven.tv)
- [README](https://github.com/rivenmedia/riven/blob/main/README.md)
- [Releases](https://github.com/rivenmedia/riven/releases)
- [rivenmedia/riven on GitHub](https://github.com/rivenmedia/riven)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/rivenmedia-riven
