Quick answer

What this guide helps you do

Build a reliable low-power Jellyfin server on Ubuntu. Install Jellyfin, mount storage, fix media access, favour Direct Play, measure power, and verify the server after reboot.

Jellyfin beginner path

New to Jellyfin? Follow this order.

These guides form the SmallGrid Jellyfin path: install it, fix folder access, solve empty libraries, reduce unnecessary transcoding, then choose the right mini PC.

  1. Give Jellyfin Access to Media Folders on Ubuntu
  2. Jellyfin Library Not Showing Files: Fix Scans, Paths and Permissions
  3. Jellyfin Direct Play vs Transcoding: Differences, CPU Use and How to Check
  4. Best Mini PC Specs for Jellyfin: What Actually Matters

Difficulty

Beginner-friendly

Focus

Jellyfin setup and troubleshooting

Best used for

Practical setup, fixes, and checks

Quick answer

A reliable low-power Jellyfin server on Ubuntu needs six things:

  1. Jellyfin installed as a managed service.
  2. Media stored at a stable server path.
  3. Storage mounted before Jellyfin starts scanning.
  4. The Jellyfin service account able to read every library folder.
  5. Clients capable of Direct Play for the formats you actually use.
  6. A measured power baseline rather than an assumed one.

The most useful access test is:

sudo -u jellyfin find /mnt/media -maxdepth 3 -type f | head -20

The most useful reboot checks are:

systemctl status jellyfin --no-pager
findmnt /mnt/media
sudo -u jellyfin find /mnt/media -maxdepth 3 -type f | head -20

Do not optimise power consumption until the service starts correctly, the storage is mounted, the files are readable, and the library survives a controlled reboot.


What this guide covers

This is the complete native-Ubuntu build guide for a small, always-on Jellyfin server.

It covers:

  • installing Jellyfin as a system service
  • choosing a maintainable storage layout
  • mounting media reliably
  • granting the jellyfin account read access
  • adding and validating libraries
  • reducing avoidable transcoding
  • measuring idle and playback power
  • checking temperatures, storage and service health
  • proving the build survives restart and reboot

It does not duplicate the full repair workflow for every failure type.

Use:

For Docker installations, use the Docker-specific guides because container paths and user IDs change the permission model.


SmallGrid verification environment

SmallGrid’s current media-server environment uses:

Operating system: Ubuntu Server
Jellyfin runtime: Docker in production
Storage pool:     MergerFS
TV host path:     /srv/media_pool/TV
Container path:   /tv
Media services:   Jellyfin, Sonarr, Radarr and qBittorrent
Network:          Local Ethernet
Timezone:         Europe/London

The production system is containerised, but the reliability checks in this guide also apply to a native package installation:

  • the service is active
  • the storage is mounted
  • the Jellyfin process can read real files
  • the library path is correct
  • playback mode is known
  • the same state returns after reboot

At the last verified storage check, the active media branches contained 1,539 files, and the host and Jellyfin-visible counts matched.

No wattage figure is claimed in this guide without a wall-meter measurement. “Low power” means avoiding unnecessary work and measuring the whole machine rather than guessing from CPU utilisation.


DecisionRecommended starting pointReason
Operating systemCurrent Ubuntu Server LTSStable package and service management
System diskSSDFast metadata access, quiet operation and responsive updates
Media path/mnt/media or /srv/mediaClear location for shared service data
NetworkWired EthernetPredictable high-bitrate playback
Playback targetDirect PlayLowest server processing requirement
1080p targetH.264 with AAC or AC3Broad client compatibility
4K targetHEVC only where clients support itSaves storage without forcing conversion
PermissionsRead and execute ACL for jellyfinPreserves the main owner while granting access
Permanent disksUUID-based /etc/fstab mountStable after reboots and device-name changes
TranscodingHardware acceleration only when requiredReduces CPU load but adds configuration complexity

A low-power design is mostly about removing unnecessary activity:

Direct Play instead of video conversion
Stable mounts instead of failed rescans
SSD metadata instead of slow random access
Suitable clients instead of server upgrades
Measured changes instead of assumptions

Step 1: Record the starting environment

Before changing the server, record its current state:

cat /etc/os-release
uname -r
lscpu | sed -n '1,25p'
free -h
lsblk -o NAME,SIZE,FSTYPE,MODEL,MOUNTPOINTS
ip -brief address
timedatectl

Check the graphics devices if hardware transcoding may be used later:

