22 cfg = config.services.your_spotify;
24 configEnv = concatMapAttrs (name: value:
25 optionalAttrs (value != null) {
28 then boolToString value
33 configFile = pkgs.writeText "your_spotify.env" (concatStrings (mapAttrsToList (name: value: "${name}=${value}\n") configEnv));
35 options.services.your_spotify = let
36 inherit (types) nullOr port str path package;
38 enable = mkEnableOption "your_spotify";
40 enableLocalDB = mkEnableOption "a local mongodb instance";
41 nginxVirtualHost = mkOption {
45 If set creates an nginx virtual host for the client.
46 In most cases this should be the CLIENT_ENDPOINT without
51 package = mkPackageOption pkgs "your_spotify" {};
53 clientPackage = mkOption {
55 description = "Client package to use.";
58 spotifySecretFile = mkOption {
61 A file containing the secret key of your Spotify application.
62 Refer to: [Creating the Spotify Application](https://github.com/Yooooomi/your_spotify#creating-the-spotify-application).
68 Your Spotify Configuration. Refer to [Your Spotify](https://github.com/Yooooomi/your_spotify) for definitions and values.
70 example = lib.literalExpression ''
72 CLIENT_ENDPOINT = "https://example.com";
73 API_ENDPOINT = "https://api.example.com";
74 SPOTIFY_PUBLIC = "spotify_client_id";
77 type = types.submodule {
78 freeformType = types.attrsOf types.str;
80 CLIENT_ENDPOINT = mkOption {
83 The endpoint of your web application.
84 Has to include a protocol Prefix (e.g. `http://`)
86 example = "https://your_spotify.example.org";
88 API_ENDPOINT = mkOption {
91 The endpoint of your server
92 This api has to be reachable from the device you use the website from not from the server.
93 This means that for example you may need two nginx virtual hosts if you want to expose this on the
95 Has to include a protocol Prefix (e.g. `http://`)
97 example = "https://localhost:3000";
99 SPOTIFY_PUBLIC = mkOption {
102 The public client ID of your Spotify application.
103 Refer to: [Creating the Spotify Application](https://github.com/Yooooomi/your_spotify#creating-the-spotify-application)
106 MONGO_ENDPOINT = mkOption {
108 description = ''The endpoint of the Mongo database.'';
109 default = "mongodb://localhost:27017/your_spotify";
113 description = "The port of the api server";
121 config = mkIf cfg.enable {
122 services.your_spotify.clientPackage = mkDefault (cfg.package.client.override {apiEndpoint = cfg.settings.API_ENDPOINT;});
123 systemd.services.your_spotify = {
124 after = ["network.target"];
126 export SPOTIFY_SECRET=$(< "$CREDENTIALS_DIRECTORY/SPOTIFY_SECRET")
127 ${lib.getExe' cfg.package "your_spotify_migrate"}
128 exec ${lib.getExe cfg.package}
131 User = "your_spotify";
132 Group = "your_spotify";
134 EnvironmentFile = [configFile];
135 StateDirectory = "your_spotify";
136 LimitNOFILE = "1048576";
138 PrivateDevices = true;
139 StateDirectoryMode = "0700";
142 LoadCredential = ["SPOTIFY_SECRET:${cfg.spotifySecretFile}"];
145 CapabilityBoundingSet = "";
146 LockPersonality = true;
147 #MemoryDenyWriteExecute = true; # Leads to coredump because V8 does JIT
150 ProtectControlGroups = true;
152 ProtectHostname = true;
153 ProtectKernelLogs = true;
154 ProtectKernelModules = true;
155 ProtectKernelTunables = true;
156 ProtectProc = "invisible";
158 ProtectSystem = "strict";
159 RestrictAddressFamilies = [
164 RestrictNamespaces = true;
165 RestrictRealtime = true;
166 SystemCallArchitectures = "native";
173 wantedBy = ["multi-user.target"];
175 services.nginx = mkIf (cfg.nginxVirtualHost != null) {
177 virtualHosts.${cfg.nginxVirtualHost} = {
178 root = cfg.clientPackage;
179 locations."/".extraConfig = ''
180 add_header Content-Security-Policy "frame-ancestors 'none';" ;
181 add_header X-Content-Type-Options "nosniff" ;
182 try_files = $uri $uri/ /index.html ;
186 services.mongodb = mkIf cfg.enableLocalDB {
190 meta.maintainers = with lib.maintainers; [patrickdag];