at 25.11-pre 6.9 kB view raw
1{ 2 config, 3 pkgs, 4 lib, 5 ... 6}: 7let 8 cfg = config.services.plex; 9in 10{ 11 imports = [ 12 (lib.mkRemovedOptionModule [ 13 "services" 14 "plex" 15 "managePlugins" 16 ] "Please omit or define the option: `services.plex.extraPlugins' instead.") 17 ]; 18 19 options = { 20 services.plex = { 21 enable = lib.mkEnableOption "Plex Media Server"; 22 23 dataDir = lib.mkOption { 24 type = lib.types.str; 25 default = "/var/lib/plex"; 26 description = '' 27 The directory where Plex stores its data files. 28 ''; 29 }; 30 31 openFirewall = lib.mkOption { 32 type = lib.types.bool; 33 default = false; 34 description = '' 35 Open ports in the firewall for the media server. 36 ''; 37 }; 38 39 user = lib.mkOption { 40 type = lib.types.str; 41 default = "plex"; 42 description = '' 43 User account under which Plex runs. 44 ''; 45 }; 46 47 group = lib.mkOption { 48 type = lib.types.str; 49 default = "plex"; 50 description = '' 51 Group under which Plex runs. 52 ''; 53 }; 54 55 extraPlugins = lib.mkOption { 56 type = lib.types.listOf lib.types.path; 57 default = [ ]; 58 description = '' 59 A list of paths to extra plugin bundles to install in Plex's plugin 60 directory. Every time the systemd unit for Plex starts up, all of the 61 symlinks in Plex's plugin directory will be cleared and this module 62 will symlink all of the paths specified here to that directory. 63 ''; 64 example = lib.literalExpression '' 65 [ 66 (builtins.path { 67 name = "Audnexus.bundle"; 68 path = pkgs.fetchFromGitHub { 69 owner = "djdembeck"; 70 repo = "Audnexus.bundle"; 71 rev = "v0.2.8"; 72 sha256 = "sha256-IWOSz3vYL7zhdHan468xNc6C/eQ2C2BukQlaJNLXh7E="; 73 }; 74 }) 75 ] 76 ''; 77 }; 78 79 extraScanners = lib.mkOption { 80 type = lib.types.listOf lib.types.path; 81 default = [ ]; 82 description = '' 83 A list of paths to extra scanners to install in Plex's scanners 84 directory. 85 86 Every time the systemd unit for Plex starts up, all of the symlinks 87 in Plex's scanners directory will be cleared and this module will 88 symlink all of the paths specified here to that directory. 89 ''; 90 example = lib.literalExpression '' 91 [ 92 (fetchFromGitHub { 93 owner = "ZeroQI"; 94 repo = "Absolute-Series-Scanner"; 95 rev = "773a39f502a1204b0b0255903cee4ed02c46fde0"; 96 sha256 = "4l+vpiDdC8L/EeJowUgYyB3JPNTZ1sauN8liFAcK+PY="; 97 }) 98 ] 99 ''; 100 }; 101 102 accelerationDevices = lib.mkOption { 103 type = lib.types.listOf lib.types.str; 104 default = [ "*" ]; 105 example = [ "/dev/dri/renderD128" ]; 106 description = '' 107 A list of device paths to hardware acceleration devices that Plex should 108 have access to. This is useful when transcoding media files. 109 The special value `"*"` will allow all devices. 110 ''; 111 }; 112 113 package = lib.mkPackageOption pkgs "plex" { 114 extraDescription = '' 115 Plex subscribers may wish to use their own package here, 116 pointing to subscriber-only server versions. 117 ''; 118 }; 119 }; 120 }; 121 122 config = lib.mkIf cfg.enable { 123 # Most of this is just copied from the RPM package's systemd service file. 124 systemd.services.plex = { 125 description = "Plex Media Server"; 126 after = [ "network.target" ]; 127 wantedBy = [ "multi-user.target" ]; 128 129 serviceConfig = { 130 Type = "simple"; 131 User = cfg.user; 132 Group = cfg.group; 133 134 # Run the pre-start script with full permissions (the "!" prefix) so it 135 # can create the data directory if necessary. 136 ExecStartPre = 137 let 138 preStartScript = pkgs.writeScript "plex-run-prestart" '' 139 #!${pkgs.bash}/bin/bash 140 141 # Create data directory if it doesn't exist 142 if ! test -d "$PLEX_DATADIR"; then 143 echo "Creating initial Plex data directory in: $PLEX_DATADIR" 144 install -d -m 0755 -o "${cfg.user}" -g "${cfg.group}" "$PLEX_DATADIR" 145 fi 146 ''; 147 in 148 "!${preStartScript}"; 149 150 ExecStart = "${cfg.package}/bin/plexmediaserver"; 151 KillSignal = "SIGQUIT"; 152 PIDFile = "${cfg.dataDir}/Plex Media Server/plexmediaserver.pid"; 153 Restart = "on-failure"; 154 155 # Hardening 156 NoNewPrivileges = true; 157 PrivateTmp = true; 158 PrivateDevices = cfg.accelerationDevices == [ ]; 159 DeviceAllow = lib.mkIf ( 160 cfg.accelerationDevices != [ ] && !lib.elem "*" cfg.accelerationDevices 161 ) cfg.accelerationDevices; 162 ProtectSystem = true; 163 ProtectHome = true; 164 ProtectControlGroups = true; 165 ProtectKernelModules = true; 166 ProtectKernelTunables = true; 167 RestrictAddressFamilies = [ 168 "AF_UNIX" 169 "AF_INET" 170 "AF_INET6" 171 "AF_NETLINK" 172 ]; 173 # This could be made to work if the namespaces needed were known 174 # RestrictNamespaces = true; 175 RestrictRealtime = true; 176 RestrictSUIDSGID = true; 177 MemoryDenyWriteExecute = true; 178 LockPersonality = true; 179 }; 180 181 environment = { 182 # Configuration for our FHS userenv script 183 PLEX_DATADIR = cfg.dataDir; 184 PLEX_PLUGINS = lib.concatMapStringsSep ":" builtins.toString cfg.extraPlugins; 185 PLEX_SCANNERS = lib.concatMapStringsSep ":" builtins.toString cfg.extraScanners; 186 187 # The following variables should be set by the FHS userenv script: 188 # PLEX_MEDIA_SERVER_APPLICATION_SUPPORT_DIR 189 # PLEX_MEDIA_SERVER_HOME 190 191 # Allow access to GPU acceleration; the Plex LD_LIBRARY_PATH is added 192 # by the FHS userenv script. 193 LD_LIBRARY_PATH = "/run/opengl-driver/lib"; 194 195 PLEX_MEDIA_SERVER_MAX_PLUGIN_PROCS = "6"; 196 PLEX_MEDIA_SERVER_TMPDIR = "/tmp"; 197 PLEX_MEDIA_SERVER_USE_SYSLOG = "true"; 198 LC_ALL = "en_US.UTF-8"; 199 LANG = "en_US.UTF-8"; 200 }; 201 }; 202 203 networking.firewall = lib.mkIf cfg.openFirewall { 204 allowedTCPPorts = [ 205 32400 206 3005 207 8324 208 32469 209 ]; 210 allowedUDPPorts = [ 211 1900 212 5353 213 32410 214 32412 215 32413 216 32414 217 ]; 218 }; 219 220 users.users = lib.mkIf (cfg.user == "plex") { 221 plex = { 222 group = cfg.group; 223 uid = config.ids.uids.plex; 224 }; 225 }; 226 227 users.groups = lib.mkIf (cfg.group == "plex") { 228 plex = { 229 gid = config.ids.gids.plex; 230 }; 231 }; 232 }; 233}