at 25.11-pre 5.5 kB view raw
1{ 2 config, 3 lib, 4 pkgs, 5 ... 6}: 7 8let 9 inherit (lib) 10 mkEnableOption 11 mkPackageOption 12 mkOption 13 maintainers 14 ; 15 inherit (lib.types) 16 bool 17 port 18 str 19 submodule 20 ; 21 cfg = config.services.navidrome; 22 settingsFormat = pkgs.formats.json { }; 23in 24{ 25 options = { 26 services.navidrome = { 27 28 enable = mkEnableOption "Navidrome music server"; 29 30 package = mkPackageOption pkgs "navidrome" { }; 31 32 settings = mkOption { 33 type = submodule { 34 freeformType = settingsFormat.type; 35 36 options = { 37 Address = mkOption { 38 default = "127.0.0.1"; 39 description = "Address to run Navidrome on."; 40 type = str; 41 }; 42 43 Port = mkOption { 44 default = 4533; 45 description = "Port to run Navidrome on."; 46 type = port; 47 }; 48 49 EnableInsightsCollector = mkOption { 50 default = false; 51 description = "Enable anonymous usage data collection, see <https://www.navidrome.org/docs/getting-started/insights/> for details."; 52 type = bool; 53 }; 54 }; 55 }; 56 default = { }; 57 example = { 58 MusicFolder = "/mnt/music"; 59 }; 60 description = "Configuration for Navidrome, see <https://www.navidrome.org/docs/usage/configuration-options/> for supported values."; 61 }; 62 63 user = mkOption { 64 type = str; 65 default = "navidrome"; 66 description = "User under which Navidrome runs."; 67 }; 68 69 group = mkOption { 70 type = str; 71 default = "navidrome"; 72 description = "Group under which Navidrome runs."; 73 }; 74 75 openFirewall = mkOption { 76 type = bool; 77 default = false; 78 description = "Whether to open the TCP port in the firewall"; 79 }; 80 81 environmentFile = lib.mkOption { 82 type = lib.types.nullOr lib.types.path; 83 default = null; 84 description = "Environment file, used to set any secret ND_* environment variables."; 85 }; 86 }; 87 }; 88 89 config = 90 let 91 inherit (lib) mkIf optional getExe; 92 WorkingDirectory = "/var/lib/navidrome"; 93 in 94 mkIf cfg.enable { 95 systemd = { 96 tmpfiles.settings.navidromeDirs = { 97 "${cfg.settings.DataFolder or WorkingDirectory}"."d" = { 98 mode = "700"; 99 inherit (cfg) user group; 100 }; 101 "${cfg.settings.CacheFolder or (WorkingDirectory + "/cache")}"."d" = { 102 mode = "700"; 103 inherit (cfg) user group; 104 }; 105 "${cfg.settings.MusicFolder or (WorkingDirectory + "/music")}"."d" = { 106 mode = ":700"; 107 user = ":${cfg.user}"; 108 group = ":${cfg.group}"; 109 }; 110 }; 111 services.navidrome = { 112 description = "Navidrome Media Server"; 113 after = [ "network.target" ]; 114 wantedBy = [ "multi-user.target" ]; 115 serviceConfig = { 116 ExecStart = '' 117 ${getExe cfg.package} --configfile ${settingsFormat.generate "navidrome.json" cfg.settings} 118 ''; 119 EnvironmentFile = lib.mkIf (cfg.environmentFile != null) [ cfg.environmentFile ]; 120 User = cfg.user; 121 Group = cfg.group; 122 StateDirectory = "navidrome"; 123 inherit WorkingDirectory; 124 RuntimeDirectory = "navidrome"; 125 RootDirectory = "/run/navidrome"; 126 ReadWritePaths = ""; 127 BindPaths = 128 optional (cfg.settings ? DataFolder) cfg.settings.DataFolder 129 ++ optional (cfg.settings ? CacheFolder) cfg.settings.CacheFolder; 130 BindReadOnlyPaths = 131 [ 132 # navidrome uses online services to download additional album metadata / covers 133 "${config.security.pki.caBundle}:/etc/ssl/certs/ca-certificates.crt" 134 builtins.storeDir 135 "/etc" 136 ] 137 ++ optional (cfg.settings ? MusicFolder) cfg.settings.MusicFolder 138 ++ lib.optionals config.services.resolved.enable [ 139 "/run/systemd/resolve/stub-resolv.conf" 140 "/run/systemd/resolve/resolv.conf" 141 ]; 142 CapabilityBoundingSet = ""; 143 RestrictAddressFamilies = [ 144 "AF_UNIX" 145 "AF_INET" 146 "AF_INET6" 147 ]; 148 RestrictNamespaces = true; 149 PrivateDevices = true; 150 PrivateUsers = true; 151 ProtectClock = true; 152 ProtectControlGroups = true; 153 ProtectHome = true; 154 ProtectKernelLogs = true; 155 ProtectKernelModules = true; 156 ProtectKernelTunables = true; 157 SystemCallArchitectures = "native"; 158 SystemCallFilter = [ 159 "@system-service" 160 "~@privileged" 161 ]; 162 RestrictRealtime = true; 163 LockPersonality = true; 164 MemoryDenyWriteExecute = true; 165 UMask = "0066"; 166 ProtectHostname = true; 167 }; 168 }; 169 }; 170 171 users.users = mkIf (cfg.user == "navidrome") { 172 navidrome = { 173 inherit (cfg) group; 174 isSystemUser = true; 175 }; 176 }; 177 178 users.groups = mkIf (cfg.group == "navidrome") { navidrome = { }; }; 179 180 networking.firewall.allowedTCPPorts = mkIf cfg.openFirewall [ cfg.settings.Port ]; 181 }; 182 meta.maintainers = with maintainers; [ fsnkty ]; 183}