Video and music streaming runs on Jellyfin, an open-source media server. Here's how it's configured, especially the GPU hardware transcoding.
Image: Jellyfin logo (CC BY-SA 4.0) / NVIDIA logo (Apache 2.0), Wikimedia Commons
Diagram: Duskcoil. It shows the branch between Direct Play and GPU hardware transcoding.
Jellyfin: A Self-Hosted Media Server
Jellyfin is media server software that lets various supported clients — phone apps, smart TVs, browsers — reach the video and music library stored on the home server. Unlike a commercial service, no viewing history or library contents are ever sent out externally.
GPU Hardware Transcoding
Depending on the client's playback environment (resolution, supported codecs, bandwidth), sending the original file as-is isn't always an option — it needs to be re-encoded (transcoded) in real time during playback. Doing that on the CPU is heavy, and quickly becomes a limit on both simultaneous playback count and picture quality.
To get around that, the NVIDIA GPU's hardware encoder (NVENC) is passed directly into the container (GPU passthrough), and transcoding runs on the GPU instead. Concretely, the container runtime reserves the NVIDIA driver device with three capabilities — gpu, compute, and video — so the physical GPU's video-encoding function can be called directly from inside the container. Compared to CPU transcoding, this wins on both power consumption and processing time, and comfortably handles simultaneous access from multiple clients.
Choosing the Network Mode and Memory Limit
Jellyfin's container shares the host's network rather than running in bridge mode. That's because the mechanism clients on the local network (smart TVs, phone apps) use to auto-discover the Jellyfin server (UDP broadcast discovery) doesn't work correctly under a normal bridge network — for a media-streaming use case, the convenience of auto-discovery won out. Alongside that, an explicit memory limit is set per container, so that scanning a large library or transcoding doesn't squeeze the memory available to other containers.
A Missed Exposure, and Fixing It
When the whole server's listen settings got audited across the board, it turned out Jellyfin, too, was directly reachable from every device on the same network rather than being loopback-only. That's not a setting the GUI admin panel exposes — the fix meant editing the container's internal config file directly to add the loopback address to the allowlist. Given the nature of a video/music library, there's real risk in viewing history and the library's contents being visible from outside; it got fixed to the same standard as every other self-hosted service here.
There was also an incident where the externally facing reverse-proxy/tunnel configuration got accidentally overwritten while working on an unrelated service, temporarily knocking out external access to Jellyfin. Recovering from it surfaced a constraint: giving the externally facing listener and Jellyfin's own listen port the same number causes an error at the TLS-handshake stage. Since then, the externally visible number and the number actually used inside the container are deliberately kept separate — the same "external/internal port split" pattern that shows up across every other service on this server.
While cleaning this up, another misconfiguration turned up: the integrated dashboard's link to Jellyfin, missing an explicit port number, happened to coincide with where a completely different service (the publicly exposed home-automation platform) was reachable. Since the link itself didn't error out — it just silently pointed at the wrong service — nobody noticed for a while, since it was never actually clicked and checked.
The One App That Turned Out to Support Subpath Serving
As part of an effort to consolidate several services behind a single exposed port (see the access control article), Jellyfin turned out to be one of the rare exceptions with official support for a Base URL setting — a way to prepend an arbitrary prefix to the paths it serves under. Most other self-hosted apps don't officially support subpath serving, so this couldn't be used as a general-purpose solution — but Jellyfin and the integrated dashboard are the two services that get to share a single exposed port, purely because this feature exists.