Install Jellyfin on Raspberry Pi

Why Raspberry Pi for Jellyfin?

A Raspberry Pi is the cheapest way to run a dedicated media server. A Pi 4 (4 GB) or Pi 5 handles direct play streaming to a handful of clients without breaking a sweat. Power consumption sits at 3-5 watts idle — roughly $5/year in electricity.

The catch: transcoding. The Pi’s VideoCore GPU can hardware-decode a limited set of codecs, but it cannot hardware-encode. If a client requests a format the Pi cannot direct-play, the ARM CPU handles it in software, and that is painfully slow. The strategy with a Pi is to avoid transcoding entirely — use clients that support direct play, and encode your library in widely compatible formats.

This guide covers Pi-specific Docker setup, V4L2 hardware decoding, storage, cooling, and what to realistically expect. For the general Jellyfin guide, see How to Self-Host Jellyfin with Docker.

Prerequisites

  • Raspberry Pi 4 (4 GB or 8 GB) or Raspberry Pi 5 (4 GB or 8 GB)
  • Raspberry Pi OS (64-bit, Bookworm) — the 64-bit image is required for the arm64 Docker image
  • Docker and Docker Compose installed (guide)
  • A USB 3.0 external drive or NAS mount for media storage (do NOT store media on the SD card)
  • Active cooling (heatsink + fan, or the official Pi 5 Active Cooler)
  • Wired Ethernet connection (Wi-Fi adds latency and limits throughput for HD streams)

Pi 4 vs Pi 5 for Jellyfin

CapabilityPi 4Pi 5
Hardware decode (V4L2)H.264 onlyH.264, HEVC (H.265)
Hardware encodeNoneNone
RAM options2/4/8 GB4/8 GB
USBUSB 3.0 (5 Gbps)USB 3.0 (5 Gbps, improved controller)
EthernetGigabitGigabit
Concurrent direct play streams1-22-3
Software transcoding1 stream (720p max)1 stream (1080p max, barely)

Recommendation: Get a Pi 5 if you are buying new. The HEVC decode support alone is worth it — most modern media is encoded in HEVC.

Platform Setup

Install 64-bit Raspberry Pi OS

Flash Raspberry Pi OS (64-bit, Lite) using the Raspberry Pi Imager. The Lite image (no desktop) is ideal for a headless server. Enable SSH during the flashing process.

Verify you are on 64-bit:

uname -m
# Expected: aarch64

If this shows armv7l, you are on 32-bit. Reflash with the 64-bit image.

Install Docker

curl -fsSL https://get.docker.com | sh
sudo usermod -aG docker $USER
# Log out and back in

Configure GPU Memory Split

The VideoCore GPU shares memory with the system. Allocate enough GPU memory for video processing:

# Edit the boot config
sudo nano /boot/firmware/config.txt

# Add or modify this line:
gpu_mem=256

Save and reboot. 256 MB gives the GPU enough memory for hardware decoding while leaving sufficient RAM for Jellyfin and the OS. On the 4 GB Pi 4, this leaves 3.75 GB for the system — tight but workable.

For the Pi 5, gpu_mem=256 is still appropriate. The Pi 5’s VideoCore VII is more capable but the memory allocation principle is the same.

Mount External Storage

Media libraries belong on a USB drive, not the SD card. The SD card is too slow for streaming and wears out under constant read I/O.

Plug in your USB drive and identify it:

lsblk
# Look for your drive — typically /dev/sda1

Create a mount point and mount it:

sudo mkdir -p /mnt/media
sudo mount /dev/sda1 /mnt/media

# Make it permanent (survives reboot)
echo "UUID=$(sudo blkid -s UUID -o value /dev/sda1) /mnt/media ext4 defaults,nofail 0 2" | sudo tee -a /etc/fstab

Replace ext4 with your filesystem type (ntfs-3g for NTFS, exfat for exFAT). Organize your media:

mkdir -p /mnt/media/movies /mnt/media/tv /mnt/media/music

Enable V4L2 Device Access

V4L2 (Video4Linux2) provides hardware video decoding on the Pi. Make sure the device nodes exist:

