11 Commits

Author SHA1 Message Date
7c729a065e bump clan-core 2025-08-07 10:15:03 +07:00
16a2d980de paperless service 2025-08-07 10:08:14 +07:00
846d689b2c pingvin service 2025-08-05 17:16:02 +07:00
cc0aaff3ed bump nixpkgs 2025-08-05 15:42:25 +07:00
fca02307a0 grafana service 2025-08-04 15:36:07 +07:00
db855963dc fix wrong instance name 2025-07-31 16:01:03 +07:00
cc628f47b7 rework victoriametrics to be more generic with test 2025-07-31 15:56:46 +07:00
5109c3f4fa rework stirling-pdf to be more generic with test 2025-07-31 10:40:31 +07:00
c5c8e0050d rework actual-budget to be more generic with test 2025-07-30 17:28:23 +07:00
bfd0dd1a41 vikunja service backup folders 2025-07-30 15:38:07 +07:00
d606f9e88e nextcloud service backup folders 2025-07-30 15:37:51 +07:00
45 changed files with 908 additions and 143 deletions

34
flake.lock generated
View File

@@ -20,11 +20,11 @@
]
},
"locked": {
"lastModified": 1753024554,
"narHash": "sha256-oVriwkUkY3xs7HONbusnaXxyGecMAdi/QLZ2Z7jZKAM=",
"lastModified": 1754535625,
"narHash": "sha256-RdT3/DskBjwx74cvHJHb/mLSO2XeSHitSYViNmYGU/k=",
"ref": "refs/heads/main",
"rev": "f6284a7ac228789feba4f6b33be49960ee8afe4a",
"revCount": 8541,
"rev": "f69e28a1333527cdbadb233966a7e19d4b35a1a3",
"revCount": 8886,
"type": "git",
"url": "https://git.clan.lol/clan/clan-core"
},
@@ -49,11 +49,11 @@
]
},
"locked": {
"lastModified": 1752589312,
"narHash": "sha256-BafZOenlzMYdumG12AzgVLhEVu+GcEa8nYNDSIYe1U0=",
"rev": "496bbf05a2aa7b061ef464254db5804d1c6f45b4",
"lastModified": 1753067306,
"narHash": "sha256-jyoEbaXa8/MwVQ+PajUdT63y3gYhgD9o7snO/SLaikw=",
"rev": "18dfd42bdb2cfff510b8c74206005f733e38d8b9",
"type": "tarball",
"url": "https://git.clan.lol/api/v1/repos/clan/data-mesher/archive/496bbf05a2aa7b061ef464254db5804d1c6f45b4.tar.gz"
"url": "https://git.clan.lol/api/v1/repos/clan/data-mesher/archive/18dfd42bdb2cfff510b8c74206005f733e38d8b9.tar.gz"
},
"original": {
"type": "tarball",
@@ -88,11 +88,11 @@
]
},
"locked": {
"lastModified": 1752718651,
"narHash": "sha256-PkaR0qmyP9q/MDN3uYa+RLeBA0PjvEQiM0rTDDBXkL8=",
"lastModified": 1753140376,
"narHash": "sha256-7lrVrE0jSvZHrxEzvnfHFE/Wkk9DDqb+mYCodI5uuB8=",
"owner": "nix-community",
"repo": "disko",
"rev": "d5ad4485e6f2edcc06751df65c5e16572877db88",
"rev": "545aba02960caa78a31bd9a8709a0ad4b6320a5c",
"type": "github"
},
"original": {
@@ -187,11 +187,11 @@
},
"nixpkgs": {
"locked": {
"lastModified": 1752900028,
"narHash": "sha256-dPALCtmik9Wr14MGqVXm+OQcv7vhPBXcWNIOThGnB/Q=",
"lastModified": 1754278406,
"narHash": "sha256-jvIQTMN5EzoOP5RaGztpVese8a3wqy0M/h6tNzycW28=",
"owner": "nixos",
"repo": "nixpkgs",
"rev": "6b4955211758ba47fac850c040a27f23b9b4008f",
"rev": "6a489c9482ca676ce23c0bcd7f2e1795383325fa",
"type": "github"
},
"original": {
@@ -219,11 +219,11 @@
]
},
"locked": {
"lastModified": 1752544651,
"narHash": "sha256-GllP7cmQu7zLZTs9z0J2gIL42IZHa9CBEXwBY9szT0U=",
"lastModified": 1754328224,
"narHash": "sha256-glPK8DF329/dXtosV7YSzRlF4n35WDjaVwdOMEoEXHA=",
"owner": "Mic92",
"repo": "sops-nix",
"rev": "2c8def626f54708a9c38a5861866660395bb3461",
"rev": "49021900e69812ba7ddb9e40f9170218a7eca9f4",
"type": "github"
},
"original": {

View File

@@ -7,11 +7,6 @@
}:
{
clan = {
modules = {
stirling-pdf = ../modules/clan/stirling-pdf;
actual-budget = ../modules/clan/actual-budget;
victoria-metrics = ../modules/clan/victoria-metrics;
};
inventory = {
machines = {
@@ -60,9 +55,9 @@
};
roles.default.machines.b4l = { };
};
victoria-metrics = {
victoriametrics = {
module = {
name = "victoria-metrics";
name = "victoriametrics";
input = "self";
};
roles.default.machines.b4l = { };
@@ -74,6 +69,27 @@
};
roles.default.machines.b4l = { };
};
grafana = {
module = {
name = "grafana";
input = "self";
};
roles.default.machines.b4l = { };
};
pingvin = {
module = {
name = "pingvin";
input = "self";
};
roles.default.machines.b4l = { };
};
paperless = {
module = {
name = "paperless";
input = "self";
};
roles.default.machines.b4l = { };
};
};
};
};

