# How to Set Up Jellyfin Media Server on FreeBSD
Jellyfin is a free, open-source media server that lets you stream your personal movie, TV, and music collection to any device on your network or over the internet. It is the leading community fork of Emby, built entirely without premium tiers, tracking, or subscription fees. If you run FreeBSD as your home server or NAS operating system, Jellyfin is one of the strongest reasons to keep that setup going.
This guide walks through a complete Jellyfin installation on FreeBSD, from creating an isolated jail to configuring transcoding, remote access, and backups. By the end you will have a fully functional, self-hosted media server that rivals any commercial streaming service.
Why Jellyfin on FreeBSD
The Case for Jellyfin Over Plex and Emby
Plex requires a Plex Pass subscription to unlock mobile sync, hardware transcoding, and several other features. Emby follows a similar model. Jellyfin removes all of that friction. Every feature is available from day one, no account creation on a third-party server required.
Key advantages of Jellyfin:
- **Completely free and open source** under the GNU GPL. No premium tier, no telemetry, no phoning home.
- **No central authentication server.** Your media server works even if Jellyfin's website goes offline. Plex users have experienced outages where they could not access their own local media because the central auth server was down.
- **Active development.** The project has a strong community of contributors and regular releases.
- **Plugin ecosystem.** Subtitle downloaders, metadata providers, LDAP authentication, and more can be added through the built-in plugin catalog.
Why FreeBSD as the Host
FreeBSD pairs exceptionally well with media server workloads. ZFS provides checksumming and self-healing for your media library, jails offer lightweight isolation without the overhead of full virtualization, and the network stack is mature and performant. If you are already running a [FreeBSD NAS](/blog/freebsd-nas-build/), adding Jellyfin is a natural next step.
Installation Options
You have two main approaches for installing Jellyfin on FreeBSD:
1. **Inside a jail (recommended).** This isolates Jellyfin from the host system, makes upgrades and rollbacks trivial, and follows FreeBSD best practices for service management.
2. **Directly on the host.** Simpler for single-purpose machines, but offers no isolation.
Both methods use the same package. Jellyfin is available in the FreeBSD ports tree and as a prebuilt binary package.
To install on bare metal:
sh
pkg install jellyfin
The rest of this guide focuses on the jail-based approach, which is the recommended deployment for any multi-service FreeBSD system.
Setting Up Jellyfin in a FreeBSD Jail
If you are new to jails, read the full [FreeBSD jails guide](/blog/freebsd-jails-guide/) first. The steps below assume you have a working jail management tool. This guide uses the built-in jail.conf method, but the same principles apply if you use BastilleBSD, iocage, or another jail manager.
Create the Jail
First, fetch a base system for the jail if you have not already:
sh
fetch https://download.freebsd.org/releases/amd64/14.2-RELEASE/base.txz
mkdir -p /jails/jellyfin
tar -xf base.txz -C /jails/jellyfin
Copy the DNS configuration into the jail:
sh
cp /etc/resolv.conf /jails/jellyfin/etc/resolv.conf
Add the jail definition to /etc/jail.conf:
conf
jellyfin {
host.hostname = "jellyfin";
ip4.addr = "192.168.1.50";
interface = "em0";
path = "/jails/jellyfin";
exec.start = "/bin/sh /etc/rc";
exec.stop = "/bin/sh /etc/rc.shutdown";
mount.devfs;
allow.raw_sockets;
persist;
}
Adjust the IP address and network interface to match your environment.
Start the jail:
sh
service jail start jellyfin
Install Jellyfin Inside the Jail
Enter the jail and install the package:
sh
jexec jellyfin /bin/sh
pkg install jellyfin
sysrc jellyfin_enable="YES"
service jellyfin start
Jellyfin will now be running on port 8096 inside the jail. Open a browser and navigate to http://192.168.1.50:8096 to begin the setup wizard.
Mount Your Media Library Into the Jail
Your media files likely live on a ZFS dataset on the host. Use nullfs mounts to expose them inside the jail without copying anything.
On the host, add the mount to /etc/fstab:
/storage/media /jails/jellyfin/mnt/media nullfs ro 0 0
Then mount it:
sh
mount -a
The ro flag mounts the media read-only inside the jail, which is a sensible security default since Jellyfin only needs to read your files, not write to them.
Inside the jail, verify the media is visible:
sh
jexec jellyfin ls /mnt/media
You should see your movie and TV show directories.
Initial Configuration
When you first open the Jellyfin web interface, a setup wizard walks you through the basics:
1. **Create an admin account.** Choose a strong password. This is a local account stored on your server.
2. **Add media libraries.** Point Jellyfin at the directories inside the jail where your media is mounted. For the example above, you would add /mnt/media/movies as a Movies library and /mnt/media/tv as a TV Shows library.
3. **Set your preferred language and metadata sources.** The defaults (TheMovieDB for movies, TheTVDB for TV) work well for most people.
4. **Configure remote access.** You can skip this during initial setup and configure it properly with a reverse proxy later.
After completing the wizard, Jellyfin will begin scanning your libraries and downloading metadata. This can take a while depending on the size of your collection.
Media Library Organization
Jellyfin relies on consistent file naming to match your media against online databases. Poor naming is the number one cause of incorrect or missing metadata.
Movies
Use the format: Movie Name (Year)/Movie Name (Year).ext
/mnt/media/movies/
Blade Runner 2049 (2017)/
Blade Runner 2049 (2017).mkv
The Matrix (1999)/
The Matrix (1999).mkv
The Matrix (1999).srt
Each movie gets its own folder. Subtitles, artwork, and extras go in the same folder.
TV Shows
Use the format: Show Name (Year)/Season XX/Show Name - SXXEXX - Episode Title.ext
/mnt/media/tv/
Breaking Bad (2008)/
Season 01/
Breaking Bad - S01E01 - Pilot.mkv
Breaking Bad - S01E02 - Cat's in the Bag.mkv
Season 02/
Breaking Bad - S02E01 - Seven Thirty-Seven.mkv
Music
Use the format: Artist/Album (Year)/Track# - Title.ext
/mnt/media/music/
Pink Floyd/
The Dark Side of the Moon (1973)/
01 - Speak to Me.flac
02 - Breathe.flac
Jellyfin supports FLAC, MP3, AAC, OGG, and most other common audio formats.
General Tips
- Avoid special characters in filenames. Stick to alphanumeric characters, hyphens, and parentheses.
- Include the year in parentheses to help Jellyfin distinguish remakes and similarly named titles.
- Store each item in its own subdirectory rather than dumping all files into one flat folder.
Transcoding Setup
Transcoding converts media from one format to another on the fly so that clients which cannot play the original format can still stream it. Jellyfin uses FFmpeg for all transcoding work.
Software Transcoding
FFmpeg is included as a dependency when you install the Jellyfin package. Software transcoding works out of the box. For a small number of simultaneous streams (one or two), a modern multi-core CPU handles this adequately.
To verify FFmpeg is installed inside the jail:
sh
jexec jellyfin which ffmpeg
In the Jellyfin dashboard, go to **Administration > Playback > Transcoding** and confirm the FFmpeg path is set correctly. It is typically /usr/local/bin/ffmpeg.
Hardware Acceleration on FreeBSD
Hardware-accelerated transcoding (using a GPU) significantly reduces CPU usage when multiple users are streaming simultaneously. On FreeBSD the status is as follows:
- **VAAPI (Intel integrated graphics):** Partial support exists. Intel GPUs from Haswell onward can be exposed to the jail by mounting the appropriate /dev/dri device nodes. This requires the drm-kmod package on the host and careful device permissions. Results vary by GPU generation.
- **NVIDIA NVENC:** Not supported on FreeBSD. The NVIDIA driver for FreeBSD does not expose the NVENC encoding interface.
- **AMD VCN/VCE:** Not currently supported on FreeBSD.
For most FreeBSD Jellyfin deployments, software transcoding is the practical choice. If hardware acceleration is critical to your use case, consider running Jellyfin in a Linux jail via FreeBSD's Linux compatibility layer, though this adds significant complexity.
Reducing Transcoding Demand
The best transcoding strategy is to avoid transcoding altogether:
- **Use Direct Play compatible formats.** H.264 video in an MKV or MP4 container with AAC audio plays natively on virtually every client.
- **Pre-convert problematic files.** Use ffmpeg to re-encode files ahead of time rather than relying on real-time transcoding.
- **Set client quality to Original.** In each Jellyfin client app, set the streaming quality to "Original" or "Maximum" to avoid unnecessary transcoding.
Remote Access with NGINX Reverse Proxy
Exposing Jellyfin directly to the internet is not recommended. Instead, place it behind an [NGINX reverse proxy](/blog/nginx-freebsd-production-setup/) with SSL termination.
Install NGINX
On the host or in a dedicated reverse proxy jail:
sh
pkg install nginx
sysrc nginx_enable="YES"
Configure the Reverse Proxy
Create a server block for Jellyfin in your NGINX configuration. A typical setup at /usr/local/etc/nginx/conf.d/jellyfin.conf:
nginx
server {
listen 443 ssl http2;
server_name media.example.com;
ssl_certificate /usr/local/etc/letsencrypt/live/media.example.com/fullchain.pem;
ssl_certificate_key /usr/local/etc/letsencrypt/live/media.example.com/privkey.pem;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!MD5;
client_max_body_size 20M;
location / {
proxy_pass http://192.168.1.50: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_buffering off;
}
location /socket {
proxy_pass http://192.168.1.50:8096/socket;
proxy_http_version 1.1;
proxy_set_header Upgrade $upgrade;
proxy_set_header Connection "upgrade";
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;
}
}
server {
listen 80;
server_name media.example.com;
return 301 https://$host$request_uri;
}
The /socket location block is important. Jellyfin uses WebSockets for real-time updates in the web interface, and without this block you will see connection errors in the browser console.
SSL with Let's Encrypt
Use [Let's Encrypt](/blog/lets-encrypt-freebsd/) to obtain a free SSL certificate. The certbot package with the NGINX plugin makes this straightforward:
sh
pkg install py311-certbot py311-certbot-nginx
certbot --nginx -d media.example.com
Reload NGINX after obtaining the certificate:
sh
service nginx reload
Set up automatic renewal in the host's crontab:
0 3 * * * /usr/local/bin/certbot renew --quiet --deploy-hook "service nginx reload"
Firewall Considerations
If you run PF or IPFW, ensure that ports 80 and 443 are open for inbound traffic from the internet, and that traffic from the reverse proxy can reach the Jellyfin jail on port 8096.
Client Apps
One of Jellyfin's strengths is broad client support. Once your server is running, you can connect from:
- **Web browser.** The built-in web client at your server's URL works on any modern browser. No installation required.
- **Android.** The official Jellyfin app is available on Google Play and F-Droid. It supports offline downloads.
- **iOS and iPadOS.** The Swiftfin app, available on the App Store, provides a native Apple experience. The official Jellyfin iOS app is also available.
- **Android TV and Google TV.** A dedicated app with a TV-friendly interface optimized for remote control navigation.
- **Amazon Fire TV.** The Android TV app works on Fire TV devices. Sideloading is not required since the app is available in the Amazon Appstore.
- **Roku.** A community-maintained Roku client exists in the Roku Channel Store.
- **Kodi.** The Jellyfin for Kodi add-on integrates your Jellyfin libraries directly into Kodi's interface, combining Kodi's powerful playback engine with Jellyfin's server-side management.
- **Desktop.** Jellyfin Media Player (based on mpv and jellyfin-web) is available for Windows, macOS, and Linux. The web interface also works on desktop browsers.
When configuring clients for remote access, point them to your public domain (e.g., https://media.example.com) rather than the local IP address. This ensures the connection works both inside and outside your home network if you have DNS rebinding protection or split DNS configured.
User Management and Parental Controls
Jellyfin supports multiple user accounts, each with their own watch history, preferences, and access controls. This makes it ideal for households with shared media libraries.
Creating Users
In the admin dashboard, go to **Users** and click **Add User.** Assign a username and password. You can optionally allow the user to manage their own password.
Parental Controls
For each user, Jellyfin allows you to:
- **Restrict content by rating.** Block content above a specified rating (e.g., PG-13, R, TV-MA). Jellyfin uses the metadata ratings pulled from TheMovieDB and TheTVDB.
- **Block specific tags or genres.** If you tag content with custom labels, you can restrict access based on those tags.
- **Limit library access.** Show only specific libraries to certain users. For example, a children's account might only see the "Kids Movies" and "Kids TV" libraries.
- **Set access schedules.** Restrict when a user can access the server by defining allowed time windows.
- **Disable downloads.** Prevent users from downloading media for offline use.
Access Control Tips
- Create a separate admin account from your daily viewing account. Use the admin account only for server management.
- Disable the guest account or any account you are not actively using.
- If you share your server with friends or family outside your household, consider setting bandwidth limits per user under the playback settings to prevent a single user from saturating your upload bandwidth.
Performance Tuning
ZFS Dataset Configuration for Media
If you are running ZFS (and you should be on a FreeBSD server), create a dedicated dataset for your media library with tuned properties:
sh
zfs create -o recordsize=1M -o compression=off -o atime=off storage/media
Explanation of each property:
- **recordsize=1M:** Media files are large and read sequentially. A 1 MB record size reduces metadata overhead and improves streaming throughput compared to the default 128 KB.
- **compression=off:** Video and audio files are already compressed. Enabling ZFS compression on them wastes CPU cycles for negligible space savings.
- **atime=off:** Disabling access time updates avoids unnecessary write I/O every time a file is read.
For the Jellyfin configuration and metadata directory, a separate dataset with default settings works well since those files are small and benefit from compression:
sh
zfs create -o compression=lz4 storage/jellyfin-config
Network Tuning
For high-bitrate 4K streams, ensure your network can handle sustained throughput. A single 4K HDR remux can require 60-100 Mbps. For multiple simultaneous streams:
- Use a wired gigabit connection to the server. Wireless is unreliable for high-bitrate streaming.
- If your server has multiple network interfaces, consider dedicating one to media traffic.
- In the FreeBSD kernel, the default socket buffer sizes are usually sufficient, but for heavy concurrent use you can increase them in /etc/sysctl.conf:
kern.ipc.maxsockbuf=16777216
net.inet.tcp.sendbuf_max=16777216
net.inet.tcp.recvbuf_max=16777216
Jellyfin-Specific Tuning
- **Scheduled library scans.** Disable real-time file monitoring and instead schedule library scans during off-peak hours. This reduces I/O contention during peak viewing times.
- **Metadata fetch throttling.** During initial library setup, Jellyfin can hammer metadata APIs. If you have a very large library (thousands of items), consider adding libraries in batches.
- **Log level.** Set the log level to "Warning" in production to reduce disk writes from verbose logging. The default "Information" level generates significant log volume.
Backup Strategy
Configuration Backup
Jellyfin stores its configuration, database, and metadata cache under /var/db/jellyfin inside the jail (the exact path may vary by FreeBSD version). Back up this directory regularly.
If you created a dedicated ZFS dataset for the Jellyfin configuration, snapshots are the simplest backup method:
sh
zfs snapshot storage/jellyfin-config@$(date +%Y%m%d)
Automate this with a cron job:
0 2 * * * /sbin/zfs snapshot storage/jellyfin-config@$(date +\%Y\%m\%d)
Media Backup with ZFS Snapshots
Your media library should also have a snapshot schedule. While media files are often replaceable (you can re-rip or re-download), rebuilding a large library is time-consuming:
sh
zfs snapshot storage/media@weekly-$(date +%Y%m%d)
For offsite backup, use zfs send and zfs receive to replicate snapshots to a remote server:
sh
zfs send storage/media@weekly-20260329 | ssh backup-server zfs receive backup/media
What to Back Up (Priority Order)
1. **Jellyfin database and configuration.** This contains your users, watch history, custom metadata edits, and server settings. Losing this means reconfiguring everything from scratch.
2. **Media library.** The actual video, audio, and image files.
3. **SSL certificates.** If using Let's Encrypt, the certificates auto-renew, but having a backup avoids downtime during a rebuild.
Upgrading Jellyfin
When a new version of Jellyfin is released and lands in the FreeBSD package repository, upgrading is straightforward.
Inside the jail:
sh
pkg update
pkg upgrade jellyfin
service jellyfin restart
Before upgrading, take a ZFS snapshot of the configuration dataset so you can roll back if the new version introduces issues:
sh
zfs snapshot storage/jellyfin-config@pre-upgrade-$(date +%Y%m%d)
Check the Jellyfin release notes before upgrading. Major version bumps occasionally require database migrations that cannot be reversed.
Frequently Asked Questions
Can Jellyfin play 4K HDR content?
Yes. Jellyfin can direct-play 4K HDR content to clients that support it (such as Android TV, Apple TV via Swiftfin, or Kodi). The server does not need to transcode if the client can handle the original format. However, if transcoding is triggered on HDR content, tone mapping is required to avoid washed-out colors, and this is CPU-intensive. Avoid transcoding 4K HDR whenever possible.
How does Jellyfin compare to Plex on FreeBSD?
Plex Media Server is also available as a FreeBSD package. The main differences are: Plex requires a Plex account and connects to Plex's central servers for authentication. Plex has a more polished out-of-box experience and wider smart TV support. Jellyfin is fully open source, requires no external accounts, and gives you complete control. For a privacy-conscious FreeBSD user, Jellyfin is generally the better fit.
Can I run Jellyfin alongside other services in the same jail?
You can, but it is not recommended. The point of using jails is isolation. Running Jellyfin in its own jail means you can upgrade, restart, or rebuild it without affecting other services. The resource overhead of an additional jail is minimal.
Does Jellyfin support live TV and DVR?
Yes. Jellyfin supports live TV through HDHomeRun tuners and other TV tuner devices that provide an HTTP or M3U stream. You can set up recording schedules through the Jellyfin interface. On FreeBSD, ensure the tuner hardware is accessible inside the jail if you take that route.
How much CPU and RAM does Jellyfin need?
For direct play (no transcoding), Jellyfin is very lightweight. Even a low-power system with 2 GB of RAM can serve several simultaneous direct-play streams. If you need software transcoding, plan for roughly one modern CPU core per simultaneous 1080p transcode. 4K transcoding requires significantly more. 8 GB of RAM is a comfortable minimum for a server handling transcoding alongside other services.
Can I migrate from Plex or Emby to Jellyfin?
There are community tools to migrate watch history and user data from both Plex and Emby to Jellyfin. The media files themselves do not need to change since Jellyfin reads the same file formats. Library organization conventions are also compatible.
Is Jellyfin accessible from outside my home network?
Yes, once you configure the NGINX reverse proxy and SSL as described above. Point your domain to your public IP (or use dynamic DNS if your IP changes), forward ports 80 and 443 to your reverse proxy, and you can stream from anywhere. A VPN is an alternative approach that avoids exposing any ports.
Conclusion
Jellyfin on FreeBSD is a powerful combination for anyone who wants full control over their media streaming setup. FreeBSD's jails provide clean isolation, ZFS protects your data, and Jellyfin delivers a modern streaming experience without vendor lock-in or subscription fees.
Start with the jail-based installation described here, get your libraries organized with proper naming, set up the reverse proxy for remote access, and you have a setup that competes with any commercial streaming platform while running entirely on hardware you own.