How to Self-Host Jellyfin and Stream Your Media from Anywhere
Jellyfin is a free and open-source media server that lets you organize, manage, and stream your movies, TV shows, music, and photos from your own hardware. No subscription fees, no content restrictions, no data sent to third parties. This guide walks you through installing Jellyfin with Docker Compose, setting up your libraries, and making your media server reachable from any device in the world using a Localtonet tunnel.
📋 What's in this guide
What Is Jellyfin?
Jellyfin is an open-source fork of Emby that gives you a full media server platform with no strings attached. It organizes your media files into libraries, fetches metadata and artwork automatically, and streams everything to a wide range of client apps on phones, tablets, smart TVs, and browsers. There are no premium tiers, no remote streaming paywalls, and no account required to use your own server.
Plex is the most well-known self-hosted media server, but it requires a Plex account, sends usage data to Plex's servers, and in recent years has moved remote streaming features behind a paid subscription. Jellyfin has none of those limitations. Everything runs on your hardware and your network, and remote access is built in without any extra cost.
Jellyfin
- Completely free, no subscription
- No account required to run your server
- Remote streaming works without a paid plan
- No data sent to third-party servers
- Fully open source, community maintained
- No content restrictions on your own files
Plex
- Remote streaming requires Plex Pass subscription
- Requires a Plex account even for local use
- Usage data shared with Plex Inc.
- Closed source core
- Free tier has growing limitations over time
Install Jellyfin with Docker Compose
Docker Compose is the recommended way to run Jellyfin. It handles updates cleanly, keeps configuration isolated, and works on any Linux machine including a Raspberry Pi or a NAS.
Create the project directory
mkdir jellyfin && cd jellyfin
Create the Docker Compose file
Create a docker-compose.yml file with the following content.
Update the media volume paths to match where your files actually live on the host machine.
services:
jellyfin:
image: jellyfin/jellyfin:latest
container_name: jellyfin
user: "1000:1000"
restart: unless-stopped
ports:
- "8096:8096"
volumes:
- ./config:/config
- ./cache:/cache
- /path/to/your/movies:/data/movies:ro
- /path/to/your/tvshows:/data/tvshows:ro
- /path/to/your/music:/data/music:ro
environment:
- TZ=Europe/Istanbul
The user: "1000:1000" line tells Docker to run Jellyfin as your regular user account
rather than root. This avoids permission errors when Jellyfin reads and writes to the config and cache folders.
Run id $(whoami) in your terminal to confirm your UID and GID replace 1000:1000 if they are different.
Create the config and cache directories and set permissions
mkdir -p config cache
sudo chown -R 1000:1000 config cache
Start Jellyfin
docker compose up -d
docker compose ps
Jellyfin is now running at http://localhost:8096. Open that address in a browser on the same machine
to start the setup wizard.
If you want to use your GPU to transcode video for slower client devices, add a
devices section to the Compose file. For Intel Quick Sync add
/dev/dri/renderD128:/dev/dri/renderD128. For NVIDIA, use the
nvidia runtime. Hardware transcoding is optional Jellyfin falls back to
software transcoding automatically.
Complete the Setup Wizard
Choose your language and create an admin account
Select your preferred language, then create the administrator account. Pick a strong username and password. This is the account that controls all settings and user management.
Add your media libraries
Click Add Media Library and select the content type Movies, TV Shows, Music, or Photos.
Set the folder path to one of the /data/ paths you mounted in the Compose file,
for example /data/movies. Jellyfin scans the folder and fetches metadata automatically.
Add one library for each media type.
Configure remote access
On the remote access screen, check Allow remote connections to this server. Leave Enable automatic port mapping unchecked you will use a Localtonet tunnel instead of port forwarding. Click Next and then Finish.
Jellyfin redirects you to the dashboard after the wizard finishes. The library scan runs in the background and your media will appear within a few minutes.
Client Apps
Once your server is running, you can watch your media from nearly any device.
All apps connect to your Jellyfin server using its address on your local network that is
http://your-server-ip:8096, and from outside it will be your Localtonet tunnel URL.
| Platform | App | Where to get it |
|---|---|---|
| Web browser | Built-in web client | Open http://server:8096 in any browser |
| Android | Jellyfin for Android | Google Play Store |
| iOS / iPadOS | Jellyfin Mobile | Apple App Store |
| Android TV / Fire TV | Jellyfin for Android TV | Google Play / Amazon Appstore |
| Apple TV | Jellyfin for tvOS | Apple App Store |
| Roku | Jellyfin for Roku | Roku Channel Store |
| Kodi | Jellyfin for Kodi | Kodi repository |
Stream from Anywhere with Localtonet
Jellyfin listens on port 8096. Without a public address, it is only reachable on your local network.
Localtonet creates an encrypted HTTP tunnel that gives your server a public HTTPS URL
without any router configuration or firewall changes.
Install and authenticate Localtonet on the host machine
curl -fsSL https://localtonet.com/install.sh | sh
localtonet --authtoken <YOUR_TOKEN>
Create an HTTP tunnel for port 8096
Log in to the Localtonet dashboard, go to Tunnels → New Tunnel,
select HTTP, set local IP to 127.0.0.1 and port to 8096.
Click Create. You receive a public HTTPS URL such as https://abc123.localto.net.
Update the published server URL in Jellyfin
In Jellyfin, go to Dashboard → Networking. Set Published server URL to your Localtonet HTTPS address. This tells Jellyfin to include the correct public URL in responses to client apps, so they know where to reach the server from outside your network. Click Save.
Connect from any device
Open the Jellyfin app on your phone, TV, or browser. Enter your Localtonet HTTPS URL as the server address. Log in with your Jellyfin credentials and start streaming.
If you want a stable, branded URL for your Jellyfin server something like
https://media.yourdomain.com attach a custom domain to your HTTP tunnel.
Client apps and family members can then use the same address permanently.
See our custom domain guide for setup steps.
Keep Everything Running After a Reboot
The Compose file already has restart: unless-stopped on the Jellyfin container,
so it starts automatically with Docker after every boot.
Register Localtonet as a systemd service so the tunnel also comes back without any manual steps:
sudo localtonet --install-service --authtoken <YOUR_TOKEN>
sudo localtonet --start-service --authtoken <YOUR_TOKEN>
Verify both are running:
docker compose ps
systemctl status localtonet
After this, rebooting the host machine brings your Jellyfin server and its public URL back automatically. Family members and remote clients can connect again within seconds of the machine booting up.
Security Recommendations
🔑 Use a strong admin password
Your Jellyfin admin account controls the entire server including all user data and media libraries. Use a long, unique password. Do not reuse passwords from other services. You can change it at any time under Dashboard → Users.
👤 Create separate accounts for family members
Do not share the admin account with other people. Create a regular user account for each person under Dashboard → Users → Add User. Regular accounts can watch media but cannot change server settings. You can also set up parental controls per user to restrict content by rating.
🌍 Keep port 8096 off the public internet
Use the Localtonet tunnel instead of port forwarding. Jellyfin stays bound to
localhost only. The tunnel provides TLS and a public URL without
exposing the port directly to scanners and automated attack tools.
📦 Keep Jellyfin updated
Pull the latest image and recreate the container regularly to get security fixes and new features.
Because the data lives in the ./config volume on the host, updating never wipes your settings.
docker compose pull
docker compose up -d
Frequently Asked Questions
Can I run Jellyfin on a Raspberry Pi?
Yes. The official Jellyfin Docker image supports ARM and ARM64. A Raspberry Pi 4 or Pi 5 handles Jellyfin well for a few concurrent users. Hardware transcoding is supported on the Pi 4 using V4L2 for H.264 decoding. For 4K content or many simultaneous streams, a more powerful machine is recommended.
Video keeps buffering or stopping. What should I check?
Buffering usually means the server is transcoding the video in software and cannot keep up, or your upload bandwidth is not sufficient for the bitrate. First, check Dashboard → Active Devices to see if transcoding is happening. Enable hardware transcoding if your hardware supports it. Alternatively, change the client playback quality to a lower bitrate, or use a client that can direct play the original file without transcoding.
My movies show wrong metadata or artwork. How do I fix it?
Jellyfin matches files to metadata using the filename. Name your files following the standard format: Movie Title (Year).mkv for movies and Show Name/Season 01/Show Name S01E01.mkv for TV. Right-click any item in the Jellyfin UI and choose Identify to manually search for the correct match.
Can I share my server with friends who live in other countries?
Yes. Create a user account for each friend in Jellyfin and share your Localtonet tunnel URL with them. They enter the URL in their Jellyfin app and log in with the credentials you created. The content streams from your hardware to their device. Keep in mind that your upload bandwidth determines how many people can stream simultaneously.
Will Jellyfin work with subtitles?
Yes. Jellyfin supports embedded subtitles in video files as well as external subtitle files (.srt, .ass, .vtt) placed alongside the video. You can also install the OpenSubtitles plugin from the plugin repository to search and download subtitles automatically for your library.
How do I add more media after the initial setup?
Mount the new media directory in the Compose file by adding a new volume entry, then restart the container with docker compose up -d. In Jellyfin, go to Dashboard → Libraries and add the new path to the relevant library, or create a new library for it. Jellyfin scans and adds the new content automatically.
Your Personal Streaming Service, on Your Own Hardware
Install Jellyfin with Docker Compose, point it at your media files, and open a Localtonet tunnel. Your movies and shows are available on every device, from anywhere in the world, for free.
Create Free Localtonet Account →