Kituwa IT · Self-hosting guides

Install Jellyfin with Docker Compose

Self-hosted media streaming server

media serverstreamingtranscoding

Jellyfin is a free software media server — movies, shows, music, photos — with apps for basically every device and no premium tier, no code signing requirement, and no account. It transcodes on the fly so a 4K remux plays on a five-year-old phone.

Category
Media & photos
License
GPL-3.0
Needs
GPU (optional)
Image
jellyfin/jellyfin

What it is

Point it at a directory of files, it indexes them, groups them into libraries, and serves them to web, Android, iOS, Roku, Fire TV, and anything with a browser. Hardware transcoding is the difference between smooth playback and a buffering wheel, and it's supported for Intel QuickSync, NVIDIA and AMD.

Before you start

  • Give the container --device=/dev/dri for hardware transcoding. Without it, everything runs on the CPU and a 4K stream will stutter.
  • Use READONLY on the media mount. Nothing should ever be able to write to your film library from a streaming client.
  • Don't try to transcode while seeding or if the host is doing other heavy work. Jellyfin will happily use every core and starve the rest of the server. Cap the transcode threads in the dashboard.

1 — Create the directories

Command / configuration
mkdir -p ~/services/jellyfin/{config,cache,media}
# point "media" at your real library, e.g.
# ln -s /mnt/bigdisk/media ~/services/jellyfin/media/library
cd ~/services/jellyfin

2 — Write the compose file

Command / configuration
services:
  jellyfin:
    image: jellyfin/jellyfin:latest
    container_name: jellyfin
    restart: unless-stopped
    user: "1000:1000"
    devices:
      - /dev/dri:/dev/dri
    group_add:
      - "${RENDER_GID:-104}"
    ports:
      - "127.0.0.1:8096:8096"
    volumes:
      - ./config:/config
      - ./cache:/cache
      - ./media:/media:ro
    environment:
      TZ: UTC
      JELLYFIN_PublishedServerUrl: https://tv.example.com
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:8096/health"]
      interval: 60s
      timeout: 10s
      retries: 5
      start_period: 60s

3 — Start it

Command / configuration
docker compose up -d
docker compose logs -f jellyfin | grep -i "listening\|ffmpeg\|error"

4 — First-run setup

  1. Open http://yourhost:8096 and set the language and admin account. There's no default password, so the first account you make is the admin.
  2. Add your media paths under Dashboard → Libraries. Use one folder per library so Jellyfin can infer the type — /media/movies, /media/tv, /media/music.
  3. Enable hardware acceleration in Dashboard → Playback → Transcoding. For an Intel iGPU choose QuickSync (VAAPI) with the /dev/dri/renderD128 device; for NVIDIA pick NVENC and pass the render device through.
  4. Under Dashboard → Users, create a non-admin account for family members. Admin users can change server settings; you don't want that on the TV.
  5. Verify transcoding is actually being used: play a 4K file on a low-power client and watch for a "Transcoding" indicator, then check the dashboard's Active sessions.

5 — Keep it tidy

Command / configuration
# run the library scan on a schedule instead of watching it churn
docker exec jellyfin curl -s http://localhost:8096/ScheduledTasks

# pre-optimize direct play profiles so phones don't transcode needlessly
# Settings → Playback → Transcoding → create an Android profile at 720p
Client-side remux beats server-side transcodeIf your clients can handle the codec directly, they'll skip transcoding entirely. In the client settings, turn off things like "Video quality = auto" that force a transcode for no reason. Direct play at 100Mbps is far better than transcoding at 720p.

Help when you need it

Want help getting this running?

We can help with a supported Linux host, application setup, migration or troubleshooting. Contact us to confirm the software, scope and scheduling before ordering.

Related guides

← Browse all 30 guides · Back to top