Third party cookies may be stored when visiting this site. Please see the cookie information.

PenguinTutor YouTube Channel

Raspberry Pi Jellyfin Home Media Server Guide

Part 3: Installing and configurating Jellyfin and media transcoding

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.

Initial Directory Setup

Before deploying the server, create a dedicated directory on your NVMe drive to store JellyFin's configuration data.


    mkdir -p ~/docker_data/jellyfin

Installing Jellyfin using Docker (Portainer Stack)

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'

Hardware Acceleration (Pi4 / CM4 Only)

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.

Media Optimization (transcoding)

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.

Scan for Incompatible Codecs

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

Batch Convert to H.264 (Run on a Desktop PC)

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

Final Checklist

Raspberry Pi media center running Jellyfin - home screen showing thumbnail images for different categories of videos and music files

  • Access: Once deployed visit http://<your_ip_address>:8096 to complete the setup
  • Libraries: Separate "Shows" and "Movies" content types to ensure JellyFin uses the correct metadata scrapers
  • Music: Use MusicBrainz Picard to clean up ID3 tags and album art before importing your music library.

Future Projects

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

Other Raspberry Pi Projects and tutorials

Previous Adding NAS, Docker and Web server
Adding NAS, Docker and Web server
Next Running the Raspberry Pi headless with Debian Linux
Running the Raspberry Pi headless with Debian Linux