View File

@@ -0,0 +1,36 @@
{ config, ... }:
let
abDomain = "${config.clan.core.vars.generators.b4l-actual-budget.files.subdomain.value}.${config.networking.fqdn}";
in
{
clan.core.vars.generators.b4l-actual-budget = {
files.subdomain.secret = false;
prompts = {
subdomain = {
persist = true;
type = "line";
description = "Sub-domain for Actual Budget app. Default:(budget)";
};
};
script = ''cat $prompts/subdomain || echo -n "budget" > $out/subdomain'';
};
services.actual = {
settings = {
allowedLoginMethods = [
"password"
"openid"
];
trustedProxies = [ "127.0.0.1" ];
};
};
services.nginx.virtualHosts."${abDomain}" = {
useACMEHost = "${config.networking.fqdn}";
forceSSL = true;
locations."/" = {
proxyPass = "http://localhost:${builtins.toString config.services.actual.settings.port}";
};
};
}

View File

@@ -0,0 +1,79 @@
{
pkgs,
config,
lib,
...
}:
with lib;
let
serviceName = "${config.networking.hostName}-grafana";
gfDomain = "${
config.clan.core.vars.generators."${serviceName}".files.subdomain.value
}.${config.networking.fqdn}";
settingsFormatIni = pkgs.formats.ini {
listToValue = concatMapStringsSep " " (generators.mkValueStringDefault { });
mkKeyValue = generators.mkKeyValueDefault {
mkValueString = v: if v == null then "" else generators.mkValueStringDefault { } v;
} "=";
};
configFile = settingsFormatIni.generate "config.ini" config.services.grafana.settings;
in
{
clan.core.vars.generators."${serviceName}" = {
files = {
adminpassword.secret = true;
subdomain.secret = false;
};
prompts = {
subdomain = {
persist = true;
type = "line";
description = "Sub-domain for Grafana. Default:(grafana)";
};
adminpassword = {
persist = true;
type = "hidden";
description = "Password for the admin user. Leave empty to auto-generate.";
};
};
runtimeInputs = [
pkgs.xkcdpass
pkgs.coreutils
];
script = ''
prompt_domain=$(cat "$prompts"/subdomain)
if [[ -n "''${prompt_domain-}" ]]; then
echo $prompt_domain | tr -d "\n" > "$out"/subdomain
else
echo -n "grafana" > "$out"/subdomain
fi
prompt_password=$(cat "$prompts"/adminpassword)
if [[ -n "''${prompt_password-}" ]]; then
echo "$prompt_password" | tr -d "\n" > "$out"/adminpassword
else
xkcdpass --numwords 4 --delimiter - --count 1 | tr -d "\n" > "$out"/adminpassword
fi
'';
};
systemd.services.grafana.serviceConfig.ExecStartPre = [
"+${pkgs.writeShellScript "grafana-set-password" ''
${pkgs.grafana}/bin/grafana cli --homepath ${config.services.grafana.dataDir} --config ${configFile} admin reset-admin-password $(cat ${
config.clan.core.vars.generators."${serviceName}".files.adminpassword.path
})
''}"
];
services.nginx.virtualHosts."${gfDomain}" = {
forceSSL = true;
useACMEHost = "${config.networking.fqdn}";
locations."/" = {
proxyPass = "http://localhost:${builtins.toString config.services.grafana.settings.server.http_port}";
};
};
}

View File

