Building the Ultimate Self-Hosted Media Center with Jellyfin

Building the Ultimate Self-Hosted Media Center with Jellyfin
The Ultimate Self-Hosted Media Center

In the age of rising subscription costs and disappearing content, owning your media is the only true freedom. Over the last few months, I have refined my homelab to create the "Ultimate Media Center"—a setup that rivals Netflix for video and Spotify for music, but runs entirely on my own hardware.

At the heart of this system is Jellyfin, the free, open-source media server that puts privacy and control first. Here is a detailed look at the hardware, storage, and client apps that make this setup sing.

Why I Chose Jellyfin (And Didn't Look Back)

When I started this journey, the media server landscape was dominated by Plex and Emby. However, my choice to go with Jellyfin was deliberate and philosophical.

  1. Zero Cost, Zero Paywalls: Unlike Plex, which locks hardware transcoding behind a "Plex Pass" paywall, Jellyfin offers this critical feature for free. I didn't want to pay a monthly subscription to watch my own content.
  2. Privacy First: Jellyfin is fully self-hosted with no "phone home" telemetry. My watch history stays on my server, not in a company's cloud database.
  3. Open Source Freedom: It’s a true community project. There are no premium tiers or features held back for "Pro" users—I get the full experience right out of the box.

In my quest for the perfect homelab, I realized that running everything on one "do-it-all" Platform wasn't the most efficient path. Instead, I've decoupled my services for maximum performance: TrueNAS SCALE handles the storage, while Proxmox LXC (Linux Containers) handles the heavy lifting of media streaming.

Here is exactly how I installed Jellyfin in a lightweight Proxmox container, enabled Intel QuickSync on my i5 CPU for buttery-smooth transcoding, and connected it all to my massive TrueNAS library.

1. The Architecture: Separation of Concerns

  • Storage (TrueNAS): My HP EliteDesk runs TrueNAS SCALE as a VM, managing 2x 4TB HDDs in a ZFS mirror. This is "The Vault" where the media lives.
  • Compute (Proxmox LXC): Jellyfin runs in a lightweight LXC container on Proxmox. This is "The Engine." It boots in seconds and uses barely any RAM when idle.​
  • The Link: I use an NFS share to mount the TrueNAS storage directly into the Jellyfin container.

2. Installing Jellyfin in a Proxmox LXC

Instead of a heavy VM, I used a helper script to spin up a lean Ubuntu-based LXC container.

  1. Create the LXC: I used the popular Proxmox helper scripts (by tteck) to auto-install Jellyfin.
    • Command in Proxmox Shell: bash -c "$(wget -qLO - https://github.com/tteck/Proxmox/raw/main/ct/jellyfin.sh)"
    • I chose Ubuntu 24.04 as the base because it has the latest drivers for Intel QuickSync.​
  2. Unprivileged Container: I kept the container "Unprivileged" for better security, which requires a specific tweak for the hardware acceleration to work (detailed below).​

3. Connecting the Media: Mounting TrueNAS via NFS

Since my media lives on TrueNAS, I needed to make it visible to the Jellyfin container.

  1. On TrueNAS: I created an NFS Share for my /mnt/tank/media dataset. I configured the Mapall User to root (or a dedicated media user) to ensure permissions wouldn't be a headache.​
  2. On Proxmox Host: I didn't just mount it inside the container; I mounted it on the Proxmox host first to ensure stability.
    • Edit fstab: Added 192.168.x.x:/mnt/tank/media /mnt/pve/media nfs defaults 0 0
  3. Pass-through to LXC: I added a mount point to the LXC configuration file (/etc/pve/lxc/10x.conf):
    mp0: /mnt/pve/media,mp=/media
    Now, inside the Jellyfin container, my entire library appears simply as /media.​

4. Enabling Intel QuickSync (The Critical Step)

My i5-8500 CPU has a fantastic UHD 630 iGPU, but LXC containers don't see it by default. Here is how I unlocked hardware transcoding.​

Step A: Prepare the Proxmox Host
I installed the necessary render drivers on the host:
apt install intel-media-driver-non-free

Step B: Pass the GPU to the Container
I edited the LXC config file again (nano /etc/pve/lxc/10x.conf) and added these magic lines to pass the video device groups:

bashlxc.cgroup2.devices.allow: c 226:0 rwm
lxc.cgroup2.devices.allow: c 226:128 rwm
lxc.mount.entry: /dev/dri/renderD128 dev/dri/renderD128 none bind,optional,create=file

Note: The numbers 226:0 and 226:128 correspond to the render group IDs found by running ls -l /dev/dri on the host.

Step C: Jellyfin Config
Inside Jellyfin (Dashboard > Playback), I selected Intel QuickSync (QSV). Now, when I play a 4K HDR movie, my CPU usage stays low while the iGPU handles the heavy transcoding.​

5. Access Anywhere: Nginx Proxy Manager

To finish the setup, I wanted to access my library from outside my network securely, using my custom domain mydomain.com.​

  1. Reverse Proxy: I have Nginx Proxy Manager running in another Docker container.
  2. Proxy Host: I created a new host:
    • Domain: jelly.mydomain.com
    • Forward IP: The internal IP of my Jellyfin LXC (e.g., 192.168.1.50).
    • Port: 8096
  3. SSL: I enabled "Force SSL" and requested a Let's Encrypt certificate.

Now, whether I'm on my couch or traveling, I have secure, encrypted access to my entire media library. The combination of Proxmox's efficiency and TrueNAS's storage reliability makes this the ultimate "set it and forget it" media center.