Jellyfin — playback of the Nextcloud content
Status: deployed. Confirmed by the user on 2026-09-04, together with the fact that Nextcloud content was connected to Jellyfin.
⚠️ The concrete values are TO CONFIRM. This file collects what is confirmed and what can be deduced from the rest of the documentation; every gap is marked. Do not take as true anything carrying
TO CONFIRM.
The underlying decision — separating storing from playing
Section titled “The underlying decision — separating storing from playing”Nextcloud AIO → storage, organisation, sharing, synchronisationJellyfin → playback, catalogue, TV and mobile clients └──────── both over the SAME files, on the 1 TB HDDThis had been floated as an idea since 2026-08-26 and came from a real problem: an HEVC/H.265 4K video at ~60 fps uploaded to Nextcloud gave audio with no picture in the browser. It was not corruption of the upload, it was the codec — the Nextcloud web viewer is not a player. Jellyfin is.
Why not duplicate the files: they are ~129 GB. A second copy for Jellyfin would double the HDD usage and, worse, would create two truths about the same content.
The delicate point: datadir permissions
Section titled “The delicate point: datadir permissions”This is what has to be understood before touching anything. The Nextcloud datadir has deliberately restrictive permissions:
/mnt/storage/nextcloud/data UID 33 (www-data) · GID 0 · mode 750 └── <user>/files/... ← the real structure where the files liveMode 750 means that only UID 33 and GID 0 can read. A Jellyfin
container with LinuxServer.io’s default PUID/PGID (1000:1000) cannot
read anything there. It has to be resolved, and how it was resolved
matters:
| Option | Consequence |
|---|---|
PUID=33 / PGID=0 in Jellyfin |
Works; Jellyfin runs with Nextcloud’s identity |
| Adding GID 0 as a supplementary group | Works; gives the container membership of the root group |
Loosening the datadir to 755 |
Works, but degrades Nextcloud’s posture — avoid |
⚠️ TO CONFIRM: which of the three was used.
Read-only mount — this is not optional
Section titled “Read-only mount — this is not optional”volumes: - /mnt/storage/nextcloud/data:/media:ro # ← the :ro is the important partWhy :ro: Nextcloud keeps its own database of the file tree. Any
external write in the datadir puts it out of sync, and recovery means an
occ files:scan over 129 GB. Jellyfin has no reason whatsoever to write
there — its metadata and cover art go to its own configuration volume.
⚠️ TO CONFIRM: the real mount path and whether the whole datadir was mounted or only one user’s folder.
Image and stack
Section titled “Image and stack”By the homelab convention, the image should be LinuxServer.io’s:
lscr.io/linuxserver/jellyfin (by convention — TO CONFIRM)/opt/stacks/jellyfin/ (by the /opt/stacks/<service> convention)⚠️ TO CONFIRM: the real image and tag, and whether the stack follows the directory convention.
Network and publishing
Section titled “Network and publishing”⚠️ TO CONFIRM — and it is the question with the most consequences.
The two options consistent with the network design (see
../infra/networking.md):
A) Published by Caddy jellyfin.balserosworld.net → jellyfin:8096 · follows the pattern of all the other services (NET-06, NET-08) · needs a block in the Caddyfile + a DNS record · reachable from TV clients on the LAN by name
B) Tailscale only no block in Caddy, no published port · more closed, but TV clients do not usually have TailscaleIf (A) was chosen, the site has to be added to ../services/caddy.md and to
the Caddyfile table. If Jellyfin publishes ports: on the LAN without going
through Caddy, that contradicts NET-08 and it is worth noting it as a
conscious exception, just as was done with Nextcloud AIO.
Transcoding and GPU
Section titled “Transcoding and GPU”The video that started all this was 4K60 HEVC ~61 Mb/s. The rule adopted from the start: prefer Direct Play, and do not rely on the CPU to transcode without having measured — the Ryzen 3 2200G has 4 threads and already sustains all the rest of the homelab.
The 3 GB GTX 1060 is physically present and unassigned; the initial homelab audit pointed to it precisely for NVENC in Jellyfin. Doing passthrough would involve IOMMU (already enabled) and isolating the GPU from the host.
⚠️ TO CONFIRM: whether passthrough of the GTX 1060 was done, or whether Jellyfin runs only with Direct Play / CPU transcoding.
Backup
Section titled “Backup”- Configuration and metadata: if the stack is in
/opt/stacks/jellyfin, it already falls under Layer 2 without touching anything — that path is a source ofborg-backup.sh. - The media content: it is already covered by Nextcloud AIO’s native backup. Do not add it as a separate source — it would mean backing up the same 129 GB twice.
It is one of the advantages of not duplicating the files: Jellyfin adds practically nothing to the backup volume.
To close out this file
Section titled “To close out this file”Run on docker-host and dump here whatever comes out:
ls -la /opt/stacks/jellyfingrep -v -iE 'token|password|key|secret' /opt/stacks/jellyfin/compose.yamldocker ps --format '{{.Names}}\t{{.Image}}\t{{.Ports}}' | grep -i jellygrep -A4 -i jelly /opt/stacks/caddy/Caddyfile