@@ -0,0 +1,67 @@
{ config, pkgs, ... }:
let
serviceName = "${config.networking.hostName}-paperless";
domain-name = "${
config.clan.core.vars.generators."${serviceName}".files.subdomain.value
}.${config.networking.fqdn}";
in
{
clan.core.vars.generators."${serviceName}" = {
files = {
subdomain.secret = false;
adminpassword = {
secret = true;
owner = config.services.paperless.user;
group = config.services.paperless.user;
};
};
prompts = {
subdomain = {
persist = true;
type = "line";
description = "Sub-domain for Paperless. Default:(paperless)";
};
adminpassword = {
persist = true;
type = "hidden";
description = "Password for the admin user. Leave empty to auto-generate.";
};
};
runtimeInputs = [
pkgs.xkcdpass
pkgs.coreutils
];
script = ''
prompt_domain=$(cat "$prompts"/subdomain)
if [[ -n "''${prompt_domain-}" ]]; then
echo $prompt_domain | tr -d "\n" > "$out"/subdomain
else
echo -n "paperless" > "$out"/subdomain
fi
prompt_password=$(cat "$prompts"/adminpassword)
if [[ -n "''${prompt_password-}" ]]; then
echo "$prompt_password" | tr -d "\n" > "$out"/adminpassword
else
xkcdpass --numwords 4 --delimiter - --count 1 | tr -d "\n" > "$out"/adminpassword
fi
'';
};
environment.systemPackages = [ pkgs.toybox ];
services.paperless = {
passwordFile = config.clan.core.vars.generators."${serviceName}".files.adminpassword.path;
};
services.nginx.virtualHosts."${domain-name}" = {
forceSSL = true;
useACMEHost = "${config.networking.fqdn}";
locations."/" = {
proxyPass = "http://localhost:${builtins.toString config.services.paperless.port}";
};
};
}

View File

@@ -0,0 +1,45 @@
{
pkgs,
config,
...
}:
let
serviceName = "${config.networking.hostName}-pingvin";
domain-name = "${
config.clan.core.vars.generators."${serviceName}".files.subdomain.value
}.${config.networking.fqdn}";
in
{
clan.core.vars.generators."${serviceName}" = {
files = {
subdomain.secret = false;
};
prompts = {
subdomain = {
persist = true;
type = "line";
description = "Sub-domain for Pingvin. Default:(share)";
};
};
runtimeInputs = [
pkgs.xkcdpass
pkgs.coreutils
];
script = ''
prompt_domain=$(cat "$prompts"/subdomain)
if [[ -n "''${prompt_domain-}" ]]; then
echo $prompt_domain | tr -d "\n" > "$out"/subdomain
else
echo -n "share" > "$out"/subdomain
fi
'';
};
services.pingvin-share = {
nginx.enable = true;
https = true;
hostname = domain-name;
};
}

View File

@@ -0,0 +1,26 @@
{ config, ... }:
let
stDomain = "${config.clan.core.vars.generators.b4l-stirling-pdf.files.subdomain.value}.${config.networking.fqdn}";
in
{
clan.core.vars.generators.b4l-stirling-pdf = {
files.subdomain.secret = false;
prompts = {
subdomain = {
persist = true;
type = "line";
description = "Sub-domain for Stirling PDF app. Default:(pdf)";
};
};
script = ''cat $prompts/subdomain || echo -n "pdf" > $out/subdomain'';
};
services.nginx.virtualHosts."${stDomain}" = {
forceSSL = true;
useACMEHost = "${config.networking.fqdn}";
locations."/" = {
proxyPass = "http://localhost:${builtins.toString config.services.stirling-pdf.environment.SERVER_PORT}";
};
};
}

View File

@@ -0,0 +1,73 @@
{ config, pkgs, ... }:
let
vmDomain = "${config.clan.core.vars.generators.b4l-victoriametrics.files.subdomain.value}.${config.networking.fqdn}";
in
{
clan.core.vars.generators.b4l-victoriametrics = {
files.subdomain.secret = false;
files.adminuser.secret = false;
files.adminpassword.secret = true;
prompts = {
subdomain = {
persist = true;
type = "line";
description = "Sub-domain for Victoria Metrics app. Default:(metrics)";
};
adminuser = {
persist = true;
type = "line";
description = "Username for an admin user. Default:(admin)";
};
adminpassword = {
persist = true;
type = "hidden";
description = "Password for the admin user. Leave empty to auto-generate.";
};
};
runtimeInputs = [
pkgs.xkcdpass
pkgs.coreutils
];
script = ''
prompt_domain=$(cat "$prompts"/subdomain)
if [[ -n "''${prompt_domain-}" ]]; then
echo $prompt_domain | tr -d "\n" > "$out"/subdomain
else
echo -n "metrics" > "$out"/subdomain
fi
prompt_adminuser=$(cat "$prompts"/adminuser)
if [[ -n "''${prompt_adminuser-}" ]]; then
echo $prompt_adminuser | tr -d "\n" > "$out"/adminuser
else
echo -n "admin" > "$out"/adminuser
fi
prompt_password=$(cat "$prompts"/adminpassword)
if [[ -n "''${prompt_password-}" ]]; then
echo "$prompt_password" | tr -d "\n" > "$out"/adminpassword
else
xkcdpass --numwords 4 --delimiter - --count 1 | tr -d "\n" > "$out"/adminpassword
fi
'';
};
services.victoriametrics = {
extraOptions = [
"-httpAuth.username=file://${config.clan.core.vars.generators.b4l-victoriametrics.files.adminuser.path}"
"-httpAuth.password=file://${config.clan.core.vars.generators.b4l-victoriametrics.files.adminpassword.path}"
];
};
services.nginx.virtualHosts."${vmDomain}" = {
forceSSL = true;
useACMEHost = "${config.networking.fqdn}";
locations."/" = {
proxyPass = "http://localhost${builtins.toString config.services.victoriametrics.listenAddress}";
};
};
}

