Personal-use NixOS configuration
at main 175 lines 4.3 kB view raw
1# based on https://github.com/tofu-salad/emby-server-flake/tree/a8c30e4160ee9c06ff1e875cd08dfd952868a5fb 2 3{ 4 config, 5 pkgs, 6 lib, 7 ... 8}: 9 10let 11 pkgs-internal = import ../packages { inherit pkgs; }; 12 13 inherit (lib) 14 mkIf 15 getExe 16 mkEnableOption 17 mkOption 18 ; 19 20 inherit (lib.types) 21 str 22 path 23 bool 24 package 25 ; 26 cfg = config.services.emby; 27in 28{ 29 options = { 30 services.emby = { 31 enable = mkEnableOption "Emby Media Server"; 32 33 package = mkOption { 34 type = package; 35 default = pkgs-internal.emby-server; 36 description = "The Emby package to use."; 37 }; 38 39 user = mkOption { 40 type = str; 41 default = "emby"; 42 description = "User account under which Emby runs."; 43 }; 44 45 group = mkOption { 46 type = str; 47 default = "emby"; 48 description = "Group under which Emby runs."; 49 }; 50 51 dataDir = mkOption { 52 type = path; 53 default = "/var/lib/emby"; 54 description = '' 55 Base data directory where Emby stores its program data. 56 This is passed to Emby with the `-programdata` flag. 57 ''; 58 }; 59 60 openFirewall = mkOption { 61 type = bool; 62 default = false; 63 description = '' 64 Open the default ports in the firewall for the media server. 65 Opens port 8096 (HTTP) and 8920 (HTTPS). 66 ''; 67 }; 68 }; 69 }; 70 71 config = mkIf cfg.enable { 72 systemd = { 73 tmpfiles.settings.embyDirs = { 74 "${cfg.dataDir}"."d" = { 75 mode = "700"; 76 inherit (cfg) user group; 77 }; 78 # Emby creates subdirectories automatically, but we ensure the base exists 79 "${cfg.dataDir}/plugins"."d" = { 80 mode = "755"; 81 inherit (cfg) user group; 82 }; 83 "${cfg.dataDir}/logs"."d" = { 84 mode = "755"; 85 inherit (cfg) user group; 86 }; 87 }; 88 89 services.emby = { 90 description = "Emby Media Server"; 91 after = [ "network-online.target" ]; 92 wants = [ "network-online.target" ]; 93 wantedBy = [ "multi-user.target" ]; 94 95 serviceConfig = { 96 Type = "simple"; 97 User = cfg.user; 98 Group = cfg.group; 99 UMask = "0077"; 100 WorkingDirectory = cfg.dataDir; 101 ExecStart = "${getExe cfg.package} -programdata '${cfg.dataDir}'"; 102 Restart = "on-failure"; 103 TimeoutSec = 15; 104 SuccessExitStatus = [ 105 "0" 106 "143" 107 ]; 108 109 # Security options (adapted from Jellyfin module): 110 NoNewPrivileges = true; 111 SystemCallArchitectures = "native"; 112 # AF_NETLINK needed because Emby monitors the network connection 113 RestrictAddressFamilies = [ 114 "AF_UNIX" 115 "AF_INET" 116 "AF_INET6" 117 "AF_NETLINK" 118 ]; 119 RestrictNamespaces = !config.boot.isContainer; 120 RestrictRealtime = true; 121 RestrictSUIDSGID = true; 122 ProtectControlGroups = !config.boot.isContainer; 123 ProtectHostname = true; 124 ProtectKernelLogs = !config.boot.isContainer; 125 ProtectKernelModules = !config.boot.isContainer; 126 ProtectKernelTunables = !config.boot.isContainer; 127 LockPersonality = true; 128 PrivateTmp = !config.boot.isContainer; 129 # needed for hardware acceleration 130 PrivateDevices = false; 131 PrivateUsers = true; 132 RemoveIPC = true; 133 134 SystemCallFilter = [ 135 "~@clock" 136 "~@aio" 137 "~@chown" 138 "~@cpu-emulation" 139 "~@debug" 140 "~@keyring" 141 "~@memlock" 142 "~@module" 143 "~@mount" 144 "~@obsolete" 145 "~@privileged" 146 "~@raw-io" 147 "~@reboot" 148 "~@setuid" 149 "~@swap" 150 ]; 151 SystemCallErrorNumber = "EPERM"; 152 }; 153 }; 154 }; 155 156 users.users = mkIf (cfg.user == "emby") { 157 emby = { 158 inherit (cfg) group; 159 isSystemUser = true; 160 }; 161 }; 162 163 users.groups = mkIf (cfg.group == "emby") { 164 emby = { }; 165 }; 166 167 networking.firewall = mkIf cfg.openFirewall { 168 # Emby default ports 169 allowedTCPPorts = [ 170 8096 # HTTP 171 8920 # HTTPS 172 ]; 173 }; 174 }; 175}