feat: enable scrutiny smartd monitoring

chore: update your_spotify
This commit is contained in:
Patrick 2024-03-27 17:05:20 +01:00
parent f12b52a0f2
commit 3e0e98f9aa
Signed by: patrick
GPG key ID: 451F95EFB8BECD0F
12 changed files with 134 additions and 107 deletions

View file

@ -123,6 +123,34 @@
}; };
}; };
wireguard.scrtiny-patrick.server = {
host = config.secrets.secrets.global.domains.web;
port = 51831;
reservedAddresses = ["10.44.0.0/16" "fd00:1766::/112"];
openFirewall = true;
};
services.scrutiny = {
enable = true;
openFirewall = true;
collector = {
enable = true;
settings.host.id = "elisabeth";
};
};
environment.persistence."/persist".directories = [
{
directory = "/var/lib/influxdb2";
mode = "0700";
user = "influxdb2";
}
];
environment.persistence."/state".directories = [
{
directory = "/var/lib/private/scrutiny";
mode = "0700";
}
];
fileSystems."/state".neededForBoot = true; fileSystems."/state".neededForBoot = true;
fileSystems."/persist".neededForBoot = true; fileSystems."/persist".neededForBoot = true;
boot.initrd.systemd.services."zfs-import-panzer".after = ["cryptsetup.target"]; boot.initrd.systemd.services."zfs-import-panzer".after = ["cryptsetup.target"];

View file

