at 23.11-beta 3.9 kB view raw
1{ config, pkgs, lib, ... }: 2 3with lib; 4 5let 6 cfg = config.services.jellyfin; 7in 8{ 9 options = { 10 services.jellyfin = { 11 enable = mkEnableOption (lib.mdDoc "Jellyfin Media Server"); 12 13 user = mkOption { 14 type = types.str; 15 default = "jellyfin"; 16 description = lib.mdDoc "User account under which Jellyfin runs."; 17 }; 18 19 package = mkOption { 20 type = types.package; 21 default = pkgs.jellyfin; 22 defaultText = literalExpression "pkgs.jellyfin"; 23 description = lib.mdDoc '' 24 Jellyfin package to use. 25 ''; 26 }; 27 28 group = mkOption { 29 type = types.str; 30 default = "jellyfin"; 31 description = lib.mdDoc "Group under which jellyfin runs."; 32 }; 33 34 openFirewall = mkOption { 35 type = types.bool; 36 default = false; 37 description = lib.mdDoc '' 38 Open the default ports in the firewall for the media server. The 39 HTTP/HTTPS ports can be changed in the Web UI, so this option should 40 only be used if they are unchanged. 41 ''; 42 }; 43 }; 44 }; 45 46 config = mkIf cfg.enable { 47 systemd.services.jellyfin = { 48 description = "Jellyfin Media Server"; 49 after = [ "network-online.target" ]; 50 wants = [ "network-online.target" ]; 51 wantedBy = [ "multi-user.target" ]; 52 53 # This is mostly follows: https://github.com/jellyfin/jellyfin/blob/master/fedora/jellyfin.service 54 # Upstream also disable some hardenings when running in LXC, we do the same with the isContainer option 55 serviceConfig = rec { 56 Type = "simple"; 57 User = cfg.user; 58 Group = cfg.group; 59 StateDirectory = "jellyfin"; 60 StateDirectoryMode = "0700"; 61 CacheDirectory = "jellyfin"; 62 CacheDirectoryMode = "0700"; 63 UMask = "0077"; 64 WorkingDirectory = "/var/lib/jellyfin"; 65 ExecStart = "${cfg.package}/bin/jellyfin --datadir '/var/lib/${StateDirectory}' --cachedir '/var/cache/${CacheDirectory}'"; 66 Restart = "on-failure"; 67 TimeoutSec = 15; 68 SuccessExitStatus = ["0" "143"]; 69 70 # Security options: 71 NoNewPrivileges = true; 72 SystemCallArchitectures = "native"; 73 # AF_NETLINK needed because Jellyfin monitors the network connection 74 RestrictAddressFamilies = [ "AF_UNIX" "AF_INET" "AF_INET6" "AF_NETLINK" ]; 75 RestrictNamespaces = !config.boot.isContainer; 76 RestrictRealtime = true; 77 RestrictSUIDSGID = true; 78 ProtectControlGroups = !config.boot.isContainer; 79 ProtectHostname = true; 80 ProtectKernelLogs = !config.boot.isContainer; 81 ProtectKernelModules = !config.boot.isContainer; 82 ProtectKernelTunables = !config.boot.isContainer; 83 LockPersonality = true; 84 PrivateTmp = !config.boot.isContainer; 85 # needed for hardware acceleration 86 PrivateDevices = false; 87 PrivateUsers = true; 88 RemoveIPC = true; 89 90 SystemCallFilter = [ 91 "~@clock" 92 "~@aio" 93 "~@chown" 94 "~@cpu-emulation" 95 "~@debug" 96 "~@keyring" 97 "~@memlock" 98 "~@module" 99 "~@mount" 100 "~@obsolete" 101 "~@privileged" 102 "~@raw-io" 103 "~@reboot" 104 "~@setuid" 105 "~@swap" 106 ]; 107 SystemCallErrorNumber = "EPERM"; 108 }; 109 }; 110 111 users.users = mkIf (cfg.user == "jellyfin") { 112 jellyfin = { 113 group = cfg.group; 114 isSystemUser = true; 115 }; 116 }; 117 118 users.groups = mkIf (cfg.group == "jellyfin") { 119 jellyfin = {}; 120 }; 121 122 networking.firewall = mkIf cfg.openFirewall { 123 # from https://jellyfin.org/docs/general/networking/index.html 124 allowedTCPPorts = [ 8096 8920 ]; 125 allowedUDPPorts = [ 1900 7359 ]; 126 }; 127 128 }; 129 130 meta.maintainers = with lib.maintainers; [ minijackson ]; 131}