summaryrefslogtreecommitdiffstats
path: root/nixos
diff options
context:
space:
mode:
authorPatrick <patrick@failmail.dev>2024-04-13 10:58:52 +0200
committerPatrick <patrick@failmail.dev>2024-05-13 22:10:13 +0200
commit77a6460e741a0d7ef22e2382573e32771c7911ca (patch)
tree0a72f6efbdbc13c576ad77b01ee2a18badbaeb8b /nixos
parent86feff1d442f4fca39512d8f686f43e8edad4372 (diff)
nixos/your_spotify: init
Diffstat (limited to 'nixos')
-rw-r--r--nixos/doc/manual/release-notes/rl-2405.section.md2
-rw-r--r--nixos/modules/module-list.nix1
-rw-r--r--nixos/modules/services/web-apps/your_spotify.nix191
3 files changed, 194 insertions, 0 deletions
diff --git a/nixos/doc/manual/release-notes/rl-2405.section.md b/nixos/doc/manual/release-notes/rl-2405.section.md
index 489474468466..d6b8ffe8609f 100644
--- a/nixos/doc/manual/release-notes/rl-2405.section.md
+++ b/nixos/doc/manual/release-notes/rl-2405.section.md
@@ -187,6 +187,8 @@ The pre-existing [services.ankisyncd](#opt-services.ankisyncd.enable) has been m
- [xdg-terminal-exec](https://github.com/Vladimir-csp/xdg-terminal-exec), the proposed Default Terminal Execution Specification.
+- [your_spotify](https://github.com/Yooooomi/your_spotify), a self hosted Spotify tracking dashboard. Available as [services.your_spotify](#opt-services.your_spotify.enable)
+
- [RustDesk](https://rustdesk.com), a full-featured open source remote control alternative for self-hosting and security with minimal configuration. Alternative to TeamViewer. Available as [services.rustdesk-server](#opt-services.rustdesk-server.enable).
- [Scrutiny](https://github.com/AnalogJ/scrutiny), a S.M.A.R.T monitoring tool for hard disks with a web frontend. Available as [services.scrutiny](#opt-services.scrutiny.enable).
diff --git a/nixos/modules/module-list.nix b/nixos/modules/module-list.nix
index a92ae32d06fa..b14b83a8119a 100644
--- a/nixos/modules/module-list.nix
+++ b/nixos/modules/module-list.nix
@@ -1431,6 +1431,7 @@
./services/web-apps/windmill.nix
./services/web-apps/wordpress.nix
./services/web-apps/writefreely.nix
+ ./services/web-apps/your_spotify.nix
./services/web-apps/youtrack.nix
./services/web-apps/zabbix.nix
./services/web-apps/zitadel.nix
diff --git a/nixos/modules/services/web-apps/your_spotify.nix b/nixos/modules/services/web-apps/your_spotify.nix
new file mode 100644
index 000000000000..3eb2ffef4f93
--- /dev/null
+++ b/nixos/modules/services/web-apps/your_spotify.nix
@@ -0,0 +1,191 @@
+{
+ pkgs,
+ config,
+ lib,
+ ...
+}: let
+ inherit
+ (lib)
+ boolToString
+ concatMapAttrs
+ concatStrings
+ isBool
+ mapAttrsToList
+ mkEnableOption
+ mkIf
+ mkOption
+ mkPackageOption
+ optionalAttrs
+ types
+ mkDefault
+ ;
+ cfg = config.services.your_spotify;
+
+ configEnv = concatMapAttrs (name: value:
+ optionalAttrs (value != null) {
+ ${name} =
+ if isBool value
+ then boolToString value
+ else toString value;
+ })
+ cfg.settings;
+
+ configFile = pkgs.writeText "your_spotify.env" (concatStrings (mapAttrsToList (name: value: "${name}=${value}\n") configEnv));
+in {
+ options.services.your_spotify = let
+ inherit (types) nullOr port str path package;
+ in {
+ enable = mkEnableOption "your_spotify";
+
+ enableLocalDB = mkEnableOption "a local mongodb instance";
+ nginxVirtualHost = mkOption {
+ type = nullOr str;
+ default = null;
+ description = ''
+ If set creates an nginx virtual host for the client.
+ In most cases this should be the CLIENT_ENDPOINT without
+ protocol prefix.
+ '';
+ };
+
+ package = mkPackageOption pkgs "your_spotify" {};
+
+ clientPackage = mkOption {
+ type = package;
+ description = "Client package to use.";
+ };
+
+ spotifySecretFile = mkOption {
+ type = path;
+ description = ''
+ A file containing the secret key of your Spotify application.
+ Refer to: [Creating the Spotify Application](https://github.com/Yooooomi/your_spotify#creating-the-spotify-application).
+ '';
+ };
+
+ settings = mkOption {
+ description = ''
+ Your Spotify Configuration. Refer to [Your Spotify](https://github.com/Yooooomi/your_spotify) for definitions and values.
+ '';
+ example = lib.literalExpression ''
+ {
+ CLIENT_ENDPOINT = "https://example.com";
+ API_ENDPOINT = "https://api.example.com";
+ SPOTIFY_PUBLIC = "spotify_client_id";
+ }
+ '';
+ type = types.submodule {
+ freeformType = types.attrsOf types.str;
+ options = {
+ CLIENT_ENDPOINT = mkOption {
+ type = str;
+ description = ''
+ The endpoint of your web application.
+ Has to include a protocol Prefix (e.g. `http://`)
+ '';
+ example = "https://your_spotify.example.org";
+ };
+ API_ENDPOINT = mkOption {
+ type = str;
+ description = ''
+ The endpoint of your server
+ This api has to be reachable from the device you use the website from not from the server.
+ This means that for example you may need two nginx virtual hosts if you want to expose this on the
+ internet.
+ Has to include a protocol Prefix (e.g. `http://`)
+ '';
+ example = "https://localhost:3000";
+ };
+ SPOTIFY_PUBLIC = mkOption {
+ type = str;
+ description = ''
+ The public client ID of your Spotify application.
+ Refer to: [Creating the Spotify Application](https://github.com/Yooooomi/your_spotify#creating-the-spotify-application)
+ '';
+ };
+ MONGO_ENDPOINT = mkOption {
+ type = str;
+ description = ''The endpoint of the Mongo database.'';
+ default = "mongodb://localhost:27017/your_spotify";
+ };
+ PORT = mkOption {
+ type = port;
+ description = "The port of the api server";
+ default = 3000;
+ };
+ };
+ };
+ };
+ };
+
+ config = mkIf cfg.enable {
+ services.your_spotify.clientPackage = mkDefault (cfg.package.client.override {apiEndpoint = cfg.settings.API_ENDPOINT;});
+ systemd.services.your_spotify = {
+ after = ["network.target"];
+ script = ''
+ export SPOTIFY_SECRET=$(< "$CREDENTIALS_DIRECTORY/SPOTIFY_SECRET")
+ ${lib.getExe' cfg.package "your_spotify_migrate"}
+ exec ${lib.getExe cfg.package}
+ '';
+ serviceConfig = {
+ User = "your_spotify";
+ Group = "your_spotify";
+ DynamicUser = true;
+ EnvironmentFile = [configFile];
+ StateDirectory = "your_spotify";
+ LimitNOFILE = "1048576";
+ PrivateTmp = true;
+ PrivateDevices = true;
+ StateDirectoryMode = "0700";
+ Restart = "always";
+
+ LoadCredential = ["SPOTIFY_SECRET:${cfg.spotifySecretFile}"];
+
+ # Hardening
+ CapabilityBoundingSet = "";
+ LockPersonality = true;
+ #MemoryDenyWriteExecute = true; # Leads to coredump because V8 does JIT
+ PrivateUsers = true;
+ ProtectClock = true;
+ ProtectControlGroups = true;
+ ProtectHome = true;
+ ProtectHostname = true;
+ ProtectKernelLogs = true;
+ ProtectKernelModules = true;
+ ProtectKernelTunables = true;
+ ProtectProc = "invisible";
+ ProcSubset = "pid";
+ ProtectSystem = "strict";
+ RestrictAddressFamilies = [
+ "AF_INET"
+ "AF_INET6"
+ "AF_NETLINK"
+ ];
+ RestrictNamespaces = true;
+ RestrictRealtime = true;
+ SystemCallArchitectures = "native";
+ SystemCallFilter = [
+ "@system-service"
+ "@pkey"
+ ];
+ UMask = "0077";
+ };
+ wantedBy = ["multi-user.target"];
+ };
+ services.nginx = mkIf (cfg.nginxVirtualHost != null) {
+ enable = true;
+ virtualHosts.${cfg.nginxVirtualHost} = {
+ root = cfg.clientPackage;
+ locations."/".extraConfig = ''
+ add_header Content-Security-Policy "frame-ancestors 'none';" ;
+ add_header X-Content-Type-Options "nosniff" ;
+ try_files = $uri $uri/ /index.html ;
+ '';
+ };
+ };
+ services.mongodb = mkIf cfg.enableLocalDB {
+ enable = true;
+ };
+ };
+ meta.maintainers = with lib.maintainers; [patrickdag];
+}