Ditch Plex: Building a Bulletproof Jellyfin Media Server on Linux

Reclaiming movie night from subscription creep

Contents

There was a golden age when Plex felt like magic: you pointed it at a folder of films, and suddenly your living room television displayed glossy posters, plot summaries, and trailers as if you ran a private streaming service. For a steady stream of long-time users that magic has slowly curdled into nagging account prompts, paywalled features, and the creeping sense that the software guarding your own files now answers to someone else. If you have started eyeing the monthly subscription column of your bank statement with suspicion, this guide is for you. We will build a media server that is genuinely yours, runs on a modest Linux box, transcodes video efficiently, and never once asks you to log in to a remote service to watch the films sitting on your own hard drive.

Why People Are Walking Away From Plex

Advertisement

Plex has not become a bad product overnight, but its centre of gravity has shifted. The most contentious change for hobbyists has been the requirement to authenticate against Plex’s own servers even to reach your local media, which means an outage or an account dispute on their side can lock you out of files you physically own. Layer on top of that the steady migration of once-free features behind the Plex Pass subscription: hardware transcoding, mobile downloads, and skip-intro detection have all become premium perks at one point or another.

The deeper objection is philosophical. A media server is supposed to be the very definition of self-reliant computing. When that server phones home, injects advertisements for content you did not ask for, and ties its core functionality to a company’s commercial roadmap, it stops being infrastructure and starts being a product you rent. None of this is a moral failing on Plex’s part, but it does explain why a steady stream of tinkerers have gone looking for something simpler.

What Jellyfin Actually Is

Jellyfin is a free, open-source media server that descends from Emby, which itself was once open before going proprietary. It does the same fundamental job as Plex: it scans your libraries, fetches artwork and metadata, organises everything into tidy collections, and streams to a wide range of clients. The crucial differences are that Jellyfin requires no account whatsoever, places every feature including hardware transcoding behind exactly zero paywalls, and keeps all communication on your own network unless you deliberately decide otherwise.

There are trade-offs to be honest about. The metadata matchers are occasionally less polished than Plex’s, the client ecosystem is broad but slightly less uniform, and you will not find a glossy onboarding experience that holds your hand. In exchange you get software that does what you tell it, stores its data where you can see it, and will keep working in five years regardless of anyone’s business model.

Installing With Docker Compose

Advertisement

The cleanest way to run Jellyfin on Linux is in a container, which keeps its dependencies isolated and makes upgrades a one-line affair. Assuming you already have Docker and the Compose plugin installed, create a directory and a docker-compose.yml file:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
services:
  jellyfin:
    image: jellyfin/jellyfin:latest
    container_name: jellyfin
    user: 1000:1000
    network_mode: host
    volumes:
      - ./config:/config
      - ./cache:/cache
      - /srv/media:/media
    devices:
      - /dev/dri:/dev/dri
    restart: unless-stopped

A few things deserve explanation. The network_mode: host line lets Jellyfin’s automatic discovery work properly so clients on your LAN can find it without fuss. The user: 1000:1000 value should match your own Linux user so the container does not create files owned by root in your media folders. The devices block exposes /dev/dri, which is what makes Intel hardware transcoding possible later. Adjust /srv/media to wherever your films and television live.

Bring it up and watch the logs:

1
2
docker compose up -d
docker compose logs -f jellyfin

Then open http://your-server-ip:8096 in a browser and follow the setup wizard, which will ask you to create an admin user and point at your library folders.

Organising Libraries and Naming Files

Jellyfin, like every media server, is only as clever as your file naming allows. The matchers rely on a tidy structure, so a few minutes spent on conventions saves hours of mismatched metadata later. For films, give each its own folder and include the year:

1
2
/media/Movies/Blade Runner (1982)/Blade Runner (1982).mkv
/media/Movies/Dune Part Two (2024)/Dune Part Two (2024).mkv

For television, the season-and-episode pattern is what the scanner looks for:

1
2
/media/TV/The Expanse/Season 01/The Expanse S01E01.mkv
/media/TV/The Expanse/Season 01/The Expanse S01E02.mkv

The year in parentheses disambiguates remakes, and the SxxExx token is the universal language every scanner understands. If a title still refuses to match, every item has an “Identify” option that lets you paste in the correct database entry by hand.

Hardware Transcoding With QSV and VAAPI

Transcoding is the act of re-encoding video on the fly when a client cannot play the original format or needs a lower bitrate over a weak connection. Done in software it will pin your processor and may stutter; done on dedicated silicon it is almost free. Most Intel processors from the last decade include Quick Sync Video, which Jellyfin can use through either the QSV or VAAPI driver.

After installing, go to Dashboard then Playback, set “Hardware acceleration” to “Intel QuickSync (QSV)” or “Video Acceleration API (VAAPI)”, and point the VAAPI device at /dev/dri/renderD128. Enable the codecs you want to offload, typically H.264 and HEVC. On the host you can confirm the device is present:

1
2
3
ls -l /dev/dri
sudo apt install intel-gpu-tools
sudo intel_gpu_top

That last command gives you a live view of the GPU’s render engine, so when you start a transcode you should see the “Render/3D” or “Video” engines light up. If they stay flat, transcoding is still happening on the CPU and the device passthrough needs revisiting.

Clients for Television, Mobile, and Web

A server is only useful if you can reach it from the sofa. The web interface works in any browser and is the natural fallback. For televisions, Jellyfin has native apps on Android TV, Fire TV, and webOS, and the third-party Swiftfin app covers Apple TV nicely. On phones and tablets, the official Jellyfin app handles streaming and offline downloads, while power users on Android often prefer Findroid for its slicker interface.

The pleasant surprise is that none of these clients require a subscription to unlock features. Direct play, downloads, and transcoding all work out of the box. The one area where you should temper expectations is consistency: because the apps come from different developers, small interface differences exist between platforms.

Reaching It From Outside, Safely

Here is the rule that keeps people out of trouble: do not expose your Jellyfin port directly to the internet. An open 8096 is an invitation, and a media server full of personal libraries is not something you want probed by every scanner on the web. There are two sane approaches.

The first is a reverse proxy such as Caddy or Nginx that terminates HTTPS and sits in front of Jellyfin, giving you a proper certificate and a single hardened entry point. If you go this route, do not stop at TLS — anything exposed to the public internet gets brute-forced within hours, so put rate-limiting and ban tooling in front of the login page, as I cover in keeping the bots out with fail2ban and CrowdSec. The second, and arguably better for purely personal use, is a VPN like WireGuard: you connect your phone to your home network first, then reach Jellyfin exactly as if you were on the sofa. The VPN approach exposes nothing publicly at all, which is the strongest position you can take. A Jellyfin server is, after all, just one more self-hosted service on your LAN, and the same network-hygiene thinking that applies to building your own Nextcloud applies here too: the fewer ports you open to the world, the smaller your problem.

When Things Go Wrong

Three failures account for most of the support threads, and all three are quick to diagnose once you know the shape.

Transcoding silently falls back to CPU. You set hardware acceleration in the dashboard, but playback still pins a core and stutters. The usual cause is permissions: the container user (1000:1000 above) is not a member of the render group that owns /dev/dri/renderD128. Check the device’s group on the host with ls -l /dev/dri, find that group’s numeric ID with getent group render, and add group_add: ["<that-gid>"] to the compose service. Restart, start a transcode, and watch intel_gpu_top — the Video engine should now climb.

Libraries scan but show no artwork. This is almost always file naming, not a broken metadata provider. A film sitting loose in a folder called Movies with a filename full of release-group tags will not match. Move it into its own Title (Year) folder as shown earlier and trigger a rescan. If a single stubborn title refuses, use the per-item “Identify” button to paste the correct database match by hand.

Clients on the LAN can’t find the server. If you dropped network_mode: host, Jellyfin’s auto-discovery broadcast no longer reaches the network, and TV apps won’t list the server automatically. Either restore host networking or simply type the http://server-ip:8096 address into the client manually — discovery is a convenience, not a requirement.

Plugins and a Realistic Verdict

Jellyfin’s plugin catalogue adds the niceties: better metadata providers, subtitle fetching through OpenSubtitles, intro detection so you can skip the recap, and trakt synchronisation for tracking what you have watched. Install them from Dashboard then Plugins, and restart the server when prompted.

One last piece of housekeeping that pays for itself the first time something corrupts: back up the config directory. Your media files are replaceable in principle, but the config volume holds your users, watch history, library structure, and metadata edits — months of accumulated state that is genuinely painful to rebuild. A nightly tar of ./config to another disk, or a snapshot if your filesystem supports it, turns a catastrophic “I have to set everything up again” into a five-minute restore. Stop the container first so you capture a consistent copy rather than a database mid-write. It is the least glamorous part of running your own server and the part you will be most grateful for.

So is it worth the switch? If you want a zero-effort appliance that simply works and you do not mind a subscription, Plex remains polished. But if you value owning your stack, refuse to pay for transcoding, and want software that will never lock you out of your own films, Jellyfin is the clear choice. It asks a little more setup up front and rewards you with a media server that answers to nobody but you. Movie night, reclaimed.

For the person on the fence, my practical advice is to run both for a week. Keep Plex pointed at your library, stand Jellyfin up alongside it in the container above, and let the household actually use both on the same television. You’ll learn very quickly whether the rough edges that get written up in forum threads matter to you or not — and in my experience, once people have lived with software that never interrupts a film to advertise an upsell, the rough edges stop feeling like a sacrifice and start feeling like the price of ownership. That trial costs you an evening and settles the question far better than any guide can.

Advertisement
Advertisement
Smarc
Written by Smarc

Founder and editor of vo.rs. A lifelong tinkerer who self-hosts far more than is sensible, hardens Linux boxes for fun, and prods the latest AI tools to see what they can really do. The how-to guides here are the notes Smarc wishes had existed the first time round.