ls -la /dev/video*
# Should show /dev/video10, /dev/video11, /dev/video12, etc.

If no /dev/video* devices appear, load the V4L2 codec module:

# Pi 4
sudo modprobe bcm2835-codec

# Pi 5
sudo modprobe rpivid-mem

To load automatically on boot:

# Pi 4
echo "bcm2835-codec" | sudo tee -a /etc/modules

# Pi 5
echo "rpivid-mem" | sudo tee -a /etc/modules

Docker Compose Configuration

Create the Jellyfin directory:

mkdir -p /opt/jellyfin
cd /opt/jellyfin

Create docker-compose.yml:

services:
  jellyfin:
    image: jellyfin/jellyfin:10.11.6
    container_name: jellyfin
    user: "1000:1000"
    group_add:
      - "video"
    ports:
      - "8096:8096/tcp"
      - "7359:7359/udp"
    volumes:
      - jellyfin-config:/config
      - jellyfin-cache:/cache
      - /mnt/media/movies:/media/movies:ro
      - /mnt/media/tv:/media/tv:ro
      - /mnt/media/music:/media/music:ro
    environment:
      - JELLYFIN_PublishedServerUrl=http://YOUR_PI_IP:8096
    devices:
      - /dev/video10:/dev/video10
      - /dev/video11:/dev/video11
      - /dev/video12:/dev/video12
    restart: unless-stopped

volumes:
  jellyfin-config:
  jellyfin-cache:

Notes:

  • group_add: "video" — The video group owns the V4L2 devices on Raspberry Pi OS.
  • devices — Passes through V4L2 decoder nodes. The exact device numbers vary; check ls /dev/video* on your Pi. Pass through all video1* devices (typically video10, video11, video12).
  • user: "1000:1000" — Default Pi user. Verify with id.
  • Replace YOUR_PI_IP with your Pi’s LAN IP (e.g., 192.168.1.100).
  • Media volumes are :ro (read-only) — Jellyfin never writes to your media files.

Start the stack:

docker compose up -d

Verify it is running:

docker compose logs -f jellyfin

Wait for the line that says Jellyfin is listening on port 8096.

Hardware Transcoding Setup

What the Pi Can and Cannot Do

Be clear about this: the Raspberry Pi can hardware decode certain codecs, but it cannot hardware encode. This means:

  • Direct play (no transcoding): works perfectly. The Pi serves the file as-is. This is what you want.
  • Hardware decode + software encode: the Pi’s GPU decodes the source, but the CPU must encode the output. Usable for a single 720p stream on Pi 5, but stuttery. Not recommended.
  • Full software transcoding: both decode and encode on the CPU. Unusable for anything above 480p.

V4L2 Decode Capabilities

CodecPi 4Pi 5
H.264 (AVC)Hardware decodeHardware decode
HEVC (H.265)NoHardware decode
VP9NoNo
AV1NoNo
MPEG-2Hardware decode (requires license on Pi 4)Hardware decode

Configure V4L2 in Jellyfin

  1. Open http://YOUR_PI_IP:8096.
  2. Go to Dashboard > Playback > Transcoding.
  3. Set Hardware acceleration to Video Acceleration API (V4L2).
  4. Enable H.264 decoding (and HEVC if on Pi 5).
  5. Leave hardware encoding disabled — the Pi cannot encode in hardware.
  6. Set Transcoding thread count to 4 (matches the Pi’s quad-core CPU).
  7. Enable Throttle transcoding to prevent the CPU from overheating during the rare software encode.
  8. Click Save.

The Real Strategy: Avoid Transcoding

On a Pi, your goal is 100% direct play. Transcoding is the emergency fallback, not the primary path.

How to achieve direct play:

  • Use compatible clients. Jellyfin clients on Android TV, Fire TV, Apple TV, and most smart TVs support direct play for H.264 and HEVC. Web browsers are the worst — they trigger transcoding for almost anything that is not H.264 in an MP4 container.
  • Encode your library in H.264 MP4. This is the most universally compatible format. Every client, including web browsers, direct-plays H.264/AAC in an MP4 container.
  • Disable transcoding for users. Under Dashboard > Users > [user], you can disable transcoding entirely. The client either plays the file directly or shows an error. This prevents a single bad client from pegging the Pi’s CPU.
  • Set maximum bitrate per user. If you must allow transcoding, cap it at a bitrate the Pi can handle (e.g., 4 Mbps).