lspci | grep -Ei 'vga|display|3d'
ls -la /dev/dri 2>/dev/null

Keep this output with the date. It makes later troubleshooting, upgrades and power comparisons meaningful.


Step 2: Install Jellyfin

Update Ubuntu and install the repository tools:

sudo apt update
sudo apt install -y apt-transport-https ca-certificates curl gnupg lsb-release

Add the Jellyfin signing key:

curl -fsSL https://repo.jellyfin.org/jellyfin_team.gpg.key \
  | sudo gpg --dearmor -o /usr/share/keyrings/jellyfin.gpg

Add the repository:

echo "deb [signed-by=/usr/share/keyrings/jellyfin.gpg] https://repo.jellyfin.org/ubuntu $(lsb_release -cs) main" \
  | sudo tee /etc/apt/sources.list.d/jellyfin.list

Install and start Jellyfin:

sudo apt update
sudo apt install -y jellyfin
sudo systemctl enable --now jellyfin

Verify the service:

systemctl status jellyfin --no-pager
systemctl is-enabled jellyfin
systemctl show jellyfin -p User -p Group
jellyfin --version

Expected state:

Service active:  yes
Starts at boot:  yes
Service user:    jellyfin
Version recorded: yes

Step 3: Create a stable media layout

Use a shared-service path rather than a personal home directory:

/mnt/media/
├── movies/
├── tv/
└── music/

Create the directories:

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

Recommended naming examples:

/mnt/media/movies/Blade Runner (1982)/Blade Runner (1982).mkv
/mnt/media/tv/The Expanse/Season 01/The Expanse - S01E01 - Dulcinea.mkv

Avoid storing shared libraries below /home/YOUR-USER unless you understand every parent directory’s traversal permissions.


Step 4: Confirm the storage is mounted

A mount-point directory can exist even when the actual disk, share or pool is missing.

Check the active mount:

findmnt /mnt/media
findmnt -no SOURCE,TARGET,FSTYPE,OPTIONS /mnt/media
lsblk -f
find /mnt/media -maxdepth 3 -type f | head -20

Interpretation:

ResultMeaning
findmnt shows the expected sourceStorage is mounted at the intended target
Folder exists but findmnt shows nothingJellyfin may be scanning the empty mount-point directory
Files are absentFix the storage or import path before changing Jellyfin
Files are presentContinue to the service-user access test

For permanent disks, use UUID-based entries in /etc/fstab.

After editing /etc/fstab, validate before rebooting:

sudo mount -a
findmnt /mnt/media

Do not continue until the expected files appear at the host path.


Step 5: Give Jellyfin read access

Confirm the service account:

id jellyfin

Test the path as Jellyfin:

sudo -u jellyfin find /mnt/media -maxdepth 3 -type f | head -20

If access fails, inspect every directory in the path:

namei -l /mnt/media/movies
getfacl /mnt/media

For a normal ext4 library, grant read and conditional execute access:

sudo apt install -y acl
sudo setfacl -R -m u:jellyfin:rX /mnt/media
sudo setfacl -R -d -m u:jellyfin:rX /mnt/media
sudo systemctl restart jellyfin

Verify with the same test:

getfacl /mnt/media
sudo -u jellyfin find /mnt/media -maxdepth 3 -type f | head -20

The direct service-user test is the proof. A successful setfacl command alone is not enough.


Step 6: Open Jellyfin and add the libraries

From another device on the same network, open:

http://YOUR-SERVER-IP:8096

Add the native Ubuntu paths:

Movies:   /mnt/media/movies
TV Shows: /mnt/media/tv
Music:    /mnt/media/music

Run a library scan.

A successful result should include:

Library path accepted
Scan does not finish immediately with no files
Known media appears
No permission or path errors in logs

Check recent logs:

sudo journalctl -u jellyfin --since "10 minutes ago" --no-pager

Step 7: Verify new-file inheritance

Old files may work while new Sonarr, Radarr, download-client or manually copied files remain invisible.

Compare one working and one new folder:

ls -ld "/mnt/media/tv/Working Show"
ls -ld "/mnt/media/tv/New Show"
getfacl "/mnt/media/tv/Working Show"
getfacl "/mnt/media/tv/New Show"

Test the new path directly:

sudo -u jellyfin find "/mnt/media/tv/New Show" -maxdepth 2 -type f | head

The default ACL should be inherited. Also inspect the creating service’s user, group and umask when new imports differ from existing media.


Step 8: Make Direct Play the default goal

Direct Play keeps server work low because Jellyfin sends the original media to the client.

A broadly compatible 1080p target is:

Container: MP4 or MKV
Video:     H.264
Audio:     AAC or AC3
Subtitles: SRT

For 4K, use HEVC only when the main playback clients support the exact profile, bit depth, HDR format, audio and subtitles.

During playback, record:

Client:
Connection: local or remote
Playback mode:
Video codec:
Audio codec:
Subtitle format:
Reported transcode reason:

If a file transcodes, test subtitles, audio, client and quality settings before upgrading the server.


Step 9: Measure power properly

Use a plug-in wall meter or another whole-system measurement method.

Record the same server in these states:

StateWhat to record
Powered on and idleWhole-system watts after background work settles
Local Direct PlaySame representative file and client
Direct StreamA known remux or audio-conversion case
Software transcodeOne incompatible file without acceleration
Hardware transcodeThe same file after acceleration is enabled
Library scanTemporary peak during active indexing

Use the same file, client and test duration when comparing playback states.

A useful record looks like:

Date:
Server hardware:
Ubuntu version:
Jellyfin version:
Storage state:
Playback file:
Playback client:
Playback mode:
Wall power:
CPU temperature:
Notes:

Do not publish or rely on a power saving unless the measured difference is repeatable.


Step 10: Optional hardware transcoding

Enable hardware acceleration only when a real playback requirement remains.

Inspect available devices:

ls -la /dev/dri
id jellyfin

For Intel VAAPI or Quick Sync diagnostics:

sudo apt install -y vainfo intel-media-va-driver-non-free
vainfo

Confirm the Jellyfin user can access the render device and enable only the codecs the hardware actually supports.

Hardware acceleration can make a necessary transcode efficient. It does not make an incompatible client Direct Play the original file.


Step 11: Check temperatures and background load

Install basic monitoring tools:

sudo apt install -y lm-sensors htop
sudo sensors-detect --auto
sensors

Inspect active processes:

top
ps aux --sort=-%cpu | head -15

Unexpected background work can come from:

  • a library scan
  • chapter-image extraction
  • metadata refreshes
  • software transcoding
  • another media service
  • filesystem maintenance
  • a failed task retrying repeatedly

Do not treat every short CPU spike as a power problem. Look for sustained, repeatable activity.


Step 12: Reboot and prove recovery

A home server is not reliable until the same working state returns after reboot.

Before rebooting:

sudo mount -a
systemctl is-enabled jellyfin
sudo -u jellyfin find /mnt/media -maxdepth 3 -type f | head -20

Reboot:

sudo reboot

After reconnecting:

uptime
systemctl status jellyfin --no-pager
findmnt /mnt/media
sudo -u jellyfin find /mnt/media -maxdepth 3 -type f | head -20
sudo journalctl -u jellyfin -b --no-pager -n 100

Then confirm in Jellyfin:

  1. the web interface loads
  2. libraries remain populated
  3. a known file plays
  4. the expected playback mode appears
  5. no path or permission errors appear in the current-boot logs

Final verification record

Do not call the build complete until every row is confirmed:

CheckRequired result
Jellyfin serviceActive and enabled
Media mountExpected source mounted at the expected target
Host filesReal media visible
Service-user accessjellyfin can list known media files
Library pathExact native Ubuntu path configured
Library scanCompletes without access errors
New importsInherit usable access
PlaybackMode and conversion reason known
PowerIdle and playback states measured
RebootService, mount, library and playback recover

Useful final command block:

systemctl is-active jellyfin
systemctl is-enabled jellyfin
findmnt /mnt/media
sudo -u jellyfin find /mnt/media -maxdepth 3 -type f | head -20
sudo journalctl -u jellyfin -b --no-pager -n 100


Recap

A low-power Jellyfin server is not simply a low-wattage computer.

It is a server that:

  • starts predictably
  • mounts storage correctly
  • can read the media without broad permissions
  • Direct Plays most everyday files
  • uses hardware transcoding only when required
  • has measured idle and playback consumption
  • returns to the same healthy state after reboot

Build reliability first, then measure and optimise.

Next guide

What to read next

Continue the setup path with these closely related guides.

Jellyfin guide cluster

More Jellyfin fixes and setup guides

These guides link the main Jellyfin setup, permissions, remote access, direct play, and hardware topics together.