View File

@@ -1,4 +1,4 @@
{ lib, ... }:
{ ... }:
{
_class = "clan.service";
manifest.name = "actual-budget";
@@ -6,49 +6,21 @@
manifest.categories = [ "System" ];
roles.default = {
interface.options = {
domain = lib.mkOption {
type = lib.types.str;
default = "budget";
description = "Sub domain for Actual Budget.";
};
};
perInstance =
perInstance.nixosModule =
{
settings,
lib,
config,
...
}:
{
nixosModule =
{
config,
...
}:
let
domain = "${settings.domain}.${config.networking.fqdn}";
in
{
services.actual = {
enable = true;
openFirewall = true;
settings = {
port = 5006;
allowedLoginMethods = [
"password"
"openid"
];
trustedProxies = [ "127.0.0.1" ];
};
};
services.nginx.virtualHosts."${domain}" = {
forceSSL = true;
useACMEHost = "${config.networking.fqdn}";
locations."/" = {
proxyPass = "http://localhost:${builtins.toString config.services.actual.settings.port}";
};
};
};
services.actual = {
enable = lib.mkDefault true;
};
clan.core.state.actual-budget.folders = [
config.systemd.services.actual.serviceConfig.WorkingDirectory
];
};
};
}

View File

@@ -0,0 +1,19 @@
{ lib, ... }:
let
module = lib.modules.importApply ./default.nix { };
in
{
clan.modules = {
actual-budget = module;
};
perSystem =
{ ... }:
{
clan.nixosTests.actual-budget = {
imports = [ ./tests/vm/default.nix ];
clan.modules."@clan/actual-budget" = module;
};
};
}

View File

@@ -0,0 +1,34 @@
{
...
}:
{
name = "service-actual-budget";
clan = {
directory = ./.;
inventory = {
machines.server = { };
instances = {
actual-budget-test = {
module.name = "@clan/actual-budget";
module.input = "self";
roles.default.machines."server".settings = { };
};
};
};
};
nodes = {
server = { };
};
testScript = ''
start_all()
server.wait_for_unit("actual")
server.succeed("systemctl status actual")
'';
}

View File

@@ -0,0 +1,24 @@
{ ... }:
{
_class = "clan.service";
manifest.name = "grafana";
manifest.description = "Platform for data analytics and monitoring";
manifest.categories = [ "System" ];
roles.default = {
perInstance.nixosModule =
{
config,
lib,
...
}:
{
services.grafana = {
enable = lib.mkDefault true;
};
clan.core.state.grafana.folders = [ config.services.grafana.dataDir ];
};
};
}

View File

@@ -0,0 +1,18 @@
{ lib, ... }:
let
module = lib.modules.importApply ./default.nix { };
in
{
clan.modules = {
grafana = module;
};
perSystem =
{ ... }:
{
clan.nixosTests.grafana = {
imports = [ ./tests/vm/default.nix ];
clan.modules."@clan/grafana" = module;
};
};
}

View File

@@ -0,0 +1,42 @@
{
...
}:
{
name = "service-grafana";
clan = {
directory = ./.;
inventory = {
machines.server = { };
instances = {
grafana-test = {
module.name = "@clan/grafana";
module.input = "self";
roles.default.machines."server".settings = { };
};
};
};
};
nodes = {
server = {
services.grafana = {
settings = {
server.domain = "grafana.localhost";
};
};
};
};
testScript = ''
start_all()
server.wait_for_unit("grafana")
server.succeed("systemctl status grafana")
server.wait_for_open_port(3000)
server.succeed("curl -H \"Host: grafana.localhost\" http://127.0.0.1:3000 ")
server.succeed("grafana cli -v")
'';
}