Cooling

The Pi 4 and Pi 5 both thermal-throttle under sustained load. Jellyfin’s metadata scanning and any transcoding will push the CPU to 100%, hitting 80-85C without active cooling.

Required: A heatsink and fan. For the Pi 5, the official Active Cooler ($5) is the best option. For the Pi 4, any aluminum heatsink case with a fan works.

Monitor temperature:

vcgencmd measure_temp
# Target: below 70C under sustained load

If you see temperatures above 80C during normal operation, your cooling is insufficient.

First-Time Setup

  1. Open http://YOUR_PI_IP:8096 in your browser.
  2. Select language.
  3. Create admin account.
  4. Add media libraries:
    • Movies — Content type: Movies, Folder: /media/movies
    • TV Shows — Content type: Shows, Folder: /media/tv
    • Music — Content type: Music, Folder: /media/music
  5. Set metadata language and country.
  6. Enable remote access if desired.
  7. Complete the wizard.

Important: The initial library scan fetches metadata from online sources and is CPU-intensive. On a Pi 4 with 5,000+ files, this takes 30-60 minutes. Let it finish before trying to stream anything — performance will be poor during the scan.

Troubleshooting

Playback Stutters or Buffers Constantly

Symptom: Video freezes every few seconds during playback.

Fix: Check Dashboard > Active Sessions. If it shows transcoding, that is the problem — the Pi cannot transcode fast enough. Solutions:

  1. Switch to a client that supports direct play (Android TV, Fire TV, iOS app).
  2. If using the web UI, try the Jellyfin Media Player desktop app instead — it supports more codecs natively.
  3. Re-encode the file to H.264/AAC in MP4 format using ffmpeg on another machine:
ffmpeg -i input.mkv -c:v libx264 -crf 22 -c:a aac -b:a 192k output.mp4

/dev/video Devices Missing

Symptom: No /dev/video* devices exist, or Jellyfin cannot use V4L2.

Fix: Load the kernel module:

# Pi 4
sudo modprobe bcm2835-codec

# Pi 5
sudo modprobe rpivid-mem

If the module fails to load, your kernel may not include V4L2 codec support. Ensure you are on the latest Raspberry Pi OS:

sudo apt update && sudo apt full-upgrade -y
sudo reboot

SD Card Wears Out or Corrupts

Symptom: Read-only filesystem errors, corrupted Jellyfin config, or the Pi won’t boot.

Fix: SD cards are not designed for the constant writes Jellyfin produces (transcoding cache, database updates, logs). Move the Jellyfin config volume to your USB drive:

volumes:
  - /mnt/media/jellyfin-config:/config  # Config on USB drive instead of SD card
  - /mnt/media/jellyfin-cache:/cache    # Cache on USB drive

Better yet, boot the Pi from USB entirely and eliminate the SD card. Raspberry Pi OS supports USB boot natively on Pi 4 and Pi 5.

Pi Overheats and Throttles

Symptom: vcgencmd measure_temp shows 80C+, and playback becomes choppy during peak usage.

Fix: Add active cooling. A passive heatsink alone is not sufficient for sustained Jellyfin workloads. The official Pi 5 Active Cooler or any heatsink-fan combo for Pi 4 keeps temperatures below 65C under load.

Also check that the Pi is not enclosed in a case with no ventilation.

Out of Memory Errors

Symptom: Jellyfin crashes or becomes unresponsive, dmesg shows OOM killer entries.

Fix: The 2 GB Pi 4 does not have enough RAM for Jellyfin with large libraries. Use a 4 GB or 8 GB model. On the 4 GB model, reduce gpu_mem to 128 if you are not using V4L2 hardware decoding, freeing an extra 128 MB for the system. Close any other services running on the Pi.

Comments