How to: Install Jellyfin on a Synology NAS using Docker (with Intel QSV hardware transcoding)

Updated 22/02/23 to include required /dev/dri permissions for non-root users

There is an overwhelming amount of information regarding this topic, with the vast majority being outdated. As such, I am writing this post to provide an up to date method of installing Jellyfin on a Synology NAS (in my case, a DS920+) with the required configuration to support hardware transcoding. This assumes you have a compatible NAS, since CPUs used in Synology’s latest offerings do not have an iGPU and as a result, do not support hardware transcoding.


  • Basic Docker and Docker Compose knowledge.
  • A compatible Synology NAS.
  • Docker installed (the Package Center version is fine to use).
  • Docker Compose installed (if you’re not using the Package Centre version of Docker).
  • Set /dev/dri/ permissions (if running as non-root) as documented below.

Setting /dev/dri permissions (if running as non-root user)

Unlike other OSs, Synology DSM does not permit non-root users from accessing /dev/dri which will prevent hardware transcoding from working within your Jellyfin instance if you plan on running this as a non-root user:

[AVHWDeviceContext @ 0x561260cc5a80] No VA display found for any default device.
Device creation failed: -22.
Failed to set value 'vaapi=va:,driver=iHD,kernel_driver=i915' for option 'init_hw_device': Invalid argument
Error parsing global options: Invalid argument

To resolve this issue, you simply need to run the command “chmod 777 /dev/dri/*”, however this permission is not persistant so rebooting your device will result in hardware transcoding breaking again. To get around this, create a triggered task within your DSM Control Panel with the following options:

  • Task: Jellyfin driver permissions (this part really doesn’t matter)
  • User: root
  • Event: Boot-up
  • Enabled: Checked
  • User-defined script: chmod 777 /dev/dri/*

Click “OK” to create the task, then manually run the task once.

Creating the container

In order to create the container, we are going to use a Docker Compose YAML file which will define its properties and other configurations. On Synology DSM, you have a few options for using Docker Compose, none of which are available from the Docker app’s UI.

  • Portainer – My preferred method, since it provides you with a GUI and only requires SSH for the initial install (guide here).
  • SSH (here’s a good guide on this method).
  • Task scheduler – I’d avoid this method as it makes management messy.

You can find my Compose YAML for Jellyfin below:

version: "3.8"
    image: jellyfin/jellyfin:latest
    container_name: jellyfin
    user: xxx:xxx #your UID:GID
      - TZ=Europe/London #your time zone
      - JELLYFIN_PublishedServerUrl=x.x.x.x #your NAS IP
      - /volume1/docker/jellyfin:/config
      - /volume1/docker/jellyfin/cache:/cache
      - /volume1/video:/data/media
      - /dev/dri:/dev/dri
      - 8096:8096 #required web port
      - 8920:8920 #optional https port
      - 7359:7359/udp #optional discovery port
    restart: unless-stopped

A few notes about my configuration compared to others I’ve seen:

  • I’m using the official Jellyfin image rather than, since this now supports Intel QSV
  • As I’m not using the image, I do not need to include the Opencl-Intel Docker Mod.
  • I’m mapping /dev/dri (for HW transcoding support).
  • I’m using the same media volume as Video Station.
  • I’ve specified a cache directory to ensure it’s actually where you want it, rather than in the default, hidden location.
  • An additional port (1900/udp) used for DLNA is not included as this conflicts with default Synology ports. You can work around this by using a MacVLAN network, however, as this port is optional, I have skipped it in this guide.

Key changes you must make before deploying your container:

  • Set the UID and GID values. If you’re using what these should be set to, I’d recommend creating a new “docker” standard user and checking its values using SSH command “id username“. There is no requirement to run this container as root (either by removing the PUID/PGID or setting them to 0/0) and doing so decreases security unnecessarily.
  • Set your time zone using the TZ database name
  • Set your NAS IP (PublishedServerUrl)
  • Review the configured volumes and tweak as required
  • Manually create a “jellyfin” folder and “cache” subfolder within your Docker shared folder. This won’t happen automatically and will cause deployment to fail if it’s missing.

Enabling hardware transcoding

Once Jellyfin has been deployed and configured, you must manually enable hardware transcoding. Start by opening the admin dashboard, then select Playback:

Once here, change the Hardware acceleration drop down from None to Intel QuickSync (QSV).

Select your file types (AV1 is not supported so leave it unchecked), as well as the following:

  • Enable Enable hardware transcoding.
  • Ensure both low-power options are disabled (enabling either of these options breaks transcoding).
  • Enable both tone mapping options.

After scrolling to the bottom of the page and clicking Save, you should now have a working Jellyfin container with hardware transcoding support. If you’re facing issues, please leave a comment and I will do my best to help.

Leave a comment