← Field Notes
Published Last updated 6 min read

Why I Self-Host Jellyfin

Why I chose Jellyfin for my media library and what running it taught me about storage, containers, networking, metadata, and client devices.

In this article
  1. I wanted ownership of the library
  2. Jellyfin became a storage project
  3. Containers made deployment clearer
  4. Remote access added another system
  5. Metadata is its own system
  6. Client devices matter more than expected
  7. Key takeaways
  8. What I would do differently
  9. Why I keep using it
  10. AI transparency

Streaming services are convenient, but convenience is not the same thing as control.

Titles move between platforms, subscriptions multiply, interfaces change, and a library that feels stable one month can be scattered across several services the next. I wanted one place where the organization, metadata, users, and playback experience were mine to manage.

That is what led me to Jellyfin.

It began as a way to stream my own media, but it quickly became one of the most useful projects in my homelab. Running it forced me to learn how storage, containers, networking, permissions, metadata, and client devices fit together.

I wanted ownership of the library

The biggest reason was simple: I wanted my media library to behave like a library.

I wanted consistent posters, collections, seasons, watch history, user profiles, and a structure I could improve without waiting for a streaming provider to support it. Jellyfin gave me control over how content was named, grouped, displayed, and accessed.

That control also means the mistakes are mine.

A badly named folder can create the wrong match. A plugin can sort episodes incorrectly. A storage path can disappear. A client device can behave differently from a browser. Self-hosting removes a provider from the middle, but it does not remove the work.

For me, that tradeoff is worth it.

Jellyfin became a storage project

A media server is only as reliable as the storage behind it.

My library eventually grew beyond a single machine into a setup where storage is shared across hosts. That meant thinking about mount points, permissions, network shares, and what happens when one server starts before another is ready.

Jellyfin does not care that a path used to exist. If the media mount is missing when the container starts, the library can appear empty or unavailable. Storage health and mount verification therefore became part of the application rather than a separate concern.

The container paths make those dependencies visible:

/config  -> persistent Jellyfin configuration and database
/cache   -> regenerable cache and transcoding data
/media   -> required media mount from shared storage

The media files matter, but so do Jellyfin’s configuration, database, artwork, users, and watch history. Rebuilding the application is easy compared with rebuilding the context around the library.

Containers made deployment clearer

I run Jellyfin in a container because it separates the application from the host and makes the important paths explicit.

Configuration, cache, and media are mapped intentionally. That makes it easier to understand what must persist, what can be regenerated, and what needs to be available before the service starts.

Containers did not eliminate troubleshooting. They changed the questions:

  • Is the container healthy?
  • Is the media path mounted inside it?
  • Does the container user have access?
  • Is hardware acceleration available?
  • Is the reverse proxy reaching the correct port?
  • Is the problem on the server or only on one client?

That way of thinking has carried into nearly every other self-hosted service I run.

Remote access added another system

Watching Jellyfin at home is straightforward. Making it securely and reliably available away from home introduces DNS, TLS, reverse proxies, routing, and bandwidth.

A successful connection does not guarantee successful playback. The server may be reachable while a high-bitrate file still buffers. A browser may direct-play something that a television app insists on transcoding. A remote client may expose a networking problem that never appears on the local network.

Those differences taught me to separate availability from performance.

I now troubleshoot the path in order:

  1. Can the client reach the server?
  2. Can the server reach the media file?
  3. Can the client direct-play the format?
  4. If transcoding is required, can the server handle it efficiently?

That sequence keeps me from blaming the server for every playback problem.

Metadata is its own system

Before running Jellyfin, I underestimated how much work goes into making a library feel orderly.

File names, folder structure, season numbering, metadata providers, artwork, plugins, and display order all influence the result. When one piece is wrong, the interface can make correct media look completely broken.

This became especially obvious with less conventional libraries and plugin-provided content. Episodes can appear out of order, seasons can disappear, and titles can be grouped in ways that make sense to the source but not to the viewer.

The lesson was that presentation problems often begin as data problems.

Changing a sort option may hide the symptom, but reliable organization usually starts with consistent identifiers and structure.

Client devices matter more than expected

A media server is not experienced on the server. It is experienced through the client.

Jellyfin can work perfectly in a desktop browser while behaving poorly on an older television or streaming stick. Codec support, memory, network quality, and the client application’s implementation all affect playback.

That is why testing from one device is not enough.

When playback freezes on a television but works on a PC, the server is only one possible cause. The client may be unable to direct-play the stream, a plugin may expose a format the television handles poorly, or the device may simply be underpowered.

The best fix is not always a larger server. Sometimes it is a better client.

Key takeaways

  • Self-hosting trades provider control for direct responsibility over the system.
  • Storage mounts, permissions, and persistent application data are part of Jellyfin’s reliability.
  • Reachability and playback performance are separate troubleshooting stages.
  • Metadata and folder structure can cause problems that look like interface bugs.
  • The weakest client device may shape the practical limits of the whole setup.

What I would do differently

I would design storage checks and backups before importing the full library instead of adding them after the first failure.

I would also test early on the least capable client I expected my family to use. A desktop browser is a useful baseline, but it is not representative of every television or streaming stick.

Finally, I would keep metadata troubleshooting separate from playback troubleshooting. They meet in the same interface, but they are usually different problems.

Why I keep using it

Jellyfin gives me a media system I can understand and shape.

It is not effortless, and that is partly the point. Storage failures became lessons in mounts and dependencies. Remote playback became a lesson in reverse proxies and bandwidth. Incorrect episode ordering became a lesson in metadata and application design.

The result is more than a replacement streaming interface. It connects nearly every part of my homelab while producing something my family can actually use.

That combination—practical enough to matter and complicated enough to teach—is why I continue to self-host Jellyfin.

AI transparency

AI assisted with organizing and editing this article. The Jellyfin deployment, storage layout, networking problems, plugin behavior, client testing, and conclusions described here are based on my own homelab experience.

JO

Written by

Jessie Owens

I run Eldritch IT and write about the systems, repairs, infrastructure decisions, and business lessons behind the work.