DEV Community

Cover image for Build Your Own Media Server with Jellyfin and Docker
FlatlinerAtheist | CLI-NERDS
FlatlinerAtheist | CLI-NERDS

Posted on Edited on Originally published at clinerds.com

Build Your Own Media Server with Jellyfin and Docker

Streaming subscriptions are convenient until a film disappears, a show moves to another service, or you realize your own media collection is sitting on a hard drive doing nothing. Jellyfin is a free, open-source media server that lets you stream that collection to your browser, TV, phone, and other clients — without an account at a media company.

It is also a good first self-hosting project: useful immediately, easy to run in Docker, and forgiving enough to learn on.

Before installing: organize the media

Jellyfin can fetch artwork and metadata, but it needs to identify what it is looking at. A simple structure prevents hours of mismatched titles:

/srv/media/
├── Movies/
│   └── Example Film (2024)/
│       └── Example Film (2024).mkv
└── Shows/
    └── Example Show/
        └── Season 01/
            └── Example Show - S01E01.mkv
Enter fullscreen mode Exit fullscreen mode

Use your real titles, of course. Keep films and shows in separate libraries. Read-only media mounts are a sensible default: Jellyfin needs to read your collection, not reorganize or delete it.

Run Jellyfin with Docker Compose

Create a compose.yaml:

services:
  jellyfin:
    image: jellyfin/jellyfin:latest
    container_name: jellyfin
    user: 1000:1000
    restart: unless-stopped
    volumes:
      - /srv/jellyfin/config:/config
      - /srv/jellyfin/cache:/cache
      - /srv/media:/media:ro
    ports:
      - "8096:8096"
Enter fullscreen mode Exit fullscreen mode

Create the writable directories, make sure UID/GID 1000 owns them, then start the service:

sudo mkdir -p /srv/jellyfin/{config,cache}
sudo chown -R 1000:1000 /srv/jellyfin
docker compose up -d
Enter fullscreen mode Exit fullscreen mode

Open http://server-ip:8096. Create the administrator account, add libraries pointing to /media/Movies and /media/Shows, and let the initial scan finish.

For a long-lived installation, replace latest with a release you have tested, and upgrade deliberately rather than pulling random updates every night.

Direct play first, transcoding second

The smoothest playback happens when the client supports the file directly. Transcoding converts video in real time when it does not, and high-resolution software transcoding can overwhelm an otherwise capable little server.

If you have a supported Intel or AMD GPU, hardware acceleration can help. On Linux, that commonly means passing the render device into the container:

    devices:
      - /dev/dri:/dev/dri
Enter fullscreen mode Exit fullscreen mode

Add that only if /dev/dri exists, then enable the appropriate acceleration method in Jellyfin's playback settings. The exact driver and permissions vary by hardware. Check the server dashboard's transcoding logs if playback still maxes out the CPU.

For remote viewing, a modest upload speed matters more than a powerful processor. Lower the client's streaming bitrate instead of expecting your home connection to perform miracles.

Make the library pleasant to use

Install the official Jellyfin client for your TV or streaming device where one is available, and test direct playback with a representative file before importing everything. A phone browser is useful for setup, but TV clients have different codec and subtitle support.

After the first scan, check a handful of titles for incorrect matches. Fix folder names or use the library's identify function rather than editing dozens of metadata fields manually. Keep extras and different editions separated clearly so the scanner does not merge them into a confusing entry.

Schedule library scans and metadata refreshes for a quiet time if the server runs on a small disk or low-power CPU. Also watch the config partition's free space: transcoding cache and logs should not be allowed to fill it. A full system disk can make an otherwise healthy media server look broken.

Keep it private and recoverable

Do not forward port 8096 to the internet just because remote access sounds useful. A private overlay such as Tailscale is a cleaner default for personal viewing.

Back up /srv/jellyfin/config as well as any custom metadata and artwork you care about. Your media files need their own backup too — a server disk is not a backup. The 3-2-1 backup strategy is a good model.

Finally, keep Jellyfin updated, use separate accounts for viewers, and leave remote administration disabled unless you need it. The goal is a boring media appliance: press play, watch your stuff, and spend your weekend enjoying the library instead of maintaining it.

Top comments (0)