Why leave Plex now
For years, Plex offered remote access for free. In July 2026, that changed: without a Plex Pass subscription ($2.99/month or $749.99 lifetime), streaming outside your local network is blocked. The notification or the first access refusal from a mobile device or remote desktop is often the trigger: the user looks for an immediate exit, not a lengthy evaluation.
Jellyfin is the direct answer. It is a community fork of the Emby codebase, released under GPL-2.0 license, with no mandatory account, no telemetry, and no feature locked behind a paywall. It implements the Plex API — meaning existing Plex clients (Infuse, Plexamp, nPlayer, and others) continue to work without major reconfiguration. Media files do not move: only the server layer changes.
What Jellyfin delivers in practice
- Zero paywall — remote access, multi-user accounts and transcoding are available without any subscription or lifetime Pass.
- No mandatory account — setup does not require linking an external service; user management is entirely local.
- Zero telemetry — no usage data is sent to a third party by default; the code is auditable (GPL-2.0).
- Plex API compatibility — clients that speak the Plex API detect Jellyfin as a standard Plex server, with no client-side migration needed.
- Media files stay in place — only the metadata database needs to be rebuilt; storage is untouched.
- Native clients available — Android, iOS, Android TV, Apple TV, web browser, and dozens of third-party apps support Jellyfin natively.
- Hardware transcoding supported — Intel Quick Sync, VAAPI and NVENC are configurable to reduce CPU load on high-definition streams.
- Active community and regular updates — frequent releases, community plugins, and comprehensive official documentation.
Requirements before you start
The migration assumes you already have a VPS with Docker installed. Jellyfin in Direct Play mode (devices read the file without transcoding) runs well with 2 vCPUs and 2 GB RAM. If you expect software 1080p transcoding, count at least 4 vCPUs per simultaneous stream: Jellyfin is CPU-intensive without hardware acceleration. For 4K, a GPU or an Intel chip with Quick Sync are strongly recommended.
Storage is the main sizing factor: a medium-sized media library weighs several terabytes. Your media files stay where they are — there is nothing to copy. On the network side, your domain must point to the VPS and port 8096 must be reachable internally (the reverse proxy handles HTTPS exposure).
In summary: a Linux VPS (Debian 12 or Ubuntu 22.04+), Docker and docker compose v2, a configured domain, a reverse proxy (Caddy or Nginx), and SSH access to the server.
Step-by-step migration
Export your Plex data before stopping the service
Before anything else, export your Plex library while it is still running. From the Plex server, copy the metadata folder (~/.config/Plex Media Server/ on Linux, /var/lib/plexmediaserver/ depending on the install). This backup lets you recover playlists, watch progress and ratings if you ever decide to go back.
Your media files (/mnt/media/films, /mnt/media/series, etc.) do not move — do not relocate them.
Stop Plex cleanly
Stop the Plex container or service:
docker compose stop plexOr, if Plex runs via systemd:
systemctl stop plexmediaserverFree up port 32400; Jellyfin will use 8096 by default, so you can leave the Plex port free or close it in your firewall.
Create the Jellyfin folder structure
Create the configuration and cache directories Jellyfin will use:
mkdir -p /opt/jellyfin/config /opt/jellyfin/cacheYour media remain at their original location — do not move them. Jellyfin will declare them as libraries in the initial wizard.
Write the docker-compose.yml file
Create /opt/jellyfin/docker-compose.yml with the following content:
cat > /opt/jellyfin/docker-compose.yml << 'EOF'
services:
jellyfin:
image: jellyfin/jellyfin:latest
container_name: jellyfin
restart: unless-stopped
environment:
- JELLYFIN_PublishedServerUrl=https://media.yourdomain.com
volumes:
- /opt/jellyfin/config:/config
- /opt/jellyfin/cache:/cache
- /mnt/media:/media:ro
ports:
- "127.0.0.1:8096:8096"
EOFAdjust /mnt/media to the actual path of your media. The :ro (read-only) flag is good practice: Jellyfin does not need to write to your media files.
Start Jellyfin and run the initial wizard
Start the container:
docker compose -f /opt/jellyfin/docker-compose.yml up -dOpen http://your-ip:8096 in a browser. The wizard asks you to create a local admin account (no external email address required), then to declare your libraries. Point to your existing media folders (/media/films, /media/series, etc.) — Jellyfin launches an automatic scan and rebuilds metadata from TheMovieDB and TheTVDB.
Configure the reverse proxy with SSL
Expose Jellyfin over HTTPS via Caddy or Nginx. Example Caddy configuration (Caddyfile):
media.yourdomain.com {
reverse_proxy 127.0.0.1:8096
}Caddy obtains and renews the Let's Encrypt certificate automatically. With Nginx, add the X-Real-IP and X-Forwarded-For headers that Jellyfin uses for access logs.
Reconfigure your clients and enable remote access
In Jellyfin (Dashboard → Networking), verify that the published URL (JELLYFIN_PublishedServerUrl) is correct. Native Jellyfin apps (Android, iOS, Apple TV) can add the server by URL. Clients that support the Plex API (Infuse, for example) can also point to Jellyfin: in the Infuse settings, add a Plex server and enter your Jellyfin URL — the discovery protocol is compatible.
Verify access from a mobile connection (not your Wi-Fi) to confirm that remote access works without restriction.
Migrate playlists and watch progress (optional)
Jellyfin does not natively read Plex's SQLite database. Two options: manually recreate playlists in the Jellyfin interface (a few minutes for a typical user), or use the community tool PlexToJellyfin to import watch progress (last episode watched, playback time) from Plex's XML export. This script reads the Plex Media Server/Plug-in Support/Databases/ file and pushes data via the Jellyfin API.
Plex Pass 2026 vs Jellyfin: functional comparison
| Feature | Plex (without Pass) | Jellyfin |
|---|---|---|
| Local streaming (home network) | Yes | Yes |
| Remote streaming (off-network) | Paid ($2.99/month) | Free |
| Mandatory external account | Yes | No |
| Telemetry / data sent | Yes | No (by default) |
| Code license | Proprietary | GPL-2.0 |
| Plex client compatibility (API) | Native | Yes (API emulation) |
| Hardware transcoding | Paid (Pass required) | Free |
| Multi-user accounts | Limited without Pass | No cap, local |
Recommended post-installation configuration
Once the migration is complete, a few settings improve day-to-day experience.
Metadata. Jellyfin uses TheMovieDB and TheTVDB by default. If some films or series are not recognized automatically, rename files using the convention Title (Year)/Title (Year).mkv for films and Series/Season 01/Series - S01E01.mkv for series — Jellyfin applies these conventions during scanning.
Subtitles. Enable OpenSubtitles or embedded subtitles under Dashboard → Plugins. Retrieval is automatic during library scans.
Hardware transcoding. If your VPS has an Intel chip, enable VAAPI under Dashboard → Playback → Transcoding. This significantly reduces CPU load during stream conversions.
Securing Jellyfin access
Jellyfin exposes a public web interface by default once behind your reverse proxy. A few hardening measures to apply at launch: disable public account creation (Dashboard → Users → Disable registration), enable two-factor authentication for the admin account, and restrict access to the admin interface to the local network where possible. If you use Nginx, add a rate limit on /Users/AuthenticateByName routes to slow brute-force attempts. Finally, keep the Docker image up to date: docker compose pull && docker compose up -d is sufficient to pick up security patches.
Troubleshooting: common errors after migration
A few errors come up consistently during a Plex → Jellyfin migration.
Connection refused on port 8096. The container is started but nothing responds. Check that the port mapping is 127.0.0.1:8096:8096 and not 0.0.0.0:8096:8096 if you intend to route through the reverse proxy. Diagnostic command: docker logs jellyfin.
Metadata fails to load. The initial scan can take from 10 minutes to several hours depending on library size. Monitor progress under Dashboard → Activity. If files remain without posters, check that the filename follows the convention and force a new scan with "Scan library files".
Remote access does not work. If https://media.yourdomain.com responds from the server but not from outside, check that the firewall allows port 443 (ufw allow 443), that DNS points to the correct IP, and that JELLYFIN_PublishedServerUrl matches exactly the public URL configured in the reverse proxy.
Infuse or a Plex-compatible client does not detect the server. In Infuse, select "Plex" as the server type and manually enter your Jellyfin URL. Automatic discovery via Bonjour does not work outside the local network — a manual URL is always more reliable.
CPU transcoding spikes to 100%. Without hardware acceleration, a single 4K transcoding stream can saturate several cores. Switch to VAAPI if your processor supports it, or encourage your users to enable Direct Play in their client settings.
Further reading and related guides
The migration covers replacing Plex, but Jellyfin fits into a broader ecosystem. If you are starting from scratch (without a prior Plex install), the guide Hosting Jellyfin on your own VPS covers the initial installation from the beginning. For an in-depth functional comparison between the two platforms, see Jellyfin vs Plex: which media server to choose.
If this migration is part of a broader move toward self-hosting to reduce SaaS costs, hosting Ghost on your VPS covers another common case. The logic is the same: open-source software, a VPS, access you control.
The official Jellyfin documentation (docs.jellyfin.org) is comprehensive and actively maintained — it is the reference for advanced use cases (hardware transcoding, LDAP, plugins, advanced reverse proxy).