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
| Capability | Pi 4 | Pi 5 |
|---|---|---|
| Hardware decode (V4L2) | H.264 only | H.264, HEVC (H.265) |
| Hardware encode | None | None |
| RAM options | 2/4/8 GB | 4/8 GB |
| USB | USB 3.0 (5 Gbps) | USB 3.0 (5 Gbps, improved controller) |
| Ethernet | Gigabit | Gigabit |
| Concurrent direct play streams | 1-2 | 2-3 |
| Software transcoding | 1 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"— Thevideogroup owns the V4L2 devices on Raspberry Pi OS.devices— Passes through V4L2 decoder nodes. The exact device numbers vary; checkls /dev/video*on your Pi. Pass through allvideo1*devices (typicallyvideo10,video11,video12).user: "1000:1000"— Default Pi user. Verify withid.- Replace
YOUR_PI_IPwith 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
| Codec | Pi 4 | Pi 5 |
|---|---|---|
| H.264 (AVC) | Hardware decode | Hardware decode |
| HEVC (H.265) | No | Hardware decode |
| VP9 | No | No |
| AV1 | No | No |
| MPEG-2 | Hardware decode (requires license on Pi 4) | Hardware decode |
Configure V4L2 in Jellyfin
- Open
http://YOUR_PI_IP:8096. - Go to Dashboard > Playback > Transcoding.
- Set Hardware acceleration to
Video Acceleration API (V4L2). - Enable H.264 decoding (and HEVC if on Pi 5).
- Leave hardware encoding disabled — the Pi cannot encode in hardware.
- Set Transcoding thread count to
4(matches the Pi’s quad-core CPU). - Enable Throttle transcoding to prevent the CPU from overheating during the rare software encode.
- 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
- Open
http://YOUR_PI_IP:8096in your browser. - Select language.
- Create admin account.
- 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
- Movies — Content type: Movies, Folder:
- Set metadata language and country.
- Enable remote access if desired.
- 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:
- Switch to a client that supports direct play (Android TV, Fire TV, iOS app).
- If using the web UI, try the Jellyfin Media Player desktop app instead — it supports more codecs natively.
- Re-encode the file to H.264/AAC in MP4 format using
ffmpegon 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.
Related
Get self-hosting tips in your inbox
Get the Docker Compose configs, hardware picks, and setup shortcuts we don't put in articles. Weekly. No spam.
Comments