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:

:::code
Proxmox └── 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:

:::code
lspci | grep -Ei "VGA|Display"
:::

You should see an Intel graphics device.

Next, check the available DRI devices:

:::code
ls -lah /dev/dri
:::

You should see something similar to:

:::code
card0 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:

:::code
modprobe i915
:::

Then check again:

:::code
ls -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:

:::code
mkdir -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:

:::code
Debian 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:

:::code
CT ID: 101 Hostname: jellyfin
:::

Recommended resources:

:::code
CPU: 2 Cores RAM: 2048 MB Swap: 512 MB Root Disk: 32 GB
:::






For networking:

:::code
Bridge: vmbr0
IPv4: DHCP
:::
or use static IP instead
 



For the simplest home server setup, disable the Unprivileged Container option:

:::code
Unprivileged 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:

:::code
pct 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:

:::code
pct set 101 -mp0 /mnt/media,mp=/media
:::

This creates the following mapping:

:::code
Proxmox Host:
/mnt/media

Jellyfin LXC:
/media
:::

Check the LXC configuration:

:::code
cat /etc/pve/lxc/101.conf
:::

You should see:

:::code
mp0: /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:

:::code
pct 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:

:::code
pct 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:

:::code
pct start 101
:::

Enter the container:

:::code
pct 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:

:::code
ls -lah /dev/dri
:::

You should see:

:::code
renderD128
:::

You may also see:

:::code
card0
:::

Check the permissions of the render device:

:::code
ls -l /dev/dri/renderD128
:::

You may see something similar to:

:::code
crw-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:

:::code
getent group render
:::

Example output:

:::code
render:x:104:
:::

In this example, the render group GID is 104, your GID may be different.:

:::code
104
:::

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

:::code

pct 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:

:::code
apt update
:::

Upgrade installed packages:

:::code
apt upgrade -y
:::

Install curl:

:::code
apt install curl -y
:::


13. Install Jellyfin

Download the official Jellyfin installer:

:::code
curl -s https://repo.jellyfin.org/install-debuntu.sh -O
:::

Download the checksum file:

:::code
curl -s https://repo.jellyfin.org/install-debuntu.sh.sha256sum -O
:::

Verify the installer:

:::code
sha256sum -c install-debuntu.sh.sha256sum
:::

You should see:

:::code
install-debuntu.sh: OK
:::


 

Install Jellyfin:

:::code
bash install-debuntu.sh
:::

Jellyfin will now be installed directly inside the Debian LXC container.



14. Check the Jellyfin Service

Check the Jellyfin service:

:::code
systemctl status jellyfin
:::

You should see:

:::code
active (running)
:::

Enable Jellyfin to start automatically at boot:

:::code
systemctl enable jellyfin
:::

If necessary, restart the service:

:::code
systemctl restart jellyfin
:::


15. Give Jellyfin Access to the Intel GPU

Add the Jellyfin user to the render group:

:::code
usermod -aG render jellyfin
:::

Also add Jellyfin to the video group:

:::code
usermod -aG video jellyfin
:::

Check the Jellyfin user's group memberships:

:::code
groups jellyfin
:::

You should see something similar to:

:::code
jellyfin : jellyfin render video
:::


 

Restart Jellyfin:

:::code
systemctl 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:

:::code
VA-API
Intel iHD driver
Supported profiles
Supported entrypoints
:::

 

If you see:

:::code
Permission denied
:::

check that the Jellyfin user belongs to the render group:

:::code
groups jellyfin
:::

If the GPU device cannot be initialized, recheck the Proxmox Device Passthrough configuration.


17. Find the Jellyfin IP Address

Run:

:::code
ip a
:::

Look for the IP address assigned to the LXC container.

For example:

:::code
192.168.1.50
:::

Open Jellyfin in your browser:

:::code
http://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:

:::code
Proxmox 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:

:::code
Intel 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:

:::code
H.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:

:::code
Original:
4K

Playback:
1080p 10 Mbps
:::

Open:

Jellyfin Dashboard > Active Devices

You should see:

:::code
Transcoding
:::

instead of:

:::code
Direct Play
:::

This confirms that Jellyfin is converting the video for the client.


22. Check the FFmpeg Process

Inside the Jellyfin LXC, run:

:::code
ps 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:

:::code
Intel QuickSync (QSV)
:::

to:

:::code
VA-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:

:::code
Allow 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:

:::code
Compatible 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:

:::code
Container: 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:

:::code
Proxmox 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:

:::code
Proxmox

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:

:::code
Intel UHD Graphics 630

/dev/dri/renderD128

Jellyfin LXC

Intel Quick Sync
:::

Compared with:

:::code
Proxmox

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:

:::code
Jellyfin 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:

:::code
Dell 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

For those who want the most to the point way
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


:::toc enable

Post a Comment for "How to Install Jellyfin on Proxmox LXC with Intel GPU Hardware Transcoding"