Operator-owned sources
These are the only sources the backend itself serves, because they are media you control rather than third-party sites. All three are optional and off until configured.
Local · your own files
Section titled “Local · your own files”Plays files from directories or NAS mounts you register, with seeking (HTTP Range). Browser-native files (mp4, m4v, mov, webm) play directly. With a source’s encoding toggle on, non-web containers (mkv, avi, ts and others) are transcoded to HLS on the fly.
- Bind-mount your media into the backend container so it can read it:
# in the backend service's docker-composevolumes:- /mnt/media:/media:ro
- In admin dashboard → sources, register the path (e.g.
/media) and enable it. Optionally turn encoding on for that source to also play non-web containers (needsffmpeg, which is in the image). - The backend matches a requested title or episode to a file by fuzzy-matching folder
and file names (it understands
S01E02,1x02,Season 2folders and similar). Matched files are served via/local_proxy(direct) or/local_hls(transcode).
Local only appears when at least one local source is enabled. Every request re-checks that the path stays inside the root, so path traversal and symlink escapes fail.
Cache · replay what was watched
Section titled “Cache · replay what was watched”The optional cache worker downloads a played stream (remuxed to mp4 with ffmpeg) onto a NAS target you register, then replays it from disk as a named source. Over time a flaky remote stream becomes a fast local one.
- Make sure ffmpeg is available (it is in the backend image).
- Run the downloader on one replica:
RUN_CACHE_WORKER=truethere,falseeverywhere else. Tune it with theCACHE_*variables (see Backend environment). - In the admin dashboard, enable caching and register a NAS target with a display
name. Played episodes download in the background, then appear as a source labelled
with that target’s name, served via
/cache_proxy.
Caching starts only after a few seconds of actual playback, so briefly opening a title does not trigger a download. Edge-offloaded and client-resolved streams are not cached on purpose: caching them would pull the bytes back through the backend and undo the offload.
Jellyfin · your own media server
Section titled “Jellyfin · your own media server”Streams from your own Jellyfin server. The backend matches a title by its TMDB id, picks direct play or HLS, and injects the access token server-side so it never reaches the browser.
JELLYFIN_URL=https://jellyfin.example.com # reachable from the backendJELLYFIN_USERNAME=crimsonJELLYFIN_PASSWORD=...By default the backend proxies the stream (/jellyfin_proxy). To move those bytes off
the backend too, set JELLYFIN_EDGE_INJECT=true and deploy the
proxy with NITRO_JELLYFIN_*.
The edge then injects the token and the bytes flow Jellyfin → edge → viewer.
What about other secret-bound sources?
Section titled “What about other secret-bound sources?”Some setups run a source that needs a server-held secret. The backend does only the
resolve (keeping the secret) and the client delivers the bytes, via the /resolve
grant. That wiring is operator-specific: it lives in your own private
sources engine plus the matching secret in your backend
environment. It is not part of the public stack, so it is not listed here.