@ -200,10 +200,10 @@ in {
} }
]) ])
(blockOf "paperless" {maxBodySize = "5G";}) (blockOf "paperless" {maxBodySize = "5G";})
#(blockOf "ttrss" {port = 80;}) (blockOf "ttrss" {port = 80;})
(blockOf "yourspotify" {port = 80;}) (blockOf "yourspotify" {port = 80;})
(blockOf "apispotify" { (blockOf "apispotify" {
port = 80; port = 3000;
upstream = "yourspotify"; upstream = "yourspotify";
}) })
(blockOf "nextcloud" { (blockOf "nextcloud" {
@ -308,7 +308,7 @@ in {
// mkContainer "vaultwarden" {} // mkContainer "vaultwarden" {}
// mkContainer "ddclient" {} // mkContainer "ddclient" {}
// mkContainer "ollama" {} // mkContainer "ollama" {}
#// mkContainer "ttrss" {} // mkContainer "ttrss" {}
// mkContainer "yourspotify" {} // mkContainer "yourspotify" {}
// mkContainer "netbird" {} // mkContainer "netbird" {}
// mkContainer "kanidm" {} // mkContainer "kanidm" {}

View file

@ -32,6 +32,7 @@
authelia-main = uidGid 222; authelia-main = uidGid 222;
kanidm = uidGid 223; kanidm = uidGid 223;
oauth2_proxy = uidGid 224; oauth2_proxy = uidGid 224;
influxdb2 = uidGid 225;
paperless = uidGid 315; paperless = uidGid 315;
systemd-oom = uidGid 300; systemd-oom = uidGid 300;
systemd-coredump = uidGid 301; systemd-coredump = uidGid 301;

View file

@ -17,6 +17,7 @@
mkPackageOption mkPackageOption
optionalAttrs optionalAttrs
types types
mkDefault
; ;
cfg = config.services.your_spotify; cfg = config.services.your_spotify;
@ -32,7 +33,7 @@
configFile = pkgs.writeText "your_spotify.env" (concatStrings (mapAttrsToList (name: value: "${name}=${value}\n") configEnv)); configFile = pkgs.writeText "your_spotify.env" (concatStrings (mapAttrsToList (name: value: "${name}=${value}\n") configEnv));
in { in {
options.services.your_spotify = let options.services.your_spotify = let
inherit (types) nullOr port str path bool package; inherit (types) nullOr port str path package;
in { in {
enable = mkEnableOption "your_spotify"; enable = mkEnableOption "your_spotify";
@ -51,35 +52,35 @@ in {
clientPackage = mkOption { clientPackage = mkOption {
type = package; type = package;
default = cfg.package.client.override {apiEndpoint = cfg.settings.API_ENDPOINT;};
description = "Client package to use."; description = "Client package to use.";
}; };
spotifyPublicFile = mkOption {
type = path;
description = ''
The public key of your Spotify application
[Creating the Spotify Application](https://github.com/Yooooomi/your_spotify#creating-the-spotify-application)
'';
};
spotifySecretFile = mkOption { spotifySecretFile = mkOption {
type = path; type = path;
description = '' description = ''
The secret key of your Spotify application A file containing the secret key of your Spotify application.
[Creating the Spotify Application](https://github.com/Yooooomi/your_spotify#creating-the-spotify-application) Refer to: [Creating the Spotify Application](https://github.com/Yooooomi/your_spotify#creating-the-spotify-application).
Note that you may want to set this using the `environmentFile` config option to prevent
your secret from being world-readable in the nix store.
''; '';
}; };
settings = mkOption { 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 { type = types.submodule {
freeformType = types.attrsOf types.str; freeformType = types.attrsOf types.str;
options = { options = {
CLIENT_ENDPOINT = mkOption { CLIENT_ENDPOINT = mkOption {
type = str; type = str;
description = '' description = ''
The endpoint of your web application The endpoint of your web application.
Has to include a protocol Prefix (e.g. `http://`) Has to include a protocol Prefix (e.g. `http://`)
''; '';
example = "https://your_spotify.example.org"; example = "https://your_spotify.example.org";
@ -93,28 +94,18 @@ in {
internet. internet.
Has to include a protocol Prefix (e.g. `http://`) Has to include a protocol Prefix (e.g. `http://`)
''; '';
default = "https://localhost:3000"; example = "https://localhost:3000";
}; };
CORS = mkOption { SPOTIFY_PUBLIC = mkOption {
type = nullOr str;
description = ''
List of comma-separated origin allowed, or nothing to allow any origin
'';
default = null;
};
MAX_IMPORT_CACHESIZE = mkOption {
type = str; type = str;
description = '' description = ''
The maximum element in the cache when importing data from an outside source, The public client ID of your Spotify application.
more cache means less requests to Spotify, resulting in faster imports Refer to: [Creating the Spotify Application](https://github.com/Yooooomi/your_spotify#creating-the-spotify-application)
''; '';
default = "Infinite";
}; };
MONGO_ENDPOINT = mkOption { MONGO_ENDPOINT = mkOption {
type = str; type = str;
description = '' description = ''The endpoint of the Mongo database.'';
The endpoint of the Mongo database.
'';
default = "mongodb://localhost:27017/your_spotify"; default = "mongodb://localhost:27017/your_spotify";
}; };
PORT = mkOption { PORT = mkOption {
@ -122,47 +113,19 @@ in {
description = "The port of the api server"; description = "The port of the api server";
default = 3000; default = 3000;
}; };
TIMEZONE = mkOption {
type = str;
description = ''
The timezone of your stats, only affects read requests since data is saved with UTC time
'';
default = "Europe/Paris";
};
LOG_LEVEL = mkOption {
type = str;
description = ''
The log level, debug is useful if you encouter any bugs
'';
default = "info";
};
COOKIE_VALIDITY_MS = mkOption {
type = str;
description = ''
Validity time of the authentication cookie
'';
default = "1h";
};
MONGO_NO_ADMIN_RIGHTS = mkOption {
type = bool;
description = ''
Do not ask for admin right on the Mongo database
'';
default = false;
};
}; };
}; };
}; };
}; };
config = mkIf cfg.enable { config = mkIf cfg.enable {
services.your_spotify.clientPackage = mkDefault (cfg.package.client.override {apiEndpoint = cfg.settings.API_ENDPOINT;});
systemd.services.your_spotify = { systemd.services.your_spotify = {
after = ["network.target"]; after = ["network.target"];
script = '' script = ''
export SPOTIFY_PUBLIC=$(< "$CREDENTIALS_DIRECTORY/SPOTIFY_PUBLIC")
export SPOTIFY_SECRET=$(< "$CREDENTIALS_DIRECTORY/SPOTIFY_SECRET") export SPOTIFY_SECRET=$(< "$CREDENTIALS_DIRECTORY/SPOTIFY_SECRET")
${pkgs.your_spotify}/bin/your_spotify_migrate ${lib.getExe' cfg.package "your_spotify_migrate"}
exec ${pkgs.your_spotify}/bin/your_spotify_server exec ${lib.getExe cfg.package}
''; '';
serviceConfig = { serviceConfig = {
User = "your_spotify"; User = "your_spotify";
@ -176,26 +139,23 @@ in {
StateDirectoryMode = "0700"; StateDirectoryMode = "0700";
Restart = "always"; Restart = "always";
LoadCredential = ["SPOTIFY_PUBLIC:${cfg.spotifyPublicFile}" "SPOTIFY_SECRET:${cfg.spotifySecretFile}"]; LoadCredential = ["SPOTIFY_SECRET:${cfg.spotifySecretFile}"];
# Hardening # Hardening
CapabilityBoundingSet = ""; CapabilityBoundingSet = "";
LockPersonality = true; LockPersonality = true;
#MemoryDenyWriteExecute = true; #MemoryDenyWriteExecute = true; # Leads to coredump because V8 does JIT
#NoNewPrivileges = true; # Implied by DynamicUser
PrivateUsers = true; PrivateUsers = true;
#PrivateTmp = true; # Implied by DynamicUser
ProtectClock = true; ProtectClock = true;
ProtectControlGroups = true; ProtectControlGroups = true;
ProtectHome = true; ProtectHome = true;
ProtectHostname = false; # breaks bwrap ProtectHostname = true;
ProtectKernelLogs = false; # breaks bwrap ProtectKernelLogs = true;
ProtectKernelModules = true; ProtectKernelModules = true;
ProtectKernelTunables = false; # breaks bwrap ProtectKernelTunables = true;
ProtectProc = "invisible"; ProtectProc = "invisible";
ProcSubset = "all"; # Using "pid" breaks bwrap ProcSubset = "pid";
ProtectSystem = "strict"; ProtectSystem = "strict";
#RemoveIPC = true; # Implied by DynamicUser
RestrictAddressFamilies = [ RestrictAddressFamilies = [
"AF_INET" "AF_INET"
"AF_INET6" "AF_INET6"
@ -203,7 +163,6 @@ in {
]; ];
RestrictNamespaces = true; RestrictNamespaces = true;
RestrictRealtime = true; RestrictRealtime = true;
#RestrictSUIDSGID = true; # Implied by DynamicUser
SystemCallArchitectures = "native"; SystemCallArchitectures = "native";
SystemCallFilter = [ SystemCallFilter = [
"@system-service" "@system-service"
@ -218,6 +177,8 @@ in {
virtualHosts.${cfg.nginxVirtualHost} = { virtualHosts.${cfg.nginxVirtualHost} = {
root = cfg.clientPackage; root = cfg.clientPackage;
locations."/".extraConfig = '' locations."/".extraConfig = ''
add_header Content-Security-Policy "frame-ancestors 'none';" ;
add_header X-Content-Type-Options "nosniff" ;
try_files = $uri $uri/ /index.html ; try_files = $uri $uri/ /index.html ;
''; '';
}; };
@ -226,4 +187,5 @@ in {
enable = true; enable = true;
}; };
}; };
meta.maintainers = with lib.maintainers; [patrickdag];
} }

View file

@ -13,19 +13,14 @@
mode = "440"; mode = "440";
rekeyFile = config.node.secretsDir + "/spotifySecret.age"; rekeyFile = config.node.secretsDir + "/spotifySecret.age";
}; };
age.secrets.spotifyPublic = {
owner = "root";
mode = "440";
rekeyFile = config.node.secretsDir + "/spotifyPublic.age";
};
services.your_spotify = { services.your_spotify = {
enable = true; enable = true;
spotifySecretFile = config.age.secrets.spotifySecret.path; spotifySecretFile = config.age.secrets.spotifySecret.path;
spotifyPublicFile = config.age.secrets.spotifyPublic.path;
settings = { settings = {
SPOTIFY_PUBLIC = "5397a3f2a75949459da343a5e7851bd9";
CLIENT_ENDPOINT = "https://sptfy.${config.secrets.secrets.global.domains.web}"; CLIENT_ENDPOINT = "https://sptfy.${config.secrets.secrets.global.domains.web}";
API_ENDPOINT = "https://apisptfy.${config.secrets.secrets.global.domains.web}"; API_ENDPOINT = "https://apisptfy.${config.secrets.secrets.global.domains.web}";
MONGO_NO_ADMIN_RIGHTS = false; MONGO_NO_ADMIN_RIGHTS = "false";
}; };
enableLocalDB = true; enableLocalDB = true;
nginxVirtualHost = "sptfy.${config.secrets.secrets.global.domains.web}"; nginxVirtualHost = "sptfy.${config.secrets.secrets.global.domains.web}";

View file

@ -1,29 +1,30 @@
{ {
mkYarnPackage, callPackage,
fetchFromGitHub, fetchFromGitHub,
fetchYarnDeps, fetchYarnDeps,
makeWrapper,
nodejs,
yarn,
prefetch-yarn-deps,
lib, lib,
callPackage, makeWrapper,
mkYarnPackage,
nodejs,
prefetch-yarn-deps,
yarn,
}: let }: let
version = "1.8.0"; version = "1.10.1";
src = fetchFromGitHub { src = fetchFromGitHub {
owner = "Yooooomi"; owner = "Yooooomi";
repo = "your_spotify"; repo = "your_spotify";
rev = "refs/tags/${version}"; rev = "refs/tags/${version}";
hash = "sha256-umm7J5ADY2fl+tjs6Qeda5MX2P55u0eCqwW+DWLK8Kc="; hash = "sha256-e82j2blGxQLWAlBNuAnFvlD9vwMk4/mRI0Vf7vuaPA0=";
}; };
client = callPackage ./your_spotify_client.nix {inherit src version;}; client = callPackage ./your_spotify_client.nix {inherit src version;};
in in
mkYarnPackage rec { mkYarnPackage rec {
inherit version src; inherit version src;
pname = "your_spotify"; pname = "your_spotify_server";
name = "your_spotify_server-${version}";
offlineCache = fetchYarnDeps { offlineCache = fetchYarnDeps {
yarnLock = src + "/yarn.lock"; yarnLock = src + "/yarn.lock";
hash = "sha256-pj6owoEPx9gdtFvXF8E89A+Thhe/7m0+OJU6Ttc6ooA="; hash = "sha256-5SgknaRVzgO2Dzc8MhAaM8UERWMv+PrItzevoWHbWnA=";
}; };
configurePhase = '' configurePhase = ''
@ -32,33 +33,47 @@ in
export HOME=$(mktemp -d) export HOME=$(mktemp -d)
yarn config --offline set yarn-offline-mirror $offlineCache yarn config --offline set yarn-offline-mirror $offlineCache
fixup-yarn-lock yarn.lock fixup-yarn-lock yarn.lock
yarn install --offline --frozen-lockfile --ignore-platform --ignore-scripts --no-progress --non-interactive
patchShebangs node_modules/
runHook postConfigure runHook postConfigure
''; '';
buildPhase = '' buildPhase = ''
runHook preBuild runHook preBuild
ls -lah
yarn install --offline --frozen-lockfile --ignore-platform --ignore-scripts --no-progress --non-interactive
patchShebangs node_modules/
pushd ./apps/server/ pushd ./apps/server/
yarn --offline run build yarn --offline run build
popd popd
rm -r node_modules
export NODE_ENV="production"
yarn install --offline --frozen-lockfile --ignore-platform --ignore-scripts --no-progress --non-interactive
patchShebangs node_modules/
runHook postBuild runHook postBuild
''; '';
nativeBuildInputs = [makeWrapper yarn prefetch-yarn-deps]; nativeBuildInputs = [makeWrapper yarn prefetch-yarn-deps];
installPhase = '' installPhase = ''
mkdir -p $out mkdir -p $out/share/your_spotify
cp -r node_modules $out/node_modules cp -r node_modules $out/share/your_spotify/node_modules
cp -r ./apps/server/{lib,package.json} $out cp -r ./apps/server/{lib,package.json} $out
mkdir -p $out/bin mkdir -p $out/bin
makeWrapper ${lib.escapeShellArg (lib.getExe nodejs)} "$out/bin/your_spotify_migrate" \ makeWrapper ${lib.escapeShellArg (lib.getExe nodejs)} "$out/bin/your_spotify_migrate" \
--add-flags "$out/lib/migrations.js" --add-flags "$out/lib/migrations.js" --set NODE_PATH "$out/share/your_spotify/node_modules"
makeWrapper ${lib.escapeShellArg (lib.getExe nodejs)} "$out/bin/your_spotify_server" \ makeWrapper ${lib.escapeShellArg (lib.getExe nodejs)} "$out/bin/your_spotify_server" \
--add-flags "$out/lib/index.js" --add-flags "$out/lib/index.js" --set NODE_PATH "$out/share/your_spotify/node_modules"
''; '';
doDist = false; doDist = false;
passthru = { passthru = {
inherit client; inherit client;
}; };
meta = with lib; {
homepage = "https://github.com/Yooooomi/your_spotify";
changelog = "https://github.com/Yooooomi/your_spotify/releases/tag/${version}";
description = "Self-hosted application that tracks what you listen and offers you a dashboard to explore statistics about it";
license = licenses.gpl3Only;
maintainers = with maintainers; [patrickdag];
mainProgram = "your_spotify_server";
};
} }

View file

@ -1,19 +1,20 @@
{ {
mkYarnPackage, apiEndpoint ? "http://localhost:3000",
makeWrapper,
fetchYarnDeps, fetchYarnDeps,
apiEndpoint ? "localhost:8080", your_spotify,
mkYarnPackage,
prefetch-yarn-deps,
src, src,
version, version,
yarn, yarn,
prefetch-yarn-deps,
}: }:
mkYarnPackage rec { mkYarnPackage rec {
inherit version src; inherit version src;
pname = "your_spotify_client"; pname = "your_spotify_client";
name = "your_spotify_client-${version}";
offlineCache = fetchYarnDeps { offlineCache = fetchYarnDeps {
yarnLock = src + "/yarn.lock"; yarnLock = src + "/yarn.lock";
hash = "sha256-pj6owoEPx9gdtFvXF8E89A+Thhe/7m0+OJU6Ttc6ooA="; hash = "sha256-5SgknaRVzgO2Dzc8MhAaM8UERWMv+PrItzevoWHbWnA=";
}; };
configurePhase = '' configurePhase = ''
runHook preConfigure runHook preConfigure
@ -29,18 +30,26 @@ mkYarnPackage rec {
buildPhase = '' buildPhase = ''
runHook preBuild runHook preBuild
pushd ./apps/client/ pushd ./apps/client/
pwd
yarn --offline run build yarn --offline run build
export API_ENDPOINT="${apiEndpoint}"
substituteInPlace scripts/run/variables.sh --replace-quiet '/app/apps/client/' "./"
chmod +x ./scripts/run/variables.sh
patchShebangs --build ./scripts/run/variables.sh
./scripts/run/variables.sh
popd popd
runHook postBuild runHook postBuild
''; '';
nativeBuildInputs = [makeWrapper yarn prefetch-yarn-deps]; nativeBuildInputs = [yarn prefetch-yarn-deps];
installPhase = '' installPhase = ''
mkdir -p $out mkdir -p $out
cp -r ./apps/client/build/* $out cp -r ./apps/client/build/* $out
substituteInPlace $out/variables-template.js --replace-quiet '__API_ENDPOINT__' "${apiEndpoint}"
mv $out/variables-template.js $out/variables.js
''; '';
doDist = false; doDist = false;
meta = {
inherit (your_spotify.meta) homepage changelog description license maintainers;
};
} }

Binary file not shown.

View file

@ -0,0 +1,16 @@
age-encryption.org/v1
-> X25519 dUgBIIGKuR7jCfDHrVWvku15MhegXbRaGVAJvQ4G+FE
G1B2zJrK5P8jW5fwboLcwnUw6sTQ+rolXsZdLkh1NYg
-> piv-p256 XTQkUA AqCwFM9PXH41lIClU3/8w7nB334kYtXwy29qqZvKD6W6
2PvTP9Ru5i4W9N3N5BOre6OoctsVNXzMK3HS22VFgRE
-> piv-p256 ZFgiIw Ao/vA/FGcaNm3VonTzkZYM7rQZ3pYlXYcH6OHxIPxyBG
Jseiz60VbsygKZMZu1GpkoDsyoGwl23/+CFe6DL9aR4
-> piv-p256 5vmPtQ A8TcW3GJHKfN+kRUH3KSYTi2Tcn7hAyN/PpsA5GqwD+d
O2D6CO0rp7SFqOz//p2gbl6HCPD55qNbnqRnwNUrSDo
-> piv-p256 ZFgiIw AtDrLdrYjUegvT1qi2X3X8CyqJU05Z48iAe01piNm5G3
hrnn4uALqPzNsMOcdBFdqSmwV+L0r5sxSXWcTZz980I
-> k"-grease E[ZXL RpX[yO>J a3h4 a
ooUbsf5wnVPZ8Y0yjm8IrQMP+9oqQGIqcdi2fiGiKN2Q2gL8FGRcIRIEE0ZdpQIp
/06QStoFSQOgoI13SqpoHhg5cHSzWT4S2z0UFCpKsLZDZ+q1S7bxV1ST
--- zaXNrqNEe3bTj3oSGJljjj1ruZ5sBLBWRijLRr8Jxk4
èÌÖóŸZØûªÝ…ï.™PF3BC ÛÌÌt³OÀò@TÌ”‡<E2809D><36>º sûƒ:1wÈöîR}*ñ·×%ô- Íl,ld¸ˆa,V¹

View file

@ -0,0 +1 @@
QPZrzkguRzNQDyMfnC6O5b49QZRCAsv28N91nR2lal0=