- Home
- Learn Linux
- Learn Electronics
- Raspberry Pi
- Programming
- Projects
- LPI certification
- News & Reviews
This guide accompanies the final part of our home server series, where we transform our Raspberry Pi Compute Module 4 into a high-performance media powerhouse using Jellyfin. Whether you are using a CM4, a Raspberry Pi 4, or the newer Pi 5, this page provides the essential scripts, Docker configurations, and optimization tips to get your media library up and running smoothly.
Note: For the full hardware setup and initial OS configuration, please refer to the previous parts of this series. Part 1 to set your EEPROM boot and install the Operating system, Part 2 for setting up as a NAS, installing Docker and adding a Web Dashboard.
Before deploying the server, create a dedicated directory on your NVMe drive to store JellyFin's configuration data.
mkdir -p ~/docker_data/jellyfin
Navigate to Stacks in Portainer and use the following YAML configuration to deploy JellyFin.
Note on Permissions: This setup uses User ID 1000, the default for the first Raspberry Pi OS user. The media folders are mounted as Read-Only (:ro) for security.
You will also need to insert the correct username and update the media directories to match your own server setup. You should also insert the IP address of your server, this was covered in the Raspberry Pi Home Server OS guide.
version: '3.8'
services:
jellyfin:
image: jellyfin/jellyfin:latest
container_name: jellyfin
user: 1000:1000
group_add:
- "44" # Grants access to /dev/video*
- "992" # Grants access to /dev/dri
network_mode: host
volumes:
- /home/<username>/docker_data/jellyfin:/config
- /home/<username>/docker_data/jellyfin/cache:/cache
- /home/<username>/docker_data/jellyfin/transcoding-temp:/transcode
- /extdata/tv-film:/data/movies:ro
- /extdata/music:/data/music:ro
- /extdata/photos:/data/photos:ro
environment:
- JELLYFIN_PublishedServerUrl=192.168.0.2
devices:
- /dev/video10:/dev/video10
- /dev/video11:/dev/video11
- /dev/video12:/dev/video12
- /dev/dri:/dev/dri
restart: 'unless-stopped'
The group_add and devices sections of the YAML configuration are for the Raspberry Pi 4 / Raspberry Pi compute module 4 to allow it to make use of the hardware decoding and encoding libraries. This is not included in the Raspberry Pi 5 which will need to use software based encoding only.
For better performance on both a Raspberry Pi 4 and Raspberry Pi 5 then you may wish to transcode the files into H.264. This is explained next.
If you are using a Raspberry Pi 5, hardware acceleration is currently handled via software or requires different configurations. The most "bulletproof" method for any Pi version is to re-encode incompatible files into H.264.
Run this script in your media folder to identify which files might cause playback lag.
#!/bin/bash
shopt -s nullglob
for file in *.{mp4,avi,mkv,mov}; do
codec=$(ffprobe -v error -select_streams v:0 -show_entries stream=codec_name -of default=noprint_wrappers=1:nokey=1 "$file" 2>/dev/null)
echo "$file ---> $codec"
done
It is recommended to run heavy conversions on a more powerful PC rather than the Pi itself. In my case running on a Desktop PC with a GPU graphics card and Ubuntu Linux. This script uses NVIDIA hardware acceleration (cuda); remove -hwaccel cuda if using a standard CPU.
#!/bin/bash
# Check if the "converted" directory does NOT exist
if [ ! -d "converted" ]; then
mkdir "converted"
echo "Created 'converted' directory."
else
# Directory exists, prompt the user for confirmation
read -p "converted directory already exists. Continue? (Y/N): " answer
case "$answer" in
[Yy]* )
# User answered yes, do nothing and let the script continue
echo "Continuing..."
;;
[Nn]* )
# User answered no, exit the script safely
echo "Quitting script."
exit 0
;;
* )
# Invalid input, exit with an error status
echo "Invalid response. Quitting."
exit 1
;;
esac
fi
# Enable extended globbing so the loop understands the @(pattern) syntax
shopt -s extglob
for file in *.@(mp4|avi|mkv|mov); do
ffmpeg -hwaccel cuda -i "$file" -c:v h264_nvenc -preset p6 -cq 24 -maxrate 8M -bufsize 16M -c:a copy "converted/${file%.*}.mp4"
done

Please Subscribe to the PenguinTutor YouTube Channel to get notified of future updates.