View File

@@ -45,6 +45,16 @@
};
};
clan.core.state.nextcloud.folders = [
config.services.nextcloud.home
]
++ (
if config.services.nextcloud.home != config.services.nextcloud.datadir then
[ config.services.nextcloud.datadir ]
else
[ ]
);
};
};
}

View File

@@ -0,0 +1,24 @@
{ ... }:
{
_class = "clan.service";
manifest.name = "paperless";
manifest.description = "A community-supported supercharged document management system: scan, index and archive all your documents";
manifest.categories = [ "System" ];
roles.default = {
perInstance.nixosModule =
{
lib,
config,
...
}:
{
services.paperless = {
enable = lib.mkDefault true;
};
clan.core.state.paperless.folders = [ config.services.paperless.dataDir ];
};
};
}

View File

@@ -0,0 +1,19 @@
{ lib, ... }:
let
module = lib.modules.importApply ./default.nix { };
in
{
clan.modules = {
paperless = module;
};
perSystem =
{ ... }:
{
clan.nixosTests.paperless = {
imports = [ ./tests/vm/default.nix ];
clan.modules."@clan/paperless" = module;
};
};
}

View File

@@ -0,0 +1,38 @@
{
...
}:
{
name = "service-paperless";
clan = {
directory = ./.;
inventory = {
machines.server = { };
instances = {
paperless-test = {
module.name = "@clan/paperless";
module.input = "self";
roles.default.machines."server".settings = { };
};
};
};
};
nodes = {
server = {
services.paperless = {
};
};
};
testScript = ''
start_all()
server.wait_for_unit("paperless-web")
server.succeed("systemctl status paperless-web")
server.wait_for_open_port(28981)
server.succeed("curl http://127.0.0.1:28981")
'';
}

View File

@@ -0,0 +1,23 @@
{ ... }:
{
_class = "clan.service";
manifest.name = "pingvin";
manifest.description = "A self-hosted file sharing platform that combines lightness and beauty, perfect for seamless and efficient file sharing.";
manifest.categories = [ "System" ];
roles.default = {
perInstance.nixosModule =
{
config,
...
}:
{
services.pingvin-share = {
enable = true;
};
clan.core.state.pingvin-share.folders = [ config.services.pingvin-share.dataDir ];
};
};
}

View File

@@ -0,0 +1,19 @@
{ lib, ... }:
let
module = lib.modules.importApply ./default.nix { };
in
{
clan.modules = {
pingvin = module;
};
perSystem =
{ ... }:
{
clan.nixosTests.pingvin = {
imports = [ ./tests/vm/default.nix ];
clan.modules."@clan/pingvin" = module;
};
};
}

View File

@@ -0,0 +1,42 @@
{
...
}:
{
name = "service-pingvin";
clan = {
directory = ./.;
inventory = {
machines.server = { };
instances = {
pingvin-test = {
module.name = "@clan/pingvin";
module.input = "self";
roles.default.machines."server".settings = { };
};
};
};
};
nodes = {
server = {
services.pingvin-share = {
hostname = "share.localhost";
frontend.port = 3000;
backend.port = 8000;
};
};
};
testScript = ''
start_all()
server.wait_for_unit("pingvin-share-frontend")
server.succeed("systemctl status pingvin-share-frontend")
server.wait_for_open_port(3000)
server.wait_for_open_port(8000)
server.succeed("curl -H \"Host: share.localhost\" http://127.0.0.1:3000 ")
'';
}

View File

