What Is Jellyfin
Jellyfin is a free, open-source media server that lets you stream your personal collection of movies, TV shows, music, and live TV to any device. It is a fully self-hosted alternative to Plex and Emby, built from the ground up without any paywalls, tracking, or external dependencies. You control every aspect of your media library, from metadata management to user accounts and transcoding settings.
Jellyfin is built on the .NET Core framework and ships as a lightweight server application that you install on a home server, NAS, old laptop, or even a Raspberry Pi. Once running, it indexes your media folders, fetches metadata from sources like TMDB and TVDB, and presents a polished web interface that works across browsers, smart TVs, smartphones, and set-top boxes.
Why Run Your Own Media Server
🚀 Deploy your AI agent in 10 minutes
Managed Hermes hosting. Zero DevOps. 100M tokens/mo included.
Try it free →Running your own media server gives you complete ownership over your content. Streaming services rotate titles, impose region restrictions, and compress quality to save bandwidth. With a home media server, your 4K Blu-ray rips stay in full quality, your curated collections never disappear, and you can watch anything you own on any device in your household — even when the internet goes down.
Jellyfin specifically matters because it is fully open-source under the GPL license. There are no premium features locked behind a subscription, no user analytics phoning home, and no centralized authentication servers that could go offline. For developers and self-hosting enthusiasts, this means complete transparency, full API access, and the ability to extend functionality through a rich plugin ecosystem.
Prerequisites and Hardware Considerations
Before installing Jellyfin, assess what hardware you have and what you need. The minimum requirements are modest, but transcoding — converting video formats on the fly to suit a client device — changes the equation significantly.
- CPU: Any dual-core processor for direct-play streaming; Intel Core i5/i7 with Quick Sync Video (6th gen or newer) for hardware-accelerated transcoding
- RAM: 2 GB minimum, 4–8 GB recommended if running alongside other services
- Storage: Enough to hold your media library; a dedicated NAS or external drive array works well
- OS: Linux (Ubuntu Server, Debian, or a dedicated NAS OS like TrueNAS), Windows, macOS, or Docker
- GPU (optional): NVIDIA GPU with NVENC support, Intel iGPU with VAAPI, or an Apple Silicon chip for hardware transcoding
If you plan to stream primarily to modern devices that support the codecs your media uses (direct play), a Raspberry Pi 4 can serve as a capable Jellyfin server. If you need to transcode 4K HDR content for older clients, invest in a machine with hardware acceleration support.
Installation Methods
Option 1: Native Package Installation on Linux (Ubuntu/Debian)
This method installs Jellyfin directly on the system. It is straightforward and gives you full access to hardware acceleration without Docker abstraction layers.
# Install dependencies
sudo apt update && sudo apt install -y curl gnupg apt-transport-https
# Add Jellyfin repository
curl -fsSL https://repo.jellyfin.org/jellyfin_team.gpg.key | sudo gpg --dearmor -o /etc/apt/trusted.gpg.d/jellyfin.gpg
echo "deb [arch=$(dpkg --print-architecture)] https://repo.jellyfin.org/$(awk -F'=' '/^ID=/{ print $NF }' /etc/os-release) $(awk -F'=' '/^VERSION_CODENAME=/{ print $NF }' /etc/os-release) main" | sudo tee /etc/apt/sources.list.d/jellyfin.list
# Install Jellyfin
sudo apt update && sudo apt install -y jellyfin
# Enable and start the service
sudo systemctl enable jellyfin
sudo systemctl start jellyfin
# Check status
sudo systemctl status jellyfin
Once installed, Jellyfin listens on port 8096 by default. Open http://your-server-ip:8096 in a browser to begin setup.
Option 2: Docker Compose Installation
Docker offers isolation, easy updates, and portability. This is the recommended approach for most homelab setups, especially when combining Jellyfin with a reverse proxy and other services.
version: "3.8"
services:
jellyfin:
image: jellyfin/jellyfin:latest
container_name: jellyfin
restart: unless-stopped
ports:
- "8096:8096" # HTTP web UI
- "8920:8920" # HTTPS (optional)
volumes:
- ./jellyfin/config:/config
- ./jellyfin/cache:/cache
- /mnt/media/movies:/media/movies:ro
- /mnt/media/tv:/media/tv:ro
- /mnt/media/music:/media/music:ro
environment:
- TZ=America/New_York
- JELLYFIN_PUBLISHED_SERVER_URL=http://your-server-ip:8096
devices:
- /dev/dri:/dev/dri # For Intel Quick Sync hardware acceleration
group_add:
- "44" # video group ID for /dev/dri access (check with `getent group video`)
Place this file in a directory, then run:
docker-compose up -d
Verify the container is running with docker ps. Access the web interface at http://your-server-ip:8096.
Initial Setup Walkthrough
When you first open Jellyfin, a setup wizard guides you through essential configuration. Here is what to pay attention to at each step.
1. Create the Admin User
Set a strong username and password for the administrator account. This account has full control over server settings, user management, and library permissions. You can create additional non-admin users later for family members.
2. Configure Media Libraries
This is where you tell Jellyfin where your media lives. For each library type (Movies, Shows, Music), point Jellyfin to the mounted volume or directory containing that media. The folder structure matters — Jellyfin recognizes media more reliably when you follow standard naming conventions.
Example directory structure:
/mnt/media/movies/
├── Inception (2010)/
│ └── Inception (2010).mkv
├── The Matrix (1999)/
│ └── The Matrix (1999).mkv
/mnt/media/tv/
├── Breaking Bad/
│ ├── Season 1/
│ │ ├── Breaking Bad - S01E01 - Pilot.mkv
│ │ └── Breaking Bad - S01E02 - Cat's in the Bag.mkv
│ └── Season 2/
│ └── Breaking Bad - S02E01 - Seven Thirty-Seven.mkv
For each library, select the content type, choose metadata providers (TMDB and TVDB are default and work well), and enable chapter image extraction if desired. Jellyfin scans the folders and begins populating artwork, descriptions, and cast information.
3. Configure Metadata Languages and Providers
Set your preferred language for metadata and artwork. You can prioritize metadata downloaders — for example, place TMDB above TVDB if you prefer their episode ordering. Enable Open Subtitles or other subtitle plugins if you want automatic subtitle fetching.
4. Enable Hardware Acceleration (Optional but Recommended)
Navigate to Dashboard > Playback > Transcoding. Choose the appropriate hardware acceleration method:
- VAAPI: For Intel integrated GPUs on Linux (most common homelab setup)
- NVENC: For NVIDIA dedicated GPUs
- VideoToolbox: For Apple Silicon / macOS
- QuickSync: For Intel GPUs on Windows
Check the box for "Enable hardware decoding for" the relevant codecs (H.264, HEVC, MPEG2, etc.) and save. To verify it works, play a media file that requires transcoding and check the dashboard for "(HW)" indicators next to the transcoding stream.
User Management and Permissions
Jellyfin lets you create individual user accounts with fine-grained access control. This is useful for households where children should see only certain content, or where you want to keep watch history separate.
# Creating a user via the Jellyfin API (useful for automation scripts)
curl -X POST "http://localhost:8096/Users/New" \
-H "Content-Type: application/json" \
-H "Authorization: MediaBrowser Token=YOUR_ADMIN_API_KEY" \
-d '{
"Name": "FamilyAccount",
"Password": "secure-password-here",
"Enabled": true,
"EnableUserPreferenceAccess": true,
"EnableRemoteAccess": true
}'
From the web dashboard, you can then assign library access per user — restrict certain libraries to adults only, or grant read-only access to specific folders. Parental rating filters are also available based on content metadata.
Client Applications and Remote Access
Jellyfin works across a wide range of client devices:
- Web browser: Access directly at the server URL; no installation needed
- Jellyfin Media Player: Desktop application for Windows, macOS, and Linux with native codec support
- Android / Android TV: Official app on Google Play and Amazon Appstore
- iOS / Apple TV: SwiftFin app on the App Store
- Roku: Official Jellyfin channel
- Kodi: Use the Jellyfin for Kodi add-on for a native-feeling experience
- Infuse (Apple): Direct connection to Jellyfin server
For remote access outside your home network, you have several options:
- VPN: WireGuard or Tailscale for the most secure approach — clients connect to your VPN, then access Jellyfin as if local
- Reverse proxy with HTTPS: Use Nginx, Caddy, or Traefik to expose Jellyfin with SSL termination
- Cloudflare Tunnel: Expose Jellyfin through Cloudflare without opening ports on your router
Setting Up Nginx Reverse Proxy
This example configures Nginx with SSL (using Let's Encrypt) and optimizes connection handling for streaming:
server {
listen 443 ssl http2;
server_name jellyfin.yourdomain.com;
ssl_certificate /etc/letsencrypt/live/jellyfin.yourdomain.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/jellyfin.yourdomain.com/privkey.pem;
client_max_body_size 100M;
location / {
proxy_pass http://localhost:8096;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Host $host;
# WebSocket support for Jellyfin live updates
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
# Increase timeout for streaming
proxy_read_timeout 600s;
proxy_send_timeout 600s;
}
}
After configuring the reverse proxy, update the JELLYFIN_PUBLISHED_SERVER_URL environment variable (or the "Published Server URL" in Dashboard > Networking) to match your public HTTPS URL.
Automating Media Organization
Keeping a clean media library structure manually becomes tedious. The Sonarr, Radarr, and Bazarr stack automates TV show management, movie management, and subtitle fetching respectively. They integrate directly with Jellyfin to notify the server when new content arrives.
Docker Compose Integration Example
# Add these services to your existing docker-compose.yml
sonarr:
image: linuxserver/sonarr:latest
container_name: sonarr
restart: unless-stopped
ports:
- "8989:8989"
volumes:
- ./sonarr/config:/config
- /mnt/media/tv:/media/tv
- /mnt/downloads:/downloads
environment:
- TZ=America/New_York
radarr:
image: linuxserver/radarr:latest
container_name: radarr
restart: unless-stopped
ports:
- "7878:7878"
volumes:
- ./radarr/config:/config
- /mnt/media/movies:/media/movies
- /mnt/downloads:/downloads
environment:
- TZ=America/New_York
In Sonarr/Radarr settings, under Connect, add a Jellyfin connection with your server URL and API key. When a download completes, the application renames and moves the file to your media folder and tells Jellyfin to refresh that library automatically.
Best Practices for a Production Home Server
- Use consistent media naming: Follow the
Name (Year)/Name (Year).extconvention for movies andShow Name - S01E01 - Episode Title.extfor TV episodes. This dramatically improves metadata matching accuracy. - Separate config from data: Always mount Jellyfin's
/configdirectory on persistent storage (a bind mount in Docker or a dedicated directory on bare metal). Back up this directory regularly — it contains all user accounts, watch history, and library settings. - Pre-transcode or optimize for direct play: Use media formats that your target devices support natively (H.264 in MKV/MP4 with AAC audio works everywhere). This reduces server load and improves playback start time. If you must transcode, do it ahead of time with tools like Tdarr or Unmanic rather than on-the-fly.
- Enable hardware acceleration: Even a modest Intel iGPU can handle multiple simultaneous 1080p transcodes. Without hardware acceleration, a single 4K-to-1080p transcode can max out a CPU. Test with
intel_gpu_top(Linux) ornvidia-smito confirm hardware encoding is active. - Set up monitoring: Use tools like
htop,glances, or Prometheus exporters to watch CPU usage, memory, and disk I/O. Jellyfin's dashboard shows active streams and transcoding status. - Implement automatic backups: Schedule regular backups of the Jellyfin config directory. Losing your database means losing all user accounts, watch progress, and custom metadata.
- Use a reverse proxy with SSL: Never expose Jellyfin directly over HTTP on the internet. A reverse proxy with Let's Encrypt provides TLS encryption and lets you host multiple services on one domain.
- Keep plugins minimal: Each plugin adds overhead. Only install what you genuinely need — metadata providers, subtitle fetchers, and maybe a theme plugin. Test plugin compatibility after Jellyfin upgrades.
- Regularly update but pin versions in production: Jellyfin releases stable updates monthly. In Docker, use a specific version tag (
jellyfin/jellyfin:10.9.6) rather than:latestfor production to avoid unexpected breaking changes. - Set resource limits in Docker: Prevent Jellyfin from consuming all system resources by adding
mem_limitand CPU constraints in your Docker Compose file, especially if sharing the host with other services.
Troubleshooting Common Issues
Media Not Appearing in Library
Check file permissions. Jellyfin runs as the jellyfin user on native installations or as the configured user in Docker. Ensure the user has at least read access to your media directories:
# Check permissions on media mount
ls -la /mnt/media/movies
# Fix read permissions recursively
sudo chmod -R a+r /mnt/media/movies
sudo chmod -R a+r /mnt/media/tv
Also verify your folder structure matches Jellyfin's expected conventions. Misnamed files are often ignored or matched incorrectly.
Transcoding Performance Issues
If playback stutters or the server CPU spikes, check whether hardware acceleration is actually working. In the Jellyfin dashboard during playback, look for the "(HW)" tag next to the transcode info. If absent, verify:
# Check if /dev/dri is available inside the container (Docker)
docker exec jellyfin ls -la /dev/dri
# Verify VAAPI support on the host
vainfo
# Check Intel GPU usage during transcoding
intel_gpu_top
If VAAPI fails, ensure the renderD128 device is passed through and the container has the correct group permissions (video group, typically GID 44).
Reverse Proxy WebSocket Errors
If the web interface loads but content fails to play or shows spinner indefinitely, WebSocket connections are likely being blocked. Ensure your proxy configuration includes the Upgrade and Connection headers as shown in the Nginx example above.
Conclusion
Setting up Jellyfin transforms your scattered media collection into a polished, Netflix-like streaming service that you fully control. From a simple single-machine installation to a Dockerized homelab stack with automated media pipelines, hardware-accelerated transcoding, and secure remote access, Jellyfin adapts to your technical comfort level and hardware constraints. The open-source nature means you never lose access to your data or features, and the active community ensures continuous improvement. Start with the basics — install, add a library, and play something — then layer on automation, monitoring, and remote access as your needs grow. The result is a media server that serves you exactly the way you want, on every screen you own, with no monthly fees and no compromises.