at 25.11-pre 4.5 kB view raw
1{ 2 config, 3 pkgs, 4 lib, 5 ... 6}: 7let 8 cfg = config.services.polaris; 9 settingsFormat = pkgs.formats.toml { }; 10in 11{ 12 options = { 13 services.polaris = { 14 enable = lib.mkEnableOption "Polaris Music Server"; 15 16 package = lib.mkPackageOption pkgs "polaris" { }; 17 18 user = lib.mkOption { 19 type = lib.types.str; 20 default = "polaris"; 21 description = "User account under which Polaris runs."; 22 }; 23 24 group = lib.mkOption { 25 type = lib.types.str; 26 default = "polaris"; 27 description = "Group under which Polaris is run."; 28 }; 29 30 extraGroups = lib.mkOption { 31 type = lib.types.listOf lib.types.str; 32 default = [ ]; 33 description = "Polaris' auxiliary groups."; 34 example = lib.literalExpression ''["media" "music"]''; 35 }; 36 37 port = lib.mkOption { 38 type = lib.types.port; 39 default = 5050; 40 description = '' 41 The port which the Polaris REST api and web UI should listen to. 42 Note: polaris is hardcoded to listen to the hostname "0.0.0.0". 43 ''; 44 }; 45 46 settings = lib.mkOption { 47 type = settingsFormat.type; 48 default = { }; 49 description = '' 50 Contents for the TOML Polaris config, applied each start. 51 Although poorly documented, an example may be found here: 52 [test-config.toml](https://github.com/agersant/polaris/blob/374d0ca56fc0a466d797a4b252e2078607476797/test-data/config.toml) 53 ''; 54 example = lib.literalExpression '' 55 { 56 settings.reindex_every_n_seconds = 7*24*60*60; # weekly, default is 1800 57 settings.album_art_pattern = 58 "(cover|front|folder)\.(jpeg|jpg|png|bmp|gif)"; 59 mount_dirs = [ 60 { 61 name = "NAS"; 62 source = "/mnt/nas/music"; 63 } 64 { 65 name = "Local"; 66 source = "/home/my_user/Music"; 67 } 68 ]; 69 } 70 ''; 71 }; 72 73 openFirewall = lib.mkOption { 74 type = lib.types.bool; 75 default = false; 76 description = '' 77 Open the configured port in the firewall. 78 ''; 79 }; 80 }; 81 }; 82 83 config = lib.mkIf cfg.enable { 84 systemd.services.polaris = { 85 description = "Polaris Music Server"; 86 after = [ "network.target" ]; 87 wantedBy = [ "multi-user.target" ]; 88 89 serviceConfig = rec { 90 User = cfg.user; 91 Group = cfg.group; 92 DynamicUser = true; 93 SupplementaryGroups = cfg.extraGroups; 94 StateDirectory = "polaris"; 95 CacheDirectory = "polaris"; 96 ExecStart = lib.escapeShellArgs ( 97 [ 98 "${cfg.package}/bin/polaris" 99 "--foreground" 100 "--port" 101 cfg.port 102 "--database" 103 "/var/lib/${StateDirectory}/db.sqlite" 104 "--cache" 105 "/var/cache/${CacheDirectory}" 106 ] 107 ++ lib.optionals (cfg.settings != { }) [ 108 "--config" 109 (settingsFormat.generate "polaris-config.toml" cfg.settings) 110 ] 111 ); 112 Restart = "on-failure"; 113 114 # Security options: 115 116 #NoNewPrivileges = true; # implied by DynamicUser 117 #RemoveIPC = true; # implied by DynamicUser 118 119 AmbientCapabilities = ""; 120 CapabilityBoundingSet = ""; 121 122 DeviceAllow = ""; 123 124 LockPersonality = true; 125 126 #PrivateTmp = true; # implied by DynamicUser 127 PrivateDevices = true; 128 PrivateUsers = true; 129 130 ProtectClock = true; 131 ProtectControlGroups = true; 132 ProtectHostname = true; 133 ProtectKernelLogs = true; 134 ProtectKernelModules = true; 135 ProtectKernelTunables = true; 136 137 RestrictNamespaces = true; 138 RestrictAddressFamilies = [ 139 "AF_INET" 140 "AF_INET6" 141 "AF_UNIX" 142 ]; 143 RestrictRealtime = true; 144 #RestrictSUIDSGID = true; # implied by DynamicUser 145 146 SystemCallArchitectures = "native"; 147 SystemCallErrorNumber = "EPERM"; 148 SystemCallFilter = [ 149 "@system-service" 150 "~@cpu-emulation" 151 "~@debug" 152 "~@keyring" 153 "~@memlock" 154 "~@obsolete" 155 "~@privileged" 156 "~@setuid" 157 ]; 158 }; 159 }; 160 161 networking.firewall = lib.mkIf cfg.openFirewall { 162 allowedTCPPorts = [ cfg.port ]; 163 }; 164 165 }; 166 167 meta.maintainers = with lib.maintainers; [ pbsds ]; 168}