Jump to content

Jellyfin: Difference between revisions

From NixOS Wiki
Makefu (talk | contribs)
add note about intel-media-sdk on unstable
Layer-09 (talk | contribs)
Manual compliance
 
(4 intermediate revisions by 3 users not shown)
Line 1: Line 1:
[https://jellyfin.org/ Jellyfin] is an open source media server (Jellyfin Server) with several clients (Jellyfin Media Player and web client).
<languages/>


== Installation and configuration ==
{{infobox application
  |name=Jellyfin
  |image=Jelly-banner-light.svg
  |type=Media server
  |developer=Jellyfin Project
  |license=[https://www.gnu.org/licenses/gpl-2.0.html GPL-2.0]
  |os=Cross-platform (Linux, macOS, Windows)
  |platform=Server
  |programmingLanguage=C#
  |website=[https://jellyfin.org/ jellyfin.org]
  |github=jellyfin/jellyfin
  |bugTracker=[https://github.com/jellyfin/jellyfin/issues GitHub Issues]
  |documentation=[https://jellyfin.org/docs/ jellyfin.org/docs]
}}
<translate>
<!--T:1-->
<strong>[https://jellyfin.org/ Jellyfin]</strong><ref name="jellyfin">Jellyfin Project, "Jellyfin: The Free Software Media System", Official Website, Accessed October 2025. https://jellyfin.org/</ref> is a free and open-source media server that enables users to manage and stream their personal media libraries across various devices. It consists of the Jellyfin Server and multiple client applications including Jellyfin Media Player and a web interface.


To get up and running with Jellyfin, add the packages <code>pkgs.jellyfin</code> <code>pkgs.jellyfin-web</code> & <code>pkgs.jellyfin-ffmpeg</code> to your `configuration.nix` file as shown below.
== Installation == <!--T:2-->


<syntaxHighlight lang=nix>
<!--T:3-->
{
To enable Jellyfin on NixOS, add the service configuration to your <code>/etc/nixos/configuration.nix</code> file:
</translate>
 
{{code|lang=nix|line=no|1={
   services.jellyfin.enable = true;
   services.jellyfin.enable = true;
   environment.systemPackages = [
   environment.systemPackages = [
Line 14: Line 33:
   ];
   ];
}
}
</syntaxHighlight>
}}
 
<translate>
If you want more advanced configuration, use something like what's shown below and [https://search.nixos.org/options?query=jellyfin see the docs for more configuration options]
<!--T:4-->
For more advanced configuration options, refer to the [https://search.nixos.org/options?query=jellyfin NixOS options documentation]:<ref name="nixos-options">NixOS Wiki contributors, "Jellyfin NixOS module options", NixOS Search, Accessed October 2025. https://search.nixos.org/options?query=jellyfin</ref>
</translate>


<syntaxHighlight lang=nix>
{{code|lang=nix|line=no|1={
{
   services.jellyfin = {
   services.jellyfin = {
     enable = true;
     enable = true;
Line 25: Line 45:
   };
   };
}
}
</syntaxHighlight>
}}
<translate>
<!--T:5-->
After configuring Jellyfin, rebuild your system for the changes to take effect:
</translate>
{{code|lang=bash|line=no|$ sudo nixos-rebuild switch}}
<translate>
<!--T:6-->
After the rebuild completes, verify that Jellyfin is running:
</translate>
{{code|lang=bash|line=no|$ sudo systemctl status jellyfin}}
<translate>
<!--T:7-->
If Jellyfin is not running, you can start it manually:
</translate>
{{code|lang=bash|line=no|$ jellyfin}}
<translate>
<!--T:8-->
Once Jellyfin is running, you can access the web interface:


Once you have included the packages to be installed, and enabled and configured Jellyfin to your liking, then rebuild your system for changes to take effect.
<!--T:9-->
<syntaxHighlight lang=bash>$ sudo nixos-rebuild switch</syntaxHighlight>
* The Jellyfin server runs on port 8096 by default.<ref name="jellyfin-ports">Jellyfin Documentation Team, "Networking", Jellyfin Documentation, Accessed October 2025. https://jellyfin.org/docs/general/networking/</ref>
* Navigate to <code>http://localhost:8096</code> for local access.
* For remote access, replace <code>localhost</code> with the server's IP address.


After the rebuild is complete, Jellyfin should be running. Verify that it is with the following command.
== Configuration == <!--T:10-->
<syntaxHighlight lang=bash>$ sudo systemctl status jellyfin</syntaxHighlight>


If jellyfin is not running you should be able to start it by running <code>jellyfin</code> in your terminal.
=== Allowing access to external drives === <!--T:11-->
<syntaxHighlight lang=bash>$ jellyfin</syntaxHighlight>


After you've verified that Jellyfin is running you can start the configuration process.
<!--T:12-->
* The Jellyfin server should be running on port 8096.
Desktop environments typically mount external drives for the current user, while Jellyfin runs as the system user <code>jellyfin</code> by default. This can cause permission issues when accessing external media.
* Go to http://localhost:8096 if you are setting this up on your primary computer or want to test your build locally.
* If you're logging into a remote server, replace localhost with the ip address of the server.


=== Allow Jellyfin to read external drives ===
<!--T:13-->
The simplest solution is to change the service user:
</translate>


You might encounter permission issues when you try to access external drives if you haven't configured anything else with the server yet. If you haven't explicitly set up a mounting configuration for your drives and instead let your desktop environment (e.g. GNOME or KDE) automatically mount it when you try accessing it via their file explorers, Jellyfin won't be able to access the drive. This is because the desktop environment mounts it to your user, while Jellyfin runs by default as the "jellyfin" user.
{{code|lang=nix|line=no|1={
 
The easiest way to allow it to see these external drives is to change the service's user . Here is an example:
<syntaxhighlight lang="nix">
   services.jellyfin = {
   services.jellyfin = {
     enable = true;
     enable = true;
     openFirewall = true;
     openFirewall = true;
     user="yourusername";
     user = "yourusername";
   };
   };
</syntaxhighlight>
}
}}
<translate>
<!--T:14-->
If you change the user after Jellyfin is already installed, update the ownership of the data and cache directories:
</translate>


If you have changed the user option after you have already installed Jellyfin, you have to change the ownership of the folder `/var/lib/jellyfin` to the user you set it to by doing this:
{{code|lang=bash|line=no|$ sudo chown -R yourusername:yourusername /var/lib/jellyfin
$ sudo chown -R yourusername:yourusername /var/cache/jellyfin}}
<translate>
<!--T:15-->
Then restart the service:
</translate>


<syntaxhighlight lang="bash">
{{code|lang=bash|line=no|$ sudo systemctl restart jellyfin}}
  sudo chown -R yourusername:yourusername /var/lib/jellyfin
<translate>
</syntaxhighlight>
<!--T:16-->
Alternatively, configure explicit mounts via [[Filesystems]]. This approach requires more setup and each drive must be declared, but provides finer control over what Jellyfin can access.


Additionally, you should also change the ownership of the cache directory to avoid transcoding issues:
=== Hardware transcoding === <!--T:17-->


<syntaxhighlight lang="bash">
<!--T:18-->
  sudo chown -R yourusername:yourusername /var/cache/jellyfin
Modern hardware often includes video acceleration capabilities that can significantly reduce CPU usage during transcoding. For detailed information, see the [https://jellyfin.org/docs/general/post-install/transcoding/hardware-acceleration/ official Jellyfin documentation].<ref name="jellyfin-hw">Jellyfin Documentation Team, "Hardware acceleration", Jellyfin Documentation, Accessed October 2025. https://jellyfin.org/docs/general/post-install/transcoding/hardware-acceleration/</ref>
</syntaxhighlight>


Finally, restart Jellyfin for the changes to take effect:
==== VAAPI and Intel QSV ==== <!--T:19-->


<syntaxhighlight lang="bash">
<!--T:20-->
  systemctl restart jellyfin
Intel GPUs support Video Acceleration API (VAAPI) and Quick Sync Video (QSV). The required packages must be added to <code>hardware.graphics.extraPackages</code>.
</syntaxhighlight>


The alternative is to explicitly mount the drives via [[Filesystems]]. This takes more effort to set up and requires every new drive to be explicitly declared, but allows more control in what Jellyfin is allowed to see.
<!--T:21-->
Choose the appropriate driver based on your CPU generation:
* <code>intel-vaapi-driver</code> for pre-Broadwell CPUs
* <code>intel-media-driver</code> for Broadwell and newer
* <code>intel-compute-runtime</code> for newer processors
</translate>
{{Note|<code>intel-media-sdk</code> is deprecated and does not build on recent channels. Use VAAPI with <code>intel-media-driver</code> instead. See [https://discourse.nixos.org/t/intel-media-sdk-has-become-deprecated/66998 this discussion] for details.<ref name="intel-media-sdk">smana, "intel-media-sdk has become deprecated", NixOS Discourse, Accessed October 2025. https://discourse.nixos.org/t/intel-media-sdk-has-become-deprecated/66998</ref>}}


=== Intro Skipper plugin ===
{{code|lang=nix|line=no|1=
If you install the Intro Skipper plugin, it will not be able to display the skip button in the web interface. This is due to the plugin being unable to modify contents of files in the nix store. To get around this you can make the changes yourself with this:  
{ pkgs, lib, config, ... }:
<syntaxhighlight lang="nix">
{
   nixpkgs.overlays = with pkgs; [
  # Only set this if using intel-vaapi-driver:
    (
   nixpkgs.config.packageOverrides = pkgs: {
      final: prev:
    intel-vaapi-driver = pkgs.intel-vaapi-driver.override { enableHybridCodec = true; };
        {
  };
          jellyfin-web = prev.jellyfin-web.overrideAttrs (finalAttrs: previousAttrs: {
            installPhase = ''
              runHook preInstall


              # this is the important line
  systemd.services.jellyfin.environment.LIBVA_DRIVER_NAME = "iHD"; # or i965 for older GPUs
              sed -i "s#</head>#<script src=\"configurationpage?name=skip-intro-button.js\"></script></head>#" dist/index.html
  environment.sessionVariables = { LIBVA_DRIVER_NAME = "iHD"; };


              mkdir -p $out/share
  hardware.graphics = {
              cp -a dist $out/share/jellyfin-web
    enable = true;


              runHook postInstall
     extraPackages = with pkgs; [
            '';
      intel-ocl # Generic OpenCL support
          });
        }
     )
  ];
 
</syntaxhighlight>
 
== Hardware transcoding ==
In most cases you want to make most of your hardware. Modern boards often come with a hardware accelerator, all you need to do is enable it!


Source: https://jellyfin.org/docs/general/post-install/transcoding/hardware-acceleration/
      # For Broadwell and newer (ca. 2014+), use with LIBVA_DRIVER_NAME=iHD:
      intel-media-driver


=== VAAPI and Intel QSV ===
      # For older processors, use with LIBVA_DRIVER_NAME=i965:
      intel-vaapi-driver
      libva-vdpau-driver


VAAPI and QSV is often available on platforms with Intel GPUs but need their corresponding packages in <code>hardware.graphics.extraPackages</code>.
      # For 13th gen and newer:
      intel-compute-runtime


You have to choose between <code>intel-vaapi-driver</code> (old driver for pre-Broadwell CPUs), <code>intel-compute-runtime</code> and <code>intel-media-driver</code> depending of your CPU.
       # For older processors:
{{Note|<code>intel-media-sdk</code> is deprecated and currently (as of 2025-09-05) does not build on unstable channel. Instead of QSV use VAAPI for hardware acceleration in the jellyfin settings.
       intel-compute-runtime-legacy1
<br/>
source: https://discourse.nixos.org/t/intel-media-sdk-has-become-deprecated/66998}}<syntaxhighlight lang="nix">
{ pkgs, lib,config, ... }:
{
  # 1. enable vaapi on OS-level
  nixpkgs.config.packageOverrides = pkgs: {
    # Only set this if using intel-vaapi-driver
    intel-vaapi-driver = pkgs.intel-vaapi-driver.override { enableHybridCodec = true; };
  };
  systemd.services.jellyfin.environment.LIBVA_DRIVER_NAME = "iHD"; # Or "i965" if using older driver
  environment.sessionVariables = { LIBVA_DRIVER_NAME = "iHD"; };      # Same here
  hardware.graphics = {
    enable = true;
    extraPackages = with pkgs; [
       intel-media-driver # For Broadwell (2014) or newer processors. LIBVA_DRIVER_NAME=iHD
       intel-vaapi-driver # For older processors. LIBVA_DRIVER_NAME=i965
      libva-vdpau-driver # Previously vaapiVdpau


       # choose one of these two matching your CPU:
       # For 11th gen and newer:
      intel-compute-runtime # OpenCL filter support (hardware tonemapping and subtitle burn-in)
       vpl-gpu-rt
      # OpenCL support for intel CPUs before 12th gen
      # see: https://github.com/NixOS/nixpkgs/issues/356535
       intel-compute-runtime-legacy1


      vpl-gpu-rt # QSV on 11th gen or newer
       # Deprecated (may not build on recent channels):
       # deprecated since NixOS unstable (25.11) and may not build at all
       # intel-media-sdk
       intel-media-sdk # QSV up to 11th gen
      intel-ocl # OpenCL support
     ];
     ];
   };
   };


  # 2. do not forget to enable jellyfin
   services.jellyfin.enable = true;
   services.jellyfin.enable = true;
}
}
</syntaxhighlight>
}}
<translate>
==== Troubleshooting VAAPI and Intel QSV ==== <!--T:22-->
 
<!--T:23-->
Check supported VAAPI profiles:
</translate>


==== Troubleshooting VAAPI and Intel QSV ====
{{code|lang=bash|line=no|$ nix-shell -p libva-utils --run vainfo}}
You can check supported vaapi profile supported by your CPU / driver with : <code>nix-shell -p libva-utils --run vainfo</code>.
<translate>
<!--T:24-->
Verify OpenCL availability:
</translate>


You can check the OpenCL properties and devices available on the system with : <code>nix-shell -p clinfo --run clinfo</code>. If clinfo shows <code>Number of platforms 0</code> on the first line, OpenCL is not enabled or available.
{{code|lang=bash|line=no|$ nix-shell -p clinfo --run clinfo}}
<translate>
<!--T:25-->
If <code>clinfo</code> shows <code>Number of platforms 0</code>, OpenCL is not enabled or available.


The command <code>intel_gpu_top</code>, provided by the <code>intel-gpu-tools</code> package is also useful to check the status of your intel GPU: <code>nix-shell -p intel-gpu-tools --run intel_gpu_top</code>.
<!--T:26-->
Monitor Intel GPU status:
</translate>


At least on Intel N100 CPU, you will need the option <code>hardware.enableAllFirmware = true;</code> otherwise GuC formware will not load properly. Here is the type of error you will get without it : <syntaxhighlight lang="dmesg">
{{code|lang=bash|line=no|$ nix-shell -p intel-gpu-tools --run intel_gpu_top}}
[    4.174843] i915 0000:00:10.0: [drm] *ERROR* GT0: GuC firmware i915/tgl_guc_70.bin: fetch failed -ENOENT
<translate>
<!--T:27-->
On Intel N100 CPUs, enable firmware loading to prevent GuC errors:
</translate>
 
{{code|lang=nix|line=no|1={
  hardware.enableAllFirmware = true;
}
}}
<translate>
<!--T:28-->
Without this option, you may see errors like:
</translate>
 
{{code|lang=text|line=no|[    4.174843] i915 0000:00:10.0: [drm] *ERROR* GT0: GuC firmware i915/tgl_guc_70.bin: fetch failed -ENOENT
[    4.175621] i915 0000:00:10.0: [drm] GT0: GuC firmware(s) can be downloaded from https://git.kernel.org/pub/scm/linux/kernel/git/firmware/linux-firmware.git/tree/i915
[    4.175621] i915 0000:00:10.0: [drm] GT0: GuC firmware(s) can be downloaded from https://git.kernel.org/pub/scm/linux/kernel/git/firmware/linux-firmware.git/tree/i915
[    4.176286] i915 0000:00:10.0: [drm] GT0: GuC firmware i915/tgl_guc_70.bin version 0.0.0
[    4.176350] i915 0000:00:10.0: [drm] *ERROR* GT0: GuC initialization failed -ENOENT
[    4.176350] i915 0000:00:10.0: [drm] *ERROR* GT0: GuC initialization failed -ENOENT
[    4.176977] i915 0000:00:10.0: [drm] *ERROR* GT0: Enabling uc failed (-5)
[    4.176977] i915 0000:00:10.0: [drm] *ERROR* GT0: Enabling uc failed (-5)
[    4.177502] i915 0000:00:10.0: [drm] *ERROR* GT0: Failed to initialize GPU, declaring it wedged!
[    4.177502] i915 0000:00:10.0: [drm] *ERROR* GT0: Failed to initialize GPU, declaring it wedged!}}
</syntaxhighlight>
<translate>
==== VAAPI and Intel QSV on Arc GPU ==== <!--T:29-->


==== VAAPI and Intel QSV on Arc GPU ====
<!--T:30-->
Arc GPUs require Jellyfin to use FFmpeg compiled with <code>vpl</code> support. Use [[Overlays|an overlay]] to override the FFmpeg configuration:
</translate>


 
{{code|lang=nix|line=no|1=
If you want to use an Arc GPU for transcoding, you may need to override the ffmpeg version used by jellyfin to ensure that it is compiled with <code>vpl</code> and, potentially, <code>unfree</code>. An example to achieve this through [[Overlays|an overlay]]:<syntaxhighlight lang="nix">
{ pkgs, ... }:
{ pkgs, ... }:
let
let
   jellyfin-ffmpeg-overlay = (
   jellyfin-ffmpeg-overlay = (final: prev: {
    _ prev: {
    jellyfin-ffmpeg = prev.jellyfin-ffmpeg.override {
      jellyfin-ffmpeg = prev.jellyfin-ffmpeg.override {
      # Exact version depends on jellyfin-ffmpeg package
        # Exact version of ffmpeg_* depends on what jellyfin-ffmpeg package is using.
      # In 24.11 it's ffmpeg_7-full
        # In 24.11 it's ffmpeg_7-full.
      ffmpeg_7-full = prev.ffmpeg_7-full.override {
        # See jellyfin-ffmpeg package source for details
        withMfx = false; # Older media driver
        ffmpeg_7-full = prev.ffmpeg_7-full.override {
        withVpl = true; # New driver for Arc GPUs
          withMfx = false; # This corresponds to the older media driver
        withUnfree = true;
          withVpl = true; # This is the new driver
          withUnfree = true;
        };
       };
       };
     }
     };
   );
   });
in
in
{
{
   nixpkgs.overlays = [ jellyfin-ffmpeg-overlay ];
   nixpkgs.overlays = [ jellyfin-ffmpeg-overlay ];
}
}
</syntaxhighlight>This will trigger a rebuild of Jellyfin package, but the end result is that if you select "Intel QuickSync (QSV)" you should see little to no CPU load when transcoding.
}}
<translate>
<!--T:31-->
This triggers a rebuild of the Jellyfin package. After applying, select "Intel QuickSync (QSV)" in the Jellyfin settings for hardware-accelerated transcoding with minimal CPU load.
 
<!--T:32-->
If your system has both integrated and discrete GPUs, manually select the QSV device in the Playback settings to avoid random device selection. Use <code>intel_gpu_top -L</code> to list available devices.
 
==== VAAPI with Jellyfin in a NixOS container ==== <!--T:33-->
 
<!--T:34-->
Containers do not inherit graphics drivers from the host system. When running Jellyfin in a NixOS container, replicate the <code>hardware.graphics</code> configuration and pass through the GPU devices (typically <code>/dev/dri/card0</code> and <code>/dev/dri/renderD128</code>):
</translate>
 
{{code|lang=nix|line=no|1=
{
  allowedDevices = [
    { node = "/dev/dri/card0"; modifier = "rw"; }
    { node = "/dev/dri/renderD128"; modifier = "rw"; }
  ];
 
  bindMounts = {
    "/dev/dri/card0" = {
      hostPath = "/dev/dri/card0";
      isReadOnly = false;
    };
    "/dev/dri/renderD128" = {
      hostPath = "/dev/dri/renderD128";
      isReadOnly = false;
    };
  };
 
  config = {
    # Include hardware.graphics and services.jellyfin configuration
  };
}
}}
<translate>
<!--T:35-->
Verify the configuration by adding <code>libva-utils</code> to the container's <code>environment.systemPackages</code>, logging in with <code>machinectl shell container-name</code>, and running <code>vainfo</code>. Successful output looks like:
</translate>
 
{{code|lang=text|line=no|Trying display: drm
libva info: VA-API version 1.22.0
libva info: Trying to open /run/opengl-driver/lib/dri/iHD_drv_video.so
libva info: Found init function __vaDriverInit_1_22
libva info: va_openDriver() returns 0
vainfo: VA-API version: 1.22 (libva 2.22.0)
vainfo: Driver version: Intel iHD driver for Intel(R) Gen Graphics - 25.2.6 ()
vainfo: Supported profile and entrypoints
      VAProfileNone                  : VAEntrypointVideoProc
      VAProfileNone                  : VAEntrypointStats
      /* Additional profiles depend on your hardware */}}
<translate>
<!--T:36-->
With correct configuration, FFmpeg and Jellyfin can use hardware transcoding.
 
== Tips and tricks == <!--T:37-->
 
=== Intro Skipper plugin === <!--T:38-->
 
<!--T:39-->
The latest version of the Intro Skipper plugin from [https://github.com/intro-skipper/intro-skipper GitHub]<ref name="intro-skipper">Intro Skipper contributors, "Intro Skipper Jellyfin plugin", GitHub, Accessed October 2025. https://github.com/intro-skipper/intro-skipper</ref> works without manual patches on Jellyfin web, Jellyfin Media Player, and Android TV clients.
 
<!--T:40-->
If you need to manually patch the web interface for older versions, use an overlay:
</translate>
 
{{code|lang=nix|line=no|1=
nixpkgs.overlays = [
  (final: prev: {
    jellyfin-web = prev.jellyfin-web.overrideAttrs (finalAttrs: previousAttrs: {
      installPhase = ''
        runHook preInstall
        sed -i "s#</head>#<script src=\"configurationpage?name=skip-intro-button.js\"></script></head>#" dist/index.html
        mkdir -p $out/share
        cp -a dist $out/share/jellyfin-web
        runHook postInstall
      '';
    });
  })
];
}
}}
<translate>
== Troubleshooting == <!--T:41-->
 
=== Service not starting === <!--T:42-->
 
<!--T:43-->
If Jellyfin fails to start, check the service status:
 
{{code|lang=bash|line=no|$ sudo systemctl status jellyfin}}
 
<!--T:44-->
Review the service logs for error messages:
</translate>
 
{{code|lang=bash|line=no|$ sudo journalctl -u jellyfin -n 50}}
<translate>
=== Cannot access media files === <!--T:45-->
 
<!--T:46-->
Verify that the Jellyfin user has read permissions for your media directories. Check file ownership and permissions:
</translate>
 
{{code|lang=bash|line=no|$ ls -la /path/to/media}}
<translate>
<!--T:47-->
If using a custom user for the Jellyfin service, ensure the data directories have correct ownership as described in the configuration section.
 
== See also == <!--T:48-->
 
<!--T:49-->
* [[Filesystems]] – Declarative filesystem mounting on NixOS
* [[Accelerated Video Playback]] – GPU acceleration configuration
* [[Intel Graphics]] – Intel GPU driver setup
* [[Overlays]] – Customizing packages with overlays
* [https://search.nixos.org/options?query=jellyfin NixOS options search] – Jellyfin module options
* [https://jellyfin.org/docs/ Jellyfin documentation] – Official Jellyfin documentation


Note that if your system has an integrated GPU (one built into the CPU) and a discrete GPU, you may need to select the QSV device in the "Playback" settings. Otherwise the device may be picked at random and produce random results. You can use <code>intel_gpu_top -L</code> to identify the devices.
== References == <!--T:50-->
</translate>


Related:  [[Accelerated Video Playback]] and [[Intel Graphics]]
<references/>


[[Category:Server]]
[[Category:Server]]
[[Category:Applications]]
[[Category:Applications]]
[[Category:Web Applications]]
[[Category:Web Applications]]

Latest revision as of 14:06, 24 October 2025


Jellyfin

Media server Application

100%
Developer(s)Jellyfin Project
Operating SystemCross-platform (Linux, macOS, Windows)
Platform(s)Server
Language(s)C#
LicenseGPL-2.0
External links
Websitejellyfin.org
GitHubjellyfin/jellyfin
Bug trackerGitHub Issues
Documentationjellyfin.org/docs

Jellyfin[1] is a free and open-source media server that enables users to manage and stream their personal media libraries across various devices. It consists of the Jellyfin Server and multiple client applications including Jellyfin Media Player and a web interface.

Installation

To enable Jellyfin on NixOS, add the service configuration to your /etc/nixos/configuration.nix file:

{
  services.jellyfin.enable = true;
  environment.systemPackages = [
    pkgs.jellyfin
    pkgs.jellyfin-web
    pkgs.jellyfin-ffmpeg
  ];
}

For more advanced configuration options, refer to the NixOS options documentation:[2]

{
  services.jellyfin = {
    enable = true;
    openFirewall = true;
  };
}

After configuring Jellyfin, rebuild your system for the changes to take effect:

$ sudo nixos-rebuild switch

After the rebuild completes, verify that Jellyfin is running:

$ sudo systemctl status jellyfin

If Jellyfin is not running, you can start it manually:

$ jellyfin

Once Jellyfin is running, you can access the web interface:

  • The Jellyfin server runs on port 8096 by default.[3]
  • Navigate to http://localhost:8096 for local access.
  • For remote access, replace localhost with the server's IP address.

Configuration

Allowing access to external drives

Desktop environments typically mount external drives for the current user, while Jellyfin runs as the system user jellyfin by default. This can cause permission issues when accessing external media.

The simplest solution is to change the service user:

{
  services.jellyfin = {
    enable = true;
    openFirewall = true;
    user = "yourusername";
  };
}

If you change the user after Jellyfin is already installed, update the ownership of the data and cache directories:

$ sudo chown -R yourusername:yourusername /var/lib/jellyfin
$ sudo chown -R yourusername:yourusername /var/cache/jellyfin

Then restart the service:

$ sudo systemctl restart jellyfin

Alternatively, configure explicit mounts via Filesystems. This approach requires more setup and each drive must be declared, but provides finer control over what Jellyfin can access.

Hardware transcoding

Modern hardware often includes video acceleration capabilities that can significantly reduce CPU usage during transcoding. For detailed information, see the official Jellyfin documentation.[4]

VAAPI and Intel QSV

Intel GPUs support Video Acceleration API (VAAPI) and Quick Sync Video (QSV). The required packages must be added to hardware.graphics.extraPackages.

Choose the appropriate driver based on your CPU generation:

  • intel-vaapi-driver for pre-Broadwell CPUs
  • intel-media-driver for Broadwell and newer
  • intel-compute-runtime for newer processors
Note: intel-media-sdk is deprecated and does not build on recent channels. Use VAAPI with intel-media-driver instead. See this discussion for details.[5]
{ pkgs, lib, config, ... }:
{
  # Only set this if using intel-vaapi-driver:
  nixpkgs.config.packageOverrides = pkgs: {
    intel-vaapi-driver = pkgs.intel-vaapi-driver.override { enableHybridCodec = true; };
  };

  systemd.services.jellyfin.environment.LIBVA_DRIVER_NAME = "iHD"; # or i965 for older GPUs
  environment.sessionVariables = { LIBVA_DRIVER_NAME = "iHD"; };

  hardware.graphics = {
    enable = true;

    extraPackages = with pkgs; [
      intel-ocl # Generic OpenCL support

      # For Broadwell and newer (ca. 2014+), use with LIBVA_DRIVER_NAME=iHD:
      intel-media-driver

      # For older processors, use with LIBVA_DRIVER_NAME=i965:
      intel-vaapi-driver
      libva-vdpau-driver

      # For 13th gen and newer:
      intel-compute-runtime

      # For older processors:
      intel-compute-runtime-legacy1

      # For 11th gen and newer:
      vpl-gpu-rt

      # Deprecated (may not build on recent channels):
      # intel-media-sdk
    ];
  };

  services.jellyfin.enable = true;
}

Troubleshooting VAAPI and Intel QSV

Check supported VAAPI profiles:

$ nix-shell -p libva-utils --run vainfo

Verify OpenCL availability:

$ nix-shell -p clinfo --run clinfo

If clinfo shows Number of platforms 0, OpenCL is not enabled or available.

Monitor Intel GPU status:

$ nix-shell -p intel-gpu-tools --run intel_gpu_top

On Intel N100 CPUs, enable firmware loading to prevent GuC errors:

{
  hardware.enableAllFirmware = true;
}

Without this option, you may see errors like:

[    4.174843] i915 0000:00:10.0: [drm] *ERROR* GT0: GuC firmware i915/tgl_guc_70.bin: fetch failed -ENOENT
[    4.175621] i915 0000:00:10.0: [drm] GT0: GuC firmware(s) can be downloaded from https://git.kernel.org/pub/scm/linux/kernel/git/firmware/linux-firmware.git/tree/i915
[    4.176350] i915 0000:00:10.0: [drm] *ERROR* GT0: GuC initialization failed -ENOENT
[    4.176977] i915 0000:00:10.0: [drm] *ERROR* GT0: Enabling uc failed (-5)
[    4.177502] i915 0000:00:10.0: [drm] *ERROR* GT0: Failed to initialize GPU, declaring it wedged!

VAAPI and Intel QSV on Arc GPU

Arc GPUs require Jellyfin to use FFmpeg compiled with vpl support. Use an overlay to override the FFmpeg configuration:

{ pkgs, ... }:
let
  jellyfin-ffmpeg-overlay = (final: prev: {
    jellyfin-ffmpeg = prev.jellyfin-ffmpeg.override {
      # Exact version depends on jellyfin-ffmpeg package
      # In 24.11 it's ffmpeg_7-full
      ffmpeg_7-full = prev.ffmpeg_7-full.override {
        withMfx = false; # Older media driver
        withVpl = true;  # New driver for Arc GPUs
        withUnfree = true;
      };
    };
  });
in
{
  nixpkgs.overlays = [ jellyfin-ffmpeg-overlay ];
}

This triggers a rebuild of the Jellyfin package. After applying, select "Intel QuickSync (QSV)" in the Jellyfin settings for hardware-accelerated transcoding with minimal CPU load.

If your system has both integrated and discrete GPUs, manually select the QSV device in the Playback settings to avoid random device selection. Use intel_gpu_top -L to list available devices.

VAAPI with Jellyfin in a NixOS container

Containers do not inherit graphics drivers from the host system. When running Jellyfin in a NixOS container, replicate the hardware.graphics configuration and pass through the GPU devices (typically /dev/dri/card0 and /dev/dri/renderD128):

{
  allowedDevices = [
    { node = "/dev/dri/card0"; modifier = "rw"; }
    { node = "/dev/dri/renderD128"; modifier = "rw"; }
  ];

  bindMounts = {
    "/dev/dri/card0" = {
      hostPath = "/dev/dri/card0";
      isReadOnly = false;
    };
    "/dev/dri/renderD128" = {
      hostPath = "/dev/dri/renderD128";
      isReadOnly = false;
    };
  };

  config = {
    # Include hardware.graphics and services.jellyfin configuration
  };
}

Verify the configuration by adding libva-utils to the container's environment.systemPackages, logging in with machinectl shell container-name, and running vainfo. Successful output looks like:

Trying display: drm
libva info: VA-API version 1.22.0
libva info: Trying to open /run/opengl-driver/lib/dri/iHD_drv_video.so
libva info: Found init function __vaDriverInit_1_22
libva info: va_openDriver() returns 0
vainfo: VA-API version: 1.22 (libva 2.22.0)
vainfo: Driver version: Intel iHD driver for Intel(R) Gen Graphics - 25.2.6 ()
vainfo: Supported profile and entrypoints
      VAProfileNone                   : VAEntrypointVideoProc
      VAProfileNone                   : VAEntrypointStats
      /* Additional profiles depend on your hardware */

With correct configuration, FFmpeg and Jellyfin can use hardware transcoding.

Tips and tricks

Intro Skipper plugin

The latest version of the Intro Skipper plugin from GitHub[6] works without manual patches on Jellyfin web, Jellyfin Media Player, and Android TV clients.

If you need to manually patch the web interface for older versions, use an overlay:

nixpkgs.overlays = [
  (final: prev: {
    jellyfin-web = prev.jellyfin-web.overrideAttrs (finalAttrs: previousAttrs: {
      installPhase = ''
        runHook preInstall
        sed -i "s#</head>#<script src=\"configurationpage?name=skip-intro-button.js\"></script></head>#" dist/index.html
        mkdir -p $out/share
        cp -a dist $out/share/jellyfin-web
        runHook postInstall
      '';
    });
  })
];
}

Troubleshooting

Service not starting

If Jellyfin fails to start, check the service status:

$ sudo systemctl status jellyfin

Review the service logs for error messages:

$ sudo journalctl -u jellyfin -n 50

Cannot access media files

Verify that the Jellyfin user has read permissions for your media directories. Check file ownership and permissions:

$ ls -la /path/to/media

If using a custom user for the Jellyfin service, ensure the data directories have correct ownership as described in the configuration section.

See also

References

  1. Jellyfin Project, "Jellyfin: The Free Software Media System", Official Website, Accessed October 2025. https://jellyfin.org/
  2. NixOS Wiki contributors, "Jellyfin NixOS module options", NixOS Search, Accessed October 2025. https://search.nixos.org/options?query=jellyfin
  3. Jellyfin Documentation Team, "Networking", Jellyfin Documentation, Accessed October 2025. https://jellyfin.org/docs/general/networking/
  4. Jellyfin Documentation Team, "Hardware acceleration", Jellyfin Documentation, Accessed October 2025. https://jellyfin.org/docs/general/post-install/transcoding/hardware-acceleration/
  5. smana, "intel-media-sdk has become deprecated", NixOS Discourse, Accessed October 2025. https://discourse.nixos.org/t/intel-media-sdk-has-become-deprecated/66998
  6. Intro Skipper contributors, "Intro Skipper Jellyfin plugin", GitHub, Accessed October 2025. https://github.com/intro-skipper/intro-skipper