@@ -1,4 +1,4 @@
{ lib, ... }:
{ ... }:
{
_class = "clan.service";
manifest.name = "stirling-pdf";
@@ -6,43 +6,18 @@
manifest.categories = [ "System" ];
roles.default = {
interface.options = {
domain = lib.mkOption {
type = lib.types.str;
default = "pdf";
description = "Sub domain or Stirling PDF service";
};
};
perInstance =
perInstance.nixosModule =
{
settings,
lib,
...
}:
{
nixosModule =
{
config,
...
}:
let
domain = "${settings.domain}.${config.networking.fqdn}";
in
{
services.stirling-pdf = {
enable = true;
environment = {
SERVER_PORT = 8080;
};
};
services.nginx.virtualHosts."${domain}" = {
forceSSL = true;
useACMEHost = "${config.networking.fqdn}";
locations."/" = {
proxyPass = "http://localhost:${builtins.toString config.services.stirling-pdf.environment.SERVER_PORT}";
};
};
services.stirling-pdf = {
enable = lib.mkDefault true;
environment = {
SERVER_PORT = lib.mkDefault 8080;
};
};
};
};
}

View File

@@ -0,0 +1,19 @@
{ lib, ... }:
let
module = lib.modules.importApply ./default.nix { };
in
{
clan.modules = {
stirling-pdf = module;
};
perSystem =
{ ... }:
{
clan.nixosTests.stirling-pdf = {
imports = [ ./tests/vm/default.nix ];
clan.modules."@clan/stirling-pdf" = module;
};
};
}

View File

@@ -0,0 +1,34 @@
{
...
}:
{
name = "service-stirling-pdf";
clan = {
directory = ./.;
inventory = {
machines.server = { };
instances = {
stirling-pdf-test = {
module.name = "@clan/stirling-pdf";
module.input = "self";
roles.default.machines."server".settings = { };
};
};
};
};
nodes = {
server = { };
};
testScript = ''
start_all()
server.wait_for_unit("stirling-pdf")
server.succeed("systemctl status stirling-pdf")
'';
}

View File

@@ -1,47 +0,0 @@
{
_class = "clan.service";
manifest.name = "Victoria Metrics";
manifest.description = "VictoriaMetrics: fast, cost-effective monitoring solution and time series database";
manifest.categories = [ "System" ];
roles.default = {
perInstance = {
nixosModule =
{
config,
pkgs,
...
}:
let
defaultUser = "victoriametrics";
in
{
clan.core.vars.generators.victoria-metrics = {
files = {
username = {
secret = false;
};
password = {
secret = true;
owner = defaultUser;
group = defaultUser;
};
};
script = ''
echo "admin" > "$out"/username
xkcdpass --numwords 4 --delimiter - --count 1 | tr -d "\n" > "$out"/password
'';
runtimeInputs = [ pkgs.xkcdpass ];
};
services.victoriametrics = {
enable = true;
extraOptions = [
"-httpAuth.username=file://${config.clan.core.vars.generators.victoria-metrics.files.username.path}"
"-httpAuth.password=file://${config.clan.core.vars.generators.victoria-metrics.files.password.path}"
];
};
};
};
};
}

View File

@@ -0,0 +1,25 @@
{ ... }:
{
_class = "clan.service";
manifest.name = "Victoria Metrics";
manifest.description = "VictoriaMetrics: fast, cost-effective monitoring solution and time series database";
manifest.categories = [ "System" ];
roles.default = {
perInstance.nixosModule =
{
config,
lib,
...
}:
{
services.victoriametrics = {
enable = lib.mkDefault true;
};
clan.core.state.victoriametrics.folders = lib.mkDefault [
"/var/lib/${config.services.victoriametrics.stateDir}"
];
};
};
}

View File

@@ -0,0 +1,19 @@
{ lib, ... }:
let
module = lib.modules.importApply ./default.nix { };
in
{
clan.modules = {
victoriametrics = module;
};
perSystem =
{ ... }:
{
clan.nixosTests.victoriametrics = {
imports = [ ./tests/vm/default.nix ];
clan.modules."@clan/victoriametrics" = module;
};
};
}

View File

@@ -0,0 +1,34 @@
{
...
}:
{
name = "service-victoriametrics";
clan = {
directory = ./.;
inventory = {
machines.server = { };
instances = {
victoriametrics-test = {
module.name = "@clan/victoriametrics";
module.input = "self";
roles.default.machines."server".settings = { };
};
};
};
};
nodes = {
server = { };
};
testScript = ''
start_all()
server.wait_for_unit("victoriametrics")
server.succeed("systemctl status victoriametrics")
'';
}

View File

@@ -9,9 +9,19 @@
perInstance.nixosModule =
{
lib,
config,
...
}:
{
clan.core.state.vikunja.folders = [
config.services.vikunja.settings.files.basepath
]
++ (
if config.services.vikunja.settings.database.type == "sqlite" then
[ config.services.vikunja.settings.database.path ]
else
[ ]
);
services.vikunja = {
enable = lib.mkDefault true;
frontendScheme = lib.mkDefault "http";

View File

@@ -0,0 +1 @@
budget

View File

@@ -0,0 +1 @@
../../../../../../sops/machines/b4l

View File

@@ -0,0 +1,19 @@
{
"data": "ENC[AES256_GCM,data:9v56r2ZaEixMv61TGiCOmeAru2v9ZDUJe6v+Y5TdzfV5Rg==,iv:8kvq06/hfad+9af2PW+50l6Pzs99E5E2x8m3AIz5y90=,tag:aemnUje/OlGc6Hdzzkfdmg==,type:str]",
"sops": {
"age": [
{
"recipient": "age1hlzrpqqgndcthq5m5yj9egfgyet2fzrxwa6ynjzwx2r22uy6m3hqr3rd06",
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBJZUFaNW9GNXZSMnVjTG5v\nKzJlVWxzMnRSbC93a3BHc0t1YVlhQmRGOEZFCkFFK2NQNXJqdWd6cjFxaFRRR2Vy\nZE5tdkcwRXV6ZzVrdGdkcndCQ01KM3MKLS0tIEtDOG5qOG9MWWN4RnZuVGF5ajJN\nMjk0TkJvR3duZHhGTjQ2WVpqRmkrOWsKjPbLas4eDUXdhZyE29AXklDDM+czo2b7\nqvOAY2c+TyMatGpMRMPogUqGC9mj5jTZe+ZfHcxIfytDXbOgldRPow==\n-----END AGE ENCRYPTED FILE-----\n"
},
{
"recipient": "age1sg0rvgyetdcqw7j2x983fh69kdkvqsngpe5x36e5920qa7fze3cqhj4wgx",
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBtZ3NrbEEyMUpoQTRFL2ZT\nMXNrUTZsSWV3aWRMdGZUNXV2azAwOUJ3cFFRClNmMCtVTXF0VU9PM0NxTWtWSXBh\nMDVlc3BpS3ZVSUlEQit4c21IZy85QW8KLS0tIEMvWWhYM3VyTWk0TnRJbHhublpa\nZEhKSitydFdMbmVWZ01mdlVtSWV6S2sKY7L+wbtpIlo00xQukuj1Fv4iKpC3BftP\n4+55dUhp9cc7VxqV/3TkfPxeyr95OltVZOHhhwSnEzcyCP9XQ16DIw==\n-----END AGE ENCRYPTED FILE-----\n"
}
],
"lastmodified": "2025-08-01T09:25:47Z",
"mac": "ENC[AES256_GCM,data:nEaCXu003Y/kwtNrBT+reXOZfTOjhqxUXLvUFa4RFrFREgxIsNkqi80GyDFAaBbgAFA5B71Ozwh8Ml0g3TJ15DsoLkaUgrLR9gXIuh4FoDpFKmvFzUT7nm4Ac003b2bkaMPVNXRU24O+JVgK9U5tmKfqmEkRnlY5MTLFO5EGgnY=,iv:3RpMM6CjtWJSqY8T++2GIV4b3kN724h/ZhuS1U8lJGY=,tag:tkL5+aU06xF4LUeMoq6qoQ==,type:str]",
"unencrypted_suffix": "_unencrypted",
"version": "3.10.2"
}
}

View File

@@ -0,0 +1 @@
../../../../../../sops/users/kurogeek

View File

@@ -0,0 +1 @@
grafana

View File

@@ -0,0 +1 @@
../../../../../../sops/machines/b4l

View File

@@ -0,0 +1,19 @@
{
"data": "ENC[AES256_GCM,data:NsbmiB/AWbAHRotImbG89mQjINxWyCYx5QJExqv9eVpnUg==,iv:VKGzSmYZkKQzG/Fvs3Lk6KBexqKzoVOCk33Lw0ovUjY=,tag:4kWuchFThyRuqIA/tpEL2A==,type:str]",
"sops": {
"age": [
{
"recipient": "age1hlzrpqqgndcthq5m5yj9egfgyet2fzrxwa6ynjzwx2r22uy6m3hqr3rd06",
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSAxS3F6cmZQN0V0bXpSbnhJ\nQUVwa2U5cGVVLytJWjdKWnErN0tNNjFhaEJvCjRZMFFSNEdFMlY5Q2J2R0pURUt2\nMkpuWUNrT01waFVGSnhxeEF2VGhPT1kKLS0tIGNpdU4weCtza25kWExHVHJlTThw\ncXBEK2Z6RWs1ZVdjbjdPK051Yk5JVEEKrWBxciIubjp2CfLdSMuSoRaWoFEzh2Ni\nQgsFK4B/1k1nAt7hT6ihRHdaZLRGR3oZljD6obQuZt/CQX4XK/vhpA==\n-----END AGE ENCRYPTED FILE-----\n"
},
{
"recipient": "age1sg0rvgyetdcqw7j2x983fh69kdkvqsngpe5x36e5920qa7fze3cqhj4wgx",
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBmMzN5cTlrdlZhaTNxaUQ4\neHhCQWR5QVBKMEVnclFtQ2dUYzZKTitJWHdJCkFOTXVldjRJSVhmb29MY0RHcEk4\ncGtYMHZUcUIzcE0zVlp6cE0rNUlYMVUKLS0tIFhuckdZb2tFcFNIcm9tQjVyckJm\nZFVleEp4cG1GMUdOT2lhcTNKanZGR0EKwAHiw87p1/k+cOlC7TdM5ba7IrQ5nGSQ\nAWPSFjc3sX86aAQzkY/SBeQulj1tC3i4ryg09xUFg+oSPDXexpGp8g==\n-----END AGE ENCRYPTED FILE-----\n"
}
],
"lastmodified": "2025-08-06T05:23:42Z",
"mac": "ENC[AES256_GCM,data:eK8RPnR3M4KUGFBtJ43UGq0F4hw+CL1NwoCJbzpX8W8i7pPJOXkIEi0Q4bi3ALMbUxHd5mYE5lKZj0VpPaV3f3t3AvcIg2zWamBYps5R108vwmIDd2UFtmCA496sOSJgpTNX13V8X5cK+3uYXYnd4fz9qAupvFpIpkqWqGl4kxU=,iv:/KOE9y1bzpCzI1jmXZ6mfh0jhVhOvpgS7GNIp2QxvhQ=,tag:e5gLfU+9SyxunVeuOVirhw==,type:str]",
"unencrypted_suffix": "_unencrypted",
"version": "3.10.2"
}
}

View File

@@ -0,0 +1 @@
../../../../../../sops/users/kurogeek

View File

@@ -0,0 +1 @@
paperless

View File

@@ -0,0 +1 @@
share

View File

@@ -0,0 +1 @@
pdf

View File

@@ -0,0 +1 @@
../../../../../../sops/machines/b4l

View File

@@ -0,0 +1,19 @@
{
"data": "ENC[AES256_GCM,data:YpPv9DuLRdwX2CrLIU0Zr14KcrfaK2MW6N7VYBpIvw==,iv:DS2qhq/BMAVXqaGqYDH1cK3mv2nSWHbN6O+KCe/jXBk=,tag:mRvbZv/qSsAWVKmdqxrzpQ==,type:str]",
"sops": {
"age": [
{
"recipient": "age1hlzrpqqgndcthq5m5yj9egfgyet2fzrxwa6ynjzwx2r22uy6m3hqr3rd06",
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBDeHFRMXFwd3JMakozY3po\nWUo1eDZRMmVkWGVPemZURk5tUUpKay9tc0ZRCjN6UWZ3OVBIQlRReFJUelEwN25y\nZlNqWGVJZjZtaUFKT3lLOW9CcElOMjQKLS0tIEVUSE16aWhYZHdSemViY3AvRWlN\nMnQ5Yk1rODZLOUpaZWovV0RPTEt5UHMKg9GsMtLAfX5y1yWULgdbj8GrXyYhMIMr\n+G4sLcp+HJjsIo0DFvlp0TJUeRuOTVi5XXw+IsFhFTsSqjV/YFFzjw==\n-----END AGE ENCRYPTED FILE-----\n"
},
{
"recipient": "age1sg0rvgyetdcqw7j2x983fh69kdkvqsngpe5x36e5920qa7fze3cqhj4wgx",
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBBamVSSDNuczB3UTJ1Vmoy\nbnM1Q0VDVlQwYU9NQ29vL3FCbjFsSitLWmxBCld6MlAvV3JNZjlsRjVqaUpzZExp\nUWtRS1o5VDQ2RXl1bHNPWmVLTEVGT0EKLS0tIHhkdmdiNUxBTkNPNldLNnZZOUdl\nTWtyaGFsa0NnMy9lQm5mR3FEMXN0TVkKgWedpfvq46qOOdgeFH76OkO7QQyVor/w\n30Rv1n9cqfNdqBog/gPvI/sTPqFfXPpnFJjYZLNG/rnJjPHAM0+hhA==\n-----END AGE ENCRYPTED FILE-----\n"
}
],
"lastmodified": "2025-07-31T08:48:18Z",
"mac": "ENC[AES256_GCM,data:gXIh/MEkCPoL1tfGYIVQs6e335glFCz1AW0EAdVRX8VVxUk9vwNgf577Sd5fHDBuQsYrqMonRPwRYEACLtjaK37+mk1qa+A2gpg4OfhUJF1inrWXZoTY9SSH2LtlAWddcxDDAKA7n0Itqv0FkQuqVmmr3j3XzMf9fTMgAcgscDA=,iv:RZPNYp/6otR67smbNE+fcQqzO61+NEjp1sIHRTUpTl0=,tag:2Jx1M/Y+ODYRaOtps3KY2w==,type:str]",
"unencrypted_suffix": "_unencrypted",
"version": "3.10.2"
}
}

View File

@@ -0,0 +1 @@
../../../../../../sops/users/kurogeek

View File

@@ -0,0 +1 @@
admin

View File

@@ -0,0 +1 @@
metrics