19 KiB
Jellyfin - Open-Source Media Server
Table of Contents
- Overview
- What is Jellyfin?
- Why Use Jellyfin?
- How It Works
- Configuration in AI-Homelab
- Official Resources
- Educational Resources
- Docker Configuration
- Initial Setup
- Library Management
- Advanced Topics
- Troubleshooting
Overview
Category: Media Server
Docker Image: linuxserver/jellyfin
Default Stack: media.yml
Web UI: https://jellyfin.${DOMAIN} or http://SERVER_IP:8096
Authentication: Local accounts (no external service required)
Ports: 8096 (HTTP), 8920 (HTTPS), 7359 (auto-discovery), 1900 (DLNA)
What is Jellyfin?
Jellyfin is a free, open-source media server forked from Emby. It provides complete control over your media with no tracking, premium features, or account requirements. Jellyfin is 100% free with all features available without subscriptions.
Key Features
- Completely Free: No premium tiers or subscriptions
- Open Source: GPLv2 licensed
- No Tracking: Zero telemetry or analytics
- Local Accounts: No external service required
- Hardware Acceleration: VAAPI, NVENC, QSV, AMF
- Live TV & DVR: Built-in EPG support
- SyncPlay: Watch together feature
- Native Apps: Android, iOS, Roku, Fire TV, etc.
- Web Player: Modern HTML5 player
- DLNA Server: Stream to any DLNA device
- Plugins: Extensible with official/community plugins
- Webhooks: Custom notifications and integrations
Why Use Jellyfin?
- 100% Free: All features, no subscriptions ever
- Privacy Focused: No tracking, no accounts to external services
- Open Source: Community-driven development
- Self-Contained: No dependency on external services
- Hardware Transcoding: Free for everyone
- Modern Interface: Clean, responsive UI
- Active Development: Regular updates
- Plugin System: Extend functionality
- SyncPlay: Watch parties built-in
- No Vendor Lock-in: Your data, your control
How It Works
Media Files → Jellyfin Server (scans and organizes)
↓
Metadata Enrichment
(TheMovieDB, MusicBrainz, etc.)
↓
┌──────────┴──────────┐
↓ ↓
Direct Play Transcoding
(Compatible) (Hardware Accel)
↓ ↓
Jellyfin Apps Jellyfin Apps
(All Devices) (Any Browser)
Media Flow
- Add media to libraries
- Jellyfin scans and identifies content
- Metadata scraped from open databases
- User requests via web/app
- Jellyfin determines if transcoding needed
- Hardware transcoding if supported
- Stream to client
Configuration in AI-Homelab
Directory Structure
/opt/stacks/media/jellyfin/
├── config/ # Jellyfin configuration
├── cache/ # Temporary cache
└── transcode/ # Transcoding temp files
/mnt/media/
├── movies/ # Movie files
├── tv/ # TV show files
├── music/ # Music files
└── photos/ # Photo files
Environment Variables
# User permissions
PUID=1000
PGID=1000
# Timezone
TZ=America/New_York
# Optional: Published server URL
JELLYFIN_PublishedServerUrl=https://jellyfin.yourdomain.com
Official Resources
- Website: https://jellyfin.org
- Documentation: https://jellyfin.org/docs/
- GitHub: https://github.com/jellyfin/jellyfin
- Forum: https://forum.jellyfin.org
- Reddit: https://reddit.com/r/jellyfin
- Matrix Chat: https://matrix.to/#/#jellyfin:matrix.org
- Feature Requests: https://features.jellyfin.org
Educational Resources
Videos
- Jellyfin Setup Guide (Techno Tim)
- Jellyfin vs Plex vs Emby
- Ultimate Jellyfin Setup
- Jellyfin Hardware Transcoding
- Jellyfin Tips and Tricks
Articles & Guides
Concepts to Learn
- Transcoding: Converting media formats in real-time
- Hardware Acceleration: GPU-based encoding (VAAPI, NVENC, QSV)
- Direct Play: Streaming without conversion
- Remuxing: Changing container without re-encoding
- Metadata Providers: TheMovieDB, TVDb, MusicBrainz
- NFO Files: Local metadata files
- DLNA: Network streaming protocol
Docker Configuration
Complete Service Definition
jellyfin:
image: linuxserver/jellyfin:latest
container_name: jellyfin
restart: unless-stopped
networks:
- traefik-network
ports:
- "8096:8096" # HTTP Web UI
- "8920:8920" # HTTPS (optional)
- "7359:7359/udp" # Auto-discovery
- "1900:1900/udp" # DLNA
environment:
- PUID=1000
- PGID=1000
- TZ=America/New_York
- JELLYFIN_PublishedServerUrl=https://jellyfin.${DOMAIN}
volumes:
- /opt/stacks/media/jellyfin/config:/config
- /opt/stacks/media/jellyfin/cache:/cache
- /mnt/media/movies:/data/movies:ro
- /mnt/media/tv:/data/tvshows:ro
- /mnt/media/music:/data/music:ro
devices:
- /dev/dri:/dev/dri # Intel QuickSync
labels:
- "traefik.enable=true"
- "traefik.http.routers.jellyfin.rule=Host(`jellyfin.${DOMAIN}`)"
- "traefik.http.routers.jellyfin.entrypoints=websecure"
- "traefik.http.routers.jellyfin.tls.certresolver=letsencrypt"
- "traefik.http.services.jellyfin.loadbalancer.server.port=8096"
With NVIDIA GPU
jellyfin:
image: linuxserver/jellyfin:latest
container_name: jellyfin
restart: unless-stopped
runtime: nvidia # Requires nvidia-docker
environment:
- NVIDIA_VISIBLE_DEVICES=all
- NVIDIA_DRIVER_CAPABILITIES=compute,video,utility
volumes:
- /opt/stacks/media/jellyfin/config:/config
- /mnt/media:/data:ro
ports:
- "8096:8096"
Transcoding on RAM Disk
jellyfin:
volumes:
- /opt/stacks/media/jellyfin/config:/config
- /mnt/media:/data:ro
- /dev/shm:/config/transcodes # Use RAM for transcoding
Initial Setup
First-Time Configuration
-
Start Container:
docker compose up -d jellyfin -
Access Web UI:
- Local:
http://SERVER_IP:8096 - Via domain:
https://jellyfin.yourdomain.com
- Local:
-
Initial Setup Wizard:
- Select preferred display language
- Create administrator account (local, no external service)
- Set up media libraries
- Configure remote access
- Review settings
Adding Libraries
Add Movie Library:
- Dashboard → Libraries → Add Media Library
- Content type: Movies
- Display name: Movies
- Folders → Add →
/data/movies - Preferred language: English
- Country: United States
- Save
Add TV Library:
- Dashboard → Libraries → Add Media Library
- Content type: Shows
- Display name: TV Shows
- Folders → Add →
/data/tvshows - Save
Add Music Library:
- Content type: Music
- Folders → Add →
/data/music - Save
File Naming Conventions
Movies:
/data/movies/
Movie Name (Year)/
Movie Name (Year).mkv
Example:
/data/movies/
The Matrix (1999)/
The Matrix (1999).mkv
TV Shows:
/data/tvshows/
Show Name (Year)/
Season 01/
Show Name - S01E01 - Episode Name.mkv
Example:
/data/tvshows/
Breaking Bad (2008)/
Season 01/
Breaking Bad - S01E01 - Pilot.mkv
Breaking Bad - S01E02 - Cat's in the Bag.mkv
Music:
/data/music/
Artist/
Album (Year)/
01 - Track Name.mp3
Library Management
Scanning Libraries
Manual Scan:
- Dashboard → Libraries → Scan All Libraries
- Or click scan icon on specific library
Scheduled Scanning:
- Dashboard → Scheduled Tasks → Scan Media Library
- Configure scan interval
Real-time Monitoring:
- Dashboard → Libraries → Enable real-time monitoring
- Watches for file changes
Metadata Management
Providers:
- Dashboard → Libraries → Select library → Manage Library
- Metadata providers: TheMovieDB, TVDb, OMDb, etc.
- Order determines priority
Identify Item:
- Select item with wrong metadata
- ... → Identify
- Search by name or TMDB/TVDb ID
- Select correct match
Edit Metadata:
- ... → Edit Metadata
- Change title, description, images, etc.
- Lock fields to prevent overwriting
Refresh Metadata:
- ... → Refresh Metadata
- Re-scrapes from providers
Collections
Auto Collections:
- Jellyfin auto-creates collections from metadata
- Example: "Marvel Cinematic Universe" for all MCU movies
Manual Collections:
- Dashboard → Collections → New Collection
- Name collection
- Add movies/shows
- Set sorting and display options
Advanced Topics
Hardware Transcoding
Intel QuickSync (QSV):
-
Verify GPU Access:
docker exec jellyfin ls -la /dev/dri # Should show renderD128, card0, etc. # Check permissions docker exec jellyfin id # User should have video group (render group ID) -
Enable in Jellyfin:
- Dashboard → Playback → Transcoding
- Hardware acceleration: Intel QuickSync (QSV)
- Enable hardware decoding for: H264, HEVC, VP9, AV1
- Enable hardware encoding for: H264, HEVC
- Save
NVIDIA GPU (NVENC):
-
Ensure nvidia-docker installed:
docker run --rm --gpus all nvidia/cuda:11.0-base nvidia-smi -
Enable in Jellyfin:
- Dashboard → Playback → Transcoding
- Hardware acceleration: Nvidia NVENC
- Enable codecs
- Save
AMD GPU (AMF/VAAPI):
jellyfin:
devices:
- /dev/dri:/dev/dri
- /dev/kfd:/dev/kfd # AMD GPU
group_add:
- video
- render
Dashboard → Transcoding → VAAPI
Verify Hardware Transcoding:
- Play a video that requires transcoding
- Dashboard → Activity
- Check encoding method shows (hw)
User Management
Add Users:
- Dashboard → Users → Add User
- Enter username and password
- Configure library access
- Set permissions
User Profiles:
- Each user has own watch history
- Separate Continue Watching
- Individual preferences
Parental Controls:
- Set maximum parental rating
- Block unrated content
- Restrict library access
Plugins
Install Plugins:
- Dashboard → Plugins → Catalog
- Browse available plugins
- Install desired plugins
- Restart Jellyfin
Popular Plugins:
- TMDb Box Sets: Auto-create collections
- Trakt: Sync watch history to Trakt.tv
- Reports: Generate library reports
- Skin Manager: Custom themes
- Anime: Better anime support
- Fanart: Additional image sources
- Merge Versions: Combine different qualities
- Playback Reporting: Track user activity
Third-Party Repositories:
- Add custom plugin repositories
- Dashboard → Plugins → Repositories
SyncPlay (Watch Together)
Enable:
- Dashboard → Plugins → SyncPlay
- Restart Jellyfin
Use:
- User creates SyncPlay group
- Shares join code
- Others join with code
- Playback synchronized across all users
- Chat available
Perfect For:
- Long-distance watch parties
- Family movie nights
- Synchronized viewing
Live TV & DVR
Requirements:
- TV tuner hardware (HDHomeRun, etc.)
- Or IPTV source (m3u playlist)
Setup:
- Dashboard → Live TV
- Add TV source:
- Tuner device (network device auto-detected)
- Or IPTV (M3U URL)
- Configure EPG (Electronic Program Guide)
- XML TV guide URL
- Map channels
- Save
DVR:
- Record shows from EPG
- Series recordings
- Post-processing options
Troubleshooting
Jellyfin Not Accessible
# Check container status
docker ps | grep jellyfin
# View logs
docker logs jellyfin
# Test access
curl http://localhost:8096
# Check ports
docker port jellyfin
Libraries Not Scanning
# Check permissions
ls -la /mnt/media/movies/
# Fix ownership
sudo chown -R 1000:1000 /mnt/media/
# Check container can access
docker exec jellyfin ls /data/movies
# Manual scan from UI
# Dashboard → Libraries → Scan All Libraries
# Check logs
docker logs jellyfin | grep -i scan
Hardware Transcoding Not Working
# Verify GPU device
docker exec jellyfin ls -la /dev/dri
# Check permissions
docker exec jellyfin groups
# Should include video (44) and render (106 or 104)
# For Intel GPU, check:
docker exec jellyfin vainfo
# Should list supported codecs
# Check Jellyfin logs during playback
docker logs -f jellyfin
# Look for hardware encoding messages
Fix GPU Permissions:
# Get render group ID
getent group render
# Update docker-compose
jellyfin:
group_add:
- "106" # render group ID
Transcoding Failing
# Check transcode directory
docker exec jellyfin ls /config/transcodes/
# Ensure enough disk space
df -h /opt/stacks/media/jellyfin/
# Check FFmpeg
docker exec jellyfin ffmpeg -version
# Test hardware encoding
docker exec jellyfin ffmpeg -hwaccel vaapi -i /data/movies/sample.mkv -c:v h264_vaapi -f null -
Playback Buffering
Causes:
- Network bandwidth insufficient
- Transcoding too slow (CPU overload)
- Disk I/O bottleneck
- Client compatibility issues
Solutions:
- Enable hardware transcoding
- Lower streaming quality
- Use direct play when possible
- Optimize media files (H264/HEVC)
- Increase transcoding threads
- Use faster storage for transcode directory
Metadata Not Downloading
# Check internet connectivity
docker exec jellyfin ping -c 3 api.themoviedb.org
# Verify metadata providers enabled
# Dashboard → Libraries → Library → Metadata providers
# Force metadata refresh
# Select item → Refresh Metadata → Replace all metadata
# Check naming conventions
# Ensure files follow Jellyfin naming standards
Database Corruption
# Stop Jellyfin
docker stop jellyfin
# Backup database
cp -r /opt/stacks/media/jellyfin/config/data /opt/backups/jellyfin-data-backup
# Check database
sqlite3 /opt/stacks/media/jellyfin/config/data/library.db "PRAGMA integrity_check;"
# If corrupted, restore from backup or rebuild library
# Delete database and rescan (loses watch history)
# rm /opt/stacks/media/jellyfin/config/data/library.db
# Restart
docker start jellyfin
Performance Optimization
Transcoding Performance
# Use RAM disk for transcoding
jellyfin:
volumes:
- /dev/shm:/config/transcodes
# Or fast NVMe
volumes:
- /path/to/fast/nvme:/config/transcodes
Settings:
- Dashboard → Playback → Transcoding
- Transcoding thread count: Number of CPU cores
- Hardware acceleration: Enabled
- H264 encoding CRF: 23 (lower = better quality, more CPU)
- Throttle transcodes: Disabled (for local network)
Database Optimization
# Stop Jellyfin
docker stop jellyfin
# Vacuum databases
sqlite3 /opt/stacks/media/jellyfin/config/data/library.db "VACUUM;"
sqlite3 /opt/stacks/media/jellyfin/config/data/jellyfin.db "VACUUM;"
# Restart
docker start jellyfin
Network Optimization
Settings:
- Dashboard → Networking
- LAN Networks: 192.168.0.0/16,172.16.0.0/12,10.0.0.0/8
- Enable automatic port mapping: Yes
- Public HTTPS port: 8920 (if using)
- Public HTTP port: 8096
Cache Settings
# Separate cache volume for better I/O
jellyfin:
volumes:
- /opt/stacks/media/jellyfin/cache:/cache
Dashboard → System → Caching:
- Clear image cache periodically
- Set cache expiration
Security Best Practices
- Strong Passwords: Enforce for all users
- HTTPS Only: Use Traefik for SSL
- Read-Only Media: Mount media as
:ro - User Permissions: Grant minimal library access
- Network Segmentation: Consider separate VLAN
- Regular Updates: Keep Jellyfin current
- Secure Remote Access: Use VPN or Traefik auth
- Disable UPnP: If not needed for remote access
- API Keys: Regenerate periodically
- Audit Users: Review user accounts regularly
Backup Strategy
Critical Files:
/opt/stacks/media/jellyfin/config/data/ # Databases
/opt/stacks/media/jellyfin/config/config/ # Configuration
/opt/stacks/media/jellyfin/config/metadata/ # Custom metadata
Backup Script:
#!/bin/bash
DATE=$(date +%Y%m%d)
BACKUP_DIR=/opt/backups/jellyfin
# Stop Jellyfin for consistent backup
docker stop jellyfin
# Backup configuration
tar -czf $BACKUP_DIR/jellyfin-config-$DATE.tar.gz \
/opt/stacks/media/jellyfin/config/
# Restart
docker start jellyfin
# Keep last 7 backups
find $BACKUP_DIR -name "jellyfin-config-*.tar.gz" -mtime +7 -delete
Restore:
docker stop jellyfin
tar -xzf jellyfin-config-20240101.tar.gz -C /
docker start jellyfin
Jellyseerr Integration
Pair with Jellyseerr for media requests:
jellyseerr:
image: fallenbagel/jellyseerr:latest
container_name: jellyseerr
environment:
- LOG_LEVEL=info
volumes:
- /opt/stacks/media/jellyseerr/config:/app/config
ports:
- "5055:5055"
Allows users to:
- Request movies/shows
- Track request status
- Get notifications when available
- Browse available content
Summary
Jellyfin is the leading open-source media server offering:
- 100% free, no premium tiers
- Complete privacy, no tracking
- Hardware transcoding for everyone
- Modern, responsive interface
- Active community development
- Plugin extensibility
- Live TV & DVR built-in
Perfect for:
- Privacy-conscious users
- Self-hosting enthusiasts
- Those avoiding subscriptions
- Open-source advocates
- Full control seekers
- GPU transcoding needs (free)
Trade-offs:
- Smaller app ecosystem than Plex
- Less polished UI than Plex
- Fewer smart TV apps
- Smaller community/resources
- Some features less mature
Remember:
- Hardware transcoding is free (unlike Plex Pass)
- No external account required
- All features available without payment
- Active development, improving constantly
- Great alternative to Plex
- Pair with Sonarr/Radarr for automation
- Use Jellyseerr for user requests
- Privacy-first approach
Jellyfin is the best choice for users who want complete control, privacy, and all features without subscriptions!