Complete Setup Guide

Raspberry Pi 5
Jellyfin Media Server

A full walkthrough from bare hardware to a remote-accessible home media server โ€” every command, every step, every reason why.
you can go back to the project side here: Projects

7
Major Steps
30+
Commands
1.8TB
Media Storage
โˆž
Movies & Shows
๐Ÿ–ฅ๏ธ
Hardware Overview
What was used in this build
๐Ÿ“
Raspberry Pi 5
Main compute unit
๐Ÿ’พ
2TB External HDD
Media storage (2.5")
๐Ÿ’ฟ
microSD Card
OS storage (115GB)
๐ŸŒก๏ธ
Case with Fan
Cooling solution
๐Ÿ’ก
A 2.5" USB-powered drive is ideal โ€” it draws power directly from the Pi's USB port, requires no separate power supply, produces minimal heat, and is completely silent. Thats why i went with it.
01
OS Installation & First Boot
Flash Raspberry Pi OS to the microSD card

Raspberry Pi OS Lite(64-bit) was flashed to the microSD card using Raspberry Pi Imager on a Windows PC. The Pi was then connected via Pi Connect for remote terminal access.

OS Lite boots straight into a terminal with no desktop, no windows, no mouse. Everything is done through text commands. It's lighter and faster because it's not running a graphical interface in the background, which means more of the Pi's power goes to Jellyfin instead of drawing a desktop nobody is using.

โœ…
Pi Connect allows you to access the Pi's terminal from any browser without needing a monitor or keyboard connected to the Pi.
02
System Update
Always update before installing anything

Ones you have connected in Pi connect the system package list and all installed packages must be updated. This ensures we're installing the latest, most compatible versions of everything.
You can do that by pasting the command below into the terminal:

terminal
sudo apt update sudo apt upgrade -y
๐Ÿ’ก
sudo = run as administrator.
apt = the package manager on Debian/Raspberry Pi OS.
-y = automatically answer "yes" to all prompts.
03
Connect & Mount the Drive
Format, mount, and auto-mount on boot

Find the drive

After plugging in the external drive, this command lists all block devices (drives) so we can identify ours.

terminal
lsblk

The drive appeared as sda / sda1 with 1.8TB โ€” confirming the Pi detected it correctly.
It's important to note that the physical drive is 2TB, however some storage is lost to formatting overhead, which is why it shows as 1.8TB.

Format the drive

โš ๏ธ
This erases everything on the drive. Only run this if you're sure you don't need any existing data.

The drive is going to be formatted as ext4 โ€” the standard Linux filesystem. It's faster and more reliable for a Linux server than NTFS (Windows format) or FAT32.

terminal
sudo mkfs.ext4 /dev/sda1

Create mount point & mount

In Linux, drives don't appear as drive letters (like D:). Instead they are "mounted" to a folder. So we create /mnt/media as the folder where the drive will live.

terminal
sudo mkdir /mnt/media
sudo mount /dev/sda1 /mnt/media

Then if you want to make sure that your mounting worked you can run the following command:

terminal
df -h

You should see something like this โ€” look for /dev/sda1 mounted at /mnt/media with roughly 1.8TB available:

output
Filesystem Size Used Avail Use% Mounted on
/dev/sda1 1.8T 2.1M 1.7T 1% /mnt/media

If you can see /mnt/media in the list, the drive is mounted and ready to use!

Get the drive's UUID

Every drive has a unique ID (UUID). We need this to tell the Pi to auto-mount the right drive on boot โ€” not just "whatever is in the USB port". Makes it behave more like a permanent hard drive.

terminal
sudo blkid /dev/sda1

UUID looks something like: 623db798-5cca-413b-8df4-12c969db9673

Edit fstab for auto-mount

fstab is the file Linux reads on every boot to know which drives to mount and where. We added our drive so it mounts automatically every time the Pi starts.

terminal
sudo nano /etc/fstab

Line added at the bottom of the file:

โš ๏ธ
You need to paste your own UUID
/etc/fstab entry
UUID=623db798-5cca-413b-8df4-12c969db9673 /mnt/media ext4 defaults 0 2

Final fstab file should look like:

/etc/fstab
proc PARTUUID=914cfa12-01 /boot/firmware vfat defaults 0 2 PARTUUID=914cfa12-02 / ext4 defaults,noatime 0 1 UUID=623db798-5cca-413b-8df4-12c969db9673 /mnt/media ext4 defaults 0 2
verify auto-mount works
sudo systemctl daemon-reload sudo mount -a
โœ…
No output = success. Linux is silent when things work correctly.
04
Install Jellyfin Media Server
Adding the Jellyfin repository and installing

Jellyfin has an official repository for Debian Trixie. We add the repository key, add the repo, then install Jellyfin.

add jellyfin repository
sudo apt install curl gnupg -y curl -fsSL https://repo.jellyfin.org/jellyfin_team.gpg.key | sudo gpg --dearmor -o /usr/share/keyrings/jellyfin.gpg echo "deb [signed-by=/usr/share/keyrings/jellyfin.gpg] https://repo.jellyfin.org/debian trixie main" | sudo tee /etc/apt/sources.list.d/jellyfin.list
install jellyfin
sudo apt update sudo apt install jellyfin -y
enable & start jellyfin
sudo systemctl enable jellyfin sudo systemctl start jellyfin sudo systemctl status jellyfin

Jellyfin is confirmed running when status shows active (running).

Jellyfin web UI is accessible at http://[YOUR-PI-IP]:8096 โ€” you can find your Pi's IP by running:

terminal
hostname -I
05
Set Up Network Share (Samba)
Access the media drive from Windows like a normal folder

Samba is a service that lets Linux share folders over the network using Windows-compatible file sharing. This allows you to drag and drop movies directly from your PC into the Pi's media drive.

install & configure samba
sudo apt install samba -y sudo chown -R JellyfinServer:JellyfinServer /mnt/media sudo chmod -R 775 /mnt/media sudo nano /etc/samba/smb.conf

Added to the bottom of /etc/samba/smb.conf:

smb.conf entry
[Media] path = /mnt/media browseable = yes writeable = yes guest ok = yes force user = JellyfinServer
set samba password & restart
sudo smbpasswd -a JellyfinServer sudo systemctl restart smbd
โš ๏ธ
Remember the password for the next step!

From Windows PC, access the share by typing in File Explorer's address bar:

windows file explorer
\\[YOUR-PI-IP]

Login with username JellyfinServer and the Samba password you set.

06
Remote Access via Tailscale
Watch your Jellyfin from anywhere in the world

The home network might have Double NAT issue (modem + personal router) which blocked standard port forwarding. Tailscale is used instead โ€” it creates a secure private tunnel between devices without needing to open ports on your router.

Why Tailscale?

  • โœ“ Works with Double NAT โ€” no router config needed
  • โœ“ Encrypted private tunnel between your devices
  • โœ“ Free for personal use
  • โœ“ Works on Windows, Mac, Android, iOS, Linux

Install Tailscale on the Pi

install tailscale
sudo apt install tailscale -y sudo tailscale up

Running tailscale up outputs a login URL. Open it in your browser and sign in with a free Tailscale account. The Pi then joins your private Tailscale network.

get tailscale ip
tailscale ip

Jellyfin is now accessible from anywhere using Tailscale at:

remote access url
http://[YOUR-TAILSCALE-IP]:8096
โš ๏ธ
Important: Tailscale must be installed and running on EVERY device that wants to access the server remotely. Each device connects individually. Once installed Tailscale runs silently in the background โ€” no need to open it manually.

Sharing with others

To give someone else access, go to https://login.tailscale.com, find the Pi device, click Share, and enter their email. They install Tailscale, accept the invite, and can access your Jellyfin at the Tailscale IP.

07
File Naming & Organization
How to name files so Jellyfin recognizes them correctly

Jellyfin matches your files against its database to pull in posters, descriptions, and ratings. It relies on the filename and folder structure to identify what it's looking at. Messy filenames cause misidentification. Look at the potencial issues section below for examples of what to do if youy want a code to do it automatically.

/mnt/media/
โ”œโ”€โ”€ Movies/
โ”‚   โ””โ”€โ”€ Inception (2010)/
โ”‚       โ””โ”€โ”€ Inception (2010).mkv
โ””โ”€โ”€ Shows/
    โ””โ”€โ”€ Breaking Bad/
        โ””โ”€โ”€ Season 01/
            โ””โ”€โ”€ Breaking Bad S01E01.mkv

Rules

TypeRuleExample
MoviesMovie in its own folder with yearInception (2010)/Inception (2010).mkv
TV ShowsShow โ†’ Season folder โ†’ S01E01 namingBreaking Bad/Season 01/Breaking Bad S01E01.mkv
โŒ AvoidExtra tags in filenameMovie.1080p.x265-GROUP[EZTVx].mkv
โš ๏ธ
Extra text like 1080p.HEVC.x265-MeGusta[EZTVx.to] in the filename confuses Jellyfin and causes it to misidentify seasons or episodes. Always rename to a clean format.
๐Ÿ”ง
Troubleshooting
Issues encountered and how they were fixed

Drive won't unmount ("target is busy")

Jellyfin or another process is holding the drive open. Stop Jellyfin first, then find and kill any remaining process using the drive.

fix
sudo systemctl stop jellyfin sudo fuser -m /mnt/media # find PID using the drive sudo kill -9 [PID] # kill that process sudo umount /mnt/media

Tailscale not reachable from outside

Make sure you're testing from a device that also has Tailscale installed and connected. The 100.x.x.x IP only works between Tailscale devices. Also verify Jellyfin and Tailscale are both running.

check status
sudo tailscale status sudo systemctl status jellyfin sudo systemctl status tailscaled

Port forwarding blocked (Double NAT)

If you have both a modem and a router, standard port forwarding won't work. Either call your ISP to enable bridge mode, or use Tailscale instead (recommended).

Drive shows as sda instead of sda after reboot

Sometimes after a reboot the drive gets assigned a different device name (sda instead of sda). This is fine since fstab uses the UUID not the device name โ€” just remount manually if needed:

fix
sudo systemctl daemon-reload sudo mount -a sudo chown -R JellyfinServer:JellyfinServer /mnt/media sudo chmod -R 775 /mnt/media
๐ŸŽ‰
Final Setup Summary
Everything that was built
๐Ÿ“
Server
Raspberry Pi 5
๐Ÿ’พ
Media Storage
1.8TB at /mnt/media
๐ŸŽฌ
Media Server
Jellyfin Media Server
๐ŸŒ
Remote Access
Tailscale VPN
๐Ÿ“
File Transfer
Samba (\\[YOUR-PI-IP])
๐Ÿ”’
Local IP
192.168.1.170

Quick Reference โ€” Important URLs

PurposeURL / Address
Jellyfin (local network)http://[YOUR-PI-IP]:8096
Jellyfin (via Tailscale)http://[YOUR-TAILSCALE-IP]:8096
File transfer (Windows)\\[YOUR-PI-IP]
Tailscale dashboardhttps://login.tailscale.com
  • โœ“ Raspberry Pi 5 running Raspberry Pi OS Lite (64-bit)
  • โœ“ 2TB external drive formatted ext4, auto-mounted at /mnt/media
  • โœ“ Jellyfin Media Server installed and running
  • โœ“ Samba network share for easy file transfers from PC
  • โœ“ Tailscale installed for secure remote access from anywhere
  • โœ“ Proper file naming convention for Jellyfin library matching
Scripts or improvements

While this setup is solid, there are a few potential issues to be aware of:

If you want to expand your storage in the future, you can connect additional hard drives to the Pi using a powered USB hub โ€” one that plugs into the wall with its own power adapter. This is important because larger hard drives (especially 3.5 inch desktop drives) draw more power than the Pi can supply through its USB ports alone. A powered hub solves this by giving each drive its own power source.

If you want your files to have names like "Show Name S01E01.mkv", you'll need to rename them manually or use a script. And the seasons need to be in folders named "Season 01", "Season 02", etc. Otherwise Jellyfin will have trouble matching them to the correct show and season, and you might end up with missing posters or metadata. You can run:

Rename all episode files (run from the show folder on the Pi terminal):

terminal
for dir in /mnt/media/Shows/Your\ Show\ Name/*/; do for file in "$dir"*.mkv; do episode=$(echo "$file" | grep -oP 'S\d{2}E\d{2}') newname="$(dirname "$file")/Your Show Name $episode.mkv" mv "$file" "$newname" done done

Rename all season folders:

terminal
for dir in /mnt/media/Shows/Your\ Show\ Name/*/; do season=$(echo "$dir" | grep -oP 'S\d{2}') num=$(echo "$season" | grep -oP '\d{2}') mv "$dir" "/mnt/media/Shows/Your Show Name/Season $num" done