How to Install Jellyfin on Proxmox LXC with Intel GPU Hardware Transcoding
As part of my Proxmox homelab setup plan, I am gradually moving different services into lightweight and isolated containers instead of running everything on a single virtual machine. One of the services I wanted to add is Jellyfin, which will be used as the media server for my home network.
In this guide, I will show you how to install Jellyfin directly inside a Proxmox LXC container without Docker. This approach fits well with my homelab design because it keeps Jellyfin lightweight, easy to manage, and isolated from other services running on the Proxmox host. It also avoids the additional layer of Docker while still providing the benefits of LXC containerization.
The goal is to keep the setup simple:
:::codeProxmox └── LXC └── Jellyfin
:::
Media directories will be mounted directly from the Proxmox host into the LXC container, while the Intel integrated GPU will be passed through for hardware transcoding.
This setup is suitable for systems such as a Dell OptiPlex 3070 Micro with an Intel Core i3-9100 and Intel UHD Graphics 630.
1. Check the Intel GPU on Proxmox
Open the Proxmox Shell and check whether the Intel GPU is detected:
:::codelspci | grep -Ei "VGA|Display"
:::
You should see an Intel graphics device.
Next, check the available DRI devices:
:::codels -lah /dev/dri
:::
You should see something similar to:
:::codecard0 renderD128
:::
The most important device for Jellyfin is:
:::code/dev/dri/renderD128
:::
This device will be used for Intel hardware acceleration.
If /dev/dri does not exist, try loading the Intel graphics kernel module:
modprobe i915
:::
Then check again:
:::codels -lah /dev/dri
:::
If /dev/dri/renderD128 still does not appear, check whether the integrated GPU is enabled in the Dell BIOS.
This is how it looks like on my machine
2. Create the Media Directory
For this example, all media will be stored under:
:::code/mnt/media
:::
Create the media directories:
:::codemkdir -p /mnt/media/movies mkdir -p /mnt/media/series mkdir -p /mnt/media/music
:::
The directory structure will look like this:
:::code/mnt/media/ ├── movies/ ├── series/ └── music/
:::
You can replace /mnt/media with the actual path of your HDD, SSD, USB drive, NAS mount, or other storage.
3. Download a Debian LXC Template
In the Proxmox web interface, go to:
Node > local > CT Templates > Templates
Download a Debian template.
Recommended:
:::codeDebian 12
:::
Debian is lightweight, stable, and works well for a dedicated Jellyfin LXC container.
4. Create the Jellyfin LXC Container
Click Create CT.
Example configuration:
:::codeCT ID: 101 Hostname: jellyfin
:::
Recommended resources:
:::codeCPU: 2 Cores RAM: 2048 MB Swap: 512 MB Root Disk: 32 GB
:::
For networking:
:::codeBridge: vmbr0
IPv4: DHCP
:::
or use static IP instead
For the simplest home server setup, disable the Unprivileged Container option:
:::codeUnprivileged Container: OFF
:::
This creates a privileged LXC container.
A privileged LXC is generally easier to manage when you need to pass host directories and GPU devices directly into the container.
For a trusted Jellyfin home server, this keeps the configuration simple.
Finish creating the container.
5. Stop the Jellyfin LXC
Before adding storage and GPU access, stop the container.
Run this command on the Proxmox host:
:::codepct stop 101
:::
Replace 101 if your Jellyfin container uses a different CT ID.
6. Mount the Media Directory into the LXC
Run this command on the Proxmox host:
:::codepct set 101 -mp0 /mnt/media,mp=/media
:::
This creates the following mapping:
:::codeProxmox Host:
/mnt/media
Jellyfin LXC:
/media
:::
Check the LXC configuration:
:::codecat /etc/pve/lxc/101.conf
:::
You should see:
:::codemp0: /mnt/media,mp=/media
:::
The Jellyfin container can now access the media directory on the Proxmox host directly.
7. Optional: Make the Media Directory Read-Only
If Jellyfin only needs to read your media files, you can make the mount read-only:
:::codepct set 101 -mp0 /mnt/media,mp=/media,ro=1
:::
This prevents Jellyfin from modifying or deleting your original media files.
If you want Jellyfin to have full read and write access, use:
:::codepct set 101 -mp0 /mnt/media,mp=/media
:::
For most home servers, read-only access is safer if Jellyfin does not need to delete or modify media files.
8. Pass the Intel GPU to the LXC
In the Proxmox web interface, open:
Jellyfin CT > Resources
Click:
Add > Device Passthrough
Select:
:::code/dev/dri/renderD128
:::
You do not need full PCI GPU passthrough.
For Jellyfin hardware transcoding, passing the Intel render device is normally enough.
9. Start the Jellyfin LXC
Start the container:
:::codepct start 101
:::
Enter the container:
:::codepct enter 101
:::
From this point onward, run the following commands inside the Jellyfin LXC unless stated otherwise.
10. Check the GPU Inside the LXC
Run:
:::codels -lah /dev/dri
:::
You should see:
:::coderenderD128
:::
You may also see:
:::codecard0
:::
Check the permissions of the render device:
:::codels -l /dev/dri/renderD128
:::
You may see something similar to:
:::codecrw-rw---- 1 root render ... /dev/dri/renderD128
:::
On my machine, the render device membership still belong to root, we will change it to render group.
11. Check the Render Group ID
Run this code inside the LXC:
:::codegetent group render
:::
Example output:
:::coderender:x:104:
:::
In this example, the render group GID is 104, your GID may be different.:
:::code104
:::
Now we know the GID is 104, lets change it on the container settings
Stop the container first, run this command from proxmox shell or use the GUI
:::codepct stop 101
:::
Go to jellyfin lxc > Resources. Put 104 in the GID field.
Start the container again and check the render device
12. Update Debian
Update the package repository:
:::codeapt update
:::
Upgrade installed packages:
:::codeapt upgrade -y
:::
Install curl:
:::codeapt install curl -y
:::
13. Install Jellyfin
Download the official Jellyfin installer:
:::codecurl -s https://repo.jellyfin.org/install-debuntu.sh -O
:::
Download the checksum file:
:::codecurl -s https://repo.jellyfin.org/install-debuntu.sh.sha256sum -O
:::
Verify the installer:
:::codesha256sum -c install-debuntu.sh.sha256sum
:::
You should see:
:::codeinstall-debuntu.sh: OK
:::
Install Jellyfin:
:::codebash install-debuntu.sh
:::
Jellyfin will now be installed directly inside the Debian LXC container.
14. Check the Jellyfin Service
Check the Jellyfin service:
:::codesystemctl status jellyfin
:::
You should see:
:::codeactive (running)
:::
Enable Jellyfin to start automatically at boot:
:::codesystemctl enable jellyfin
:::
If necessary, restart the service:
:::codesystemctl restart jellyfin
:::
15. Give Jellyfin Access to the Intel GPU
Add the Jellyfin user to the render group:
:::codeusermod -aG render jellyfin
:::
Also add Jellyfin to the video group:
:::codeusermod -aG video jellyfin
:::
Check the Jellyfin user's group memberships:
:::codegroups jellyfin
:::
You should see something similar to:
:::codejellyfin : jellyfin render video
:::
Restart Jellyfin:
:::codesystemctl restart jellyfin
:::
16. Test Intel GPU Hardware Acceleration
Run:
:::code/usr/lib/jellyfin-ffmpeg/vainfo --display drm --device /dev/dri/renderD128
:::
A successful output should contain information about:
:::codeVA-API
Intel iHD driver
Supported profiles
Supported entrypoints
:::
If you see:
:::codePermission denied
:::
check that the Jellyfin user belongs to the render group:
:::codegroups jellyfin
:::
If the GPU device cannot be initialized, recheck the Proxmox Device Passthrough configuration.
17. Find the Jellyfin IP Address
Run:
:::codeip a
:::
Look for the IP address assigned to the LXC container.
For example:
:::code192.168.1.50
:::
Open Jellyfin in your browser:
:::codehttp://192.168.1.50:8096
:::
Replace the IP address with the actual IP address of your Jellyfin LXC.
Complete the initial Jellyfin setup wizard.
18. Add Your Media Libraries
Because the Proxmox directory:
:::code/mnt/media
:::
is mounted inside the container as:
:::code/media
:::
use the following paths when creating Jellyfin libraries. Add the libraries from Dashboard > Libraries > Add Media Library
Movies
:::code/media/movies
:::
Series
:::code/media/series
:::
Music
:::code/media/music
:::
The complete mapping is:
:::codeProxmox Host Jellyfin LXC
/mnt/media/movies -> /media/movies
/mnt/media/series -> /media/series
/mnt/media/music -> /media/music
:::
This keeps your media files separate from the Jellyfin operating system and application data.
19. Enable Intel Quick Sync in Jellyfin
Open:
Jellyfin Dashboard > Playback > Transcoding
For Hardware Acceleration, select:
:::codeIntel QuickSync (QSV)
:::
Set the hardware device to:
:::code/dev/dri/renderD128
:::
For Intel UHD Graphics 630, Intel Quick Sync is the recommended option to try first.
20. Enable Supported Hardware Decoding
For Intel UHD Graphics 630, you can normally enable hardware decoding for formats such as:
:::codeH.264
HEVC
HEVC 10-bit
MPEG-2
VC-1
VP8
VP9
VP9 10-bit
:::
Intel UHD Graphics 630 does not support AV1 hardware decoding.
Leave AV1 hardware decoding disabled.
21. Test Hardware Transcoding
Play a video in Jellyfin.
To force Jellyfin to transcode, manually reduce the playback quality.
For example:
:::codeOriginal:
4K
Playback:
1080p 10 Mbps
:::
Open:
Jellyfin Dashboard > Active Devices
You should see:
:::codeTranscoding
:::
instead of:
:::codeDirect Play
:::
This confirms that Jellyfin is converting the video for the client.
22. Check the FFmpeg Process
Inside the Jellyfin LXC, run:
:::codeps aux | grep ffmpeg
:::
When hardware acceleration is working, the FFmpeg process should normally contain references to QSV, VA-API, or:
:::code/dev/dri/renderD128
:::
This helps confirm that Jellyfin is using the Intel GPU for transcoding.
23. Use VA-API If Quick Sync Does Not Work
If Intel Quick Sync causes problems, open:
Dashboard > Playback > Transcoding
Change:
:::codeIntel QuickSync (QSV)
:::
to:
:::codeVA-API
:::
Use this device:
:::code/dev/dri/renderD128
:::
Then test transcoding again.
For Intel UHD Graphics 630, try Quick Sync first and use VA-API as the fallback option.
At this point, jellyfin is fully functional and you can start adding media/audio files. The next steps in this articles is optional and may not applicable to all users.
I am thinking to use MergerFS to accomodate multiple disk containing media files. I might do it for next article in the near future.
24. Force Jellyfin to Prioritize Direct Play
Jellyfin already prefers Direct Play whenever the media format is supported by the client. However, you can force a user account to use Direct Play and prevent Jellyfin from falling back to transcoding.
Open:
Dashboard > Users > Select User > Media Playback
Configure the playback permissions as follows:
:::codeAllow media playback: ON
Allow audio/video playback that requires transcoding: OFF
Allow video playback that requires conversion without re-encoding: OFF
:::
With these settings, Jellyfin will effectively operate in a Direct Play or Fail mode for that user.
The playback behavior will become:
:::codeCompatible media
↓
Direct Play
↓
Playback starts normally
Incompatible media
↓
Transcoding required
↓
Playback is rejected
:::
To maximize Direct Play compatibility, also configure the Jellyfin client to use Original or Maximum playback quality.
Avoid setting a low streaming bitrate limit because Jellyfin may otherwise need to transcode the video to reduce its bitrate.
For the best Direct Play experience, also prefer widely supported media formats such as:
:::codeContainer: MKV or MP4
Video: H.264 or HEVC
Audio: AAC, AC3, or other client-supported codecs
Subtitle: SRT or other text-based subtitles
:::
Image-based subtitles such as PGS may require subtitle burn-in on some clients, which normally requires video transcoding.
If you still want transcoding as an emergency fallback, leave Allow audio/video playback that requires transcoding enabled. Jellyfin will continue to prefer Direct Play whenever possible and only use Intel Quick Sync transcoding when necessary.
25. Recommended Final Configuration
A simple Jellyfin configuration for an Intel Core i3-9100 system can look like this:
:::codeProxmox Host
│
├── Intel UHD Graphics 630
│ └── /dev/dri/renderD128
│
├── /mnt/media
│ ├── movies
│ ├── series
│ └── music
│
└── LXC 101
├── Debian
├── Jellyfin
├── 2 CPU Cores
├── 2 GB RAM
├── 16 GB Root Disk
├── /media
└── /dev/dri/renderD128
:::
The software stack remains simple:
:::codeProxmox
↓
LXC
↓
Jellyfin
:::
There is no additional Docker layer.
26. Why Use Jellyfin Directly in Proxmox LXC?
Running Jellyfin directly inside an LXC container makes storage mapping simple:
:::code/mnt/media
↓
LXC Bind Mount
↓
/media
↓
Jellyfin
:::
GPU access is also straightforward:
:::codeIntel UHD Graphics 630
↓
/dev/dri/renderD128
↓
Jellyfin LXC
↓
Intel Quick Sync
:::
Compared with:
:::codeProxmox
↓
LXC
↓
Docker
↓
Jellyfin
:::
the native LXC installation has fewer layers to configure and troubleshoot.
This is especially useful on a small single-node Proxmox home server.
27. Backup Strategy
Keep Jellyfin itself inside the LXC container.
The LXC contains:
:::codeJellyfin LXC
├── Debian
├── Jellyfin
├── Configuration
├── Database
├── Users
├── Watch History
└── Metadata
:::
Keep the actual media files separately on the Proxmox host:
:::code/mnt/media
├── movies
├── series
└── music
:::
This allows the Jellyfin LXC backup to remain relatively small.
Your large movie and series collection can use a separate backup strategy.
Final Architecture
After completing the installation, your Jellyfin home server will look like this:
:::codeDell OptiPlex 3070 Micro
Intel Core i3-9100
Intel UHD Graphics 630
│
└── Proxmox VE
│
├── /mnt/media
│ ├── movies
│ ├── series
│ └── music
│
└── Jellyfin LXC
├── Debian
├── Jellyfin
├── /media
│ └── Bind Mount from /mnt/media
│
└── /dev/dri/renderD128
└── Intel Quick Sync Hardware Transcoding
:::
This setup keeps Jellyfin lightweight, easy to maintain, and easy to troubleshoot.
It also gives Jellyfin direct access to your media directories and Intel GPU without adding unnecessary Docker or nested-container layers.
Quick Notes - Commands & Notes Only
Proxmox Host Commands
# ===== COMMAND: Find Debian template =====
pveam update
pveam available --section system | grep debian
# ===== COMMAND: Download Debian template =====
pveam download local debian-12-standard_12.x-x_amd64.tar.zst
pveam list local
# ===== NOTE =====
# Replace debian-12-standard_12.x-x_amd64.tar.zst
# with the actual filename shown by: pveam list local
# ===== COMMAND: Create privileged Jellyfin LXC =====
pct create 101 local:vztmpl/debian-12-standard_12.x-x_amd64.tar.zst \
--hostname jellyfin \
--cores 2 \
--memory 2048 \
--swap 512 \
--rootfs local-lvm:32 \
--net0 name=eth0,bridge=vmbr0,ip=dhcp \
--unprivileged 0 \
--onboot 1
# ===== NOTE =====
# CT ID: 101 | CPU: 2 | RAM: 2 GB | Swap: 512 MB
# Root Disk: 32 GB | Network: DHCP
# --unprivileged 0 = Privileged LXC
# ===== COMMAND: Check Intel GPU =====
lspci | grep -Ei "VGA|Display"
ls -lah /dev/dri
# ===== NOTE =====
# Expected device: /dev/dri/renderD128
# If /dev/dri is missing, try: modprobe i915
# ===== COMMAND: Create media directories =====
mkdir -p /mnt/media/movies
mkdir -p /mnt/media/series
mkdir -p /mnt/media/music
# ===== COMMAND: Bind media to LXC =====
pct set 101 -mp0 /mnt/media,mp=/media
# ===== NOTE =====
# Proxmox /mnt/media → Jellyfin LXC /media
# ===== COMMAND: Check LXC config =====
cat /etc/pve/lxc/101.conf
# ===== GPU PASSTHROUGH: Proxmox GUI =====
# LXC 101 → Resources → Add → Device Passthrough
# Device: /dev/dri/renderD128
#
# If needed, set GID to match the render group inside LXC.
# Example: render:x:104: → GID = 104
# ===== COMMAND: Start and enter LXC =====
pct start 101
pct enter 101
Jellyfin LXC Commands
# ===== COMMAND: Check Intel GPU =====
ls -lah /dev/dri
ls -l /dev/dri/renderD128
# ===== COMMAND: Check render GID =====
getent group render
# ===== NOTE =====
# Example: render:x:104: → GID = 104
# Target ownership: root render
# If it shows root root, set the correct GID in:
# Proxmox → LXC 101 → Resources → Device Passthrough → Advanced
# ===== COMMAND: Update Debian =====
apt update
apt upgrade -y
apt install curl -y
# ===== COMMAND: Download Jellyfin installer =====
curl -s https://repo.jellyfin.org/install-debuntu.sh -O
curl -s https://repo.jellyfin.org/install-debuntu.sh.sha256sum -O
# ===== COMMAND: Verify installer =====
sha256sum -c install-debuntu.sh.sha256sum
# ===== NOTE =====
# Expected: install-debuntu.sh: OK
# ===== COMMAND: Install Jellyfin =====
bash install-debuntu.sh
# ===== COMMAND: Enable and check Jellyfin =====
systemctl enable jellyfin
systemctl status jellyfin
# ===== COMMAND: Give Jellyfin GPU access =====
usermod -aG render jellyfin
usermod -aG video jellyfin
groups jellyfin
# ===== NOTE =====
# Expected groups should include: render video
# ===== COMMAND: Restart Jellyfin =====
systemctl restart jellyfin
systemctl status jellyfin
# ===== COMMAND: Test Intel GPU acceleration =====
/usr/lib/jellyfin-ffmpeg/vainfo --display drm --device /dev/dri/renderD128
# ===== NOTE =====
# Expected output should include:
# VA-API, Intel iHD driver, supported profiles/entrypoints
# ===== COMMAND: Check Jellyfin IP =====
ip a
# ===== NOTE =====
# Jellyfin Web: http://JELLYFIN-IP:8096
# Example: http://192.168.1.50:8096
# ===== OPTIONAL: Check FFmpeg during transcoding =====
ps aux | grep ffmpeg
Post a Comment for "How to Install Jellyfin on Proxmox LXC with Intel GPU Hardware Transcoding"
Post a Comment