This commit is contained in:
soraefir
2026-06-04 00:30:29 +02:00
parent b82393272c
commit 9a89479f66
26 changed files with 1385 additions and 1380 deletions

View File

@@ -16,8 +16,12 @@ let
// (if serverCfg.containers?nextcloud then { NEXTCLOUD_DOMAIN = "${serverCfg.containers.nextcloud.subdomain}.${serverCfg.domain}";} else {}); // (if serverCfg.containers?nextcloud then { NEXTCLOUD_DOMAIN = "${serverCfg.containers.nextcloud.subdomain}.${serverCfg.domain}";} else {});
}; };
in { in {
sops = true; requires = {
db = true; secrets = [ name ];
databases = [ name ];
};
runtime = {
paths = [{ paths = [{
path="${serverCfg.path.config}/authentik"; path="${serverCfg.path.config}/authentik";
owner = "1000:1000"; owner = "1000:1000";
@@ -111,4 +115,5 @@ in {
echo "Completed Authentik Setup" echo "Completed Authentik Setup"
''; '';
}; };
};
} }

View File

@@ -3,10 +3,7 @@ let
version = "latest"; version = "latest";
serverCfg = config.syscfg.server; serverCfg = config.syscfg.server;
in { in {
sops = false; runtime = {
db = false;
containers = { containers = {
server = builder.mkContainer { server = builder.mkContainer {
subdomain = containerCfg.subdomain; subdomain = containerCfg.subdomain;
@@ -36,6 +33,7 @@ in {
}; };
}; };
}; };
};
# curl 'https://books.test.helcel.net/admin/ajaxconfig' \ # curl 'https://books.test.helcel.net/admin/ajaxconfig' \
# -X POST # -X POST

View File

@@ -3,7 +3,9 @@ let
version = "latest"; version = "latest";
serverCfg = config.syscfg.server; serverCfg = config.syscfg.server;
in { in {
sops = true; requires.secrets = [ name ];
runtime = {
containers = { containers = {
server = builder.mkContainer { server = builder.mkContainer {
subdomain = containerCfg.subdomain; subdomain = containerCfg.subdomain;
@@ -31,4 +33,5 @@ in {
}; };
}; };
}; };
};
} }

View File

@@ -13,7 +13,9 @@ let
}; };
}; };
in { in {
sops = true; requires.secrets = [ name ];
runtime = {
paths = [{ paths = [{
path="${serverCfg.path.data}/ethercalc/"; path="${serverCfg.path.data}/ethercalc/";
mode = "0666"; mode = "0666";
@@ -36,4 +38,5 @@ in {
}; };
}; };
}; };
};
} }

View File

@@ -76,8 +76,12 @@ let
}; };
}; };
in { in {
sops = true; requires = {
db = true; secrets = [ name ];
databases = [ name ];
};
runtime = {
paths = [{ paths = [{
path="${serverCfg.path.config}/etherpad/"; path="${serverCfg.path.config}/etherpad/";
mode = "0444"; mode = "0444";
@@ -121,4 +125,5 @@ in {
chmod 444 ${serverCfg.path.config}/etherpad/APIKEY.txt chmod 444 ${serverCfg.path.config}/etherpad/APIKEY.txt
''; '';
}; };
};
} }

View File

@@ -3,8 +3,12 @@ let
version = "latest"; version = "latest";
serverCfg = config.syscfg.server; serverCfg = config.syscfg.server;
in { in {
sops = true; requires = {
db = true; secrets = [ name ];
databases = [ name ];
};
runtime = {
paths = [ paths = [
{ {
path = "${serverCfg.path.config}/freshrss"; path = "${serverCfg.path.config}/freshrss";
@@ -53,4 +57,5 @@ in {
''; '';
}; };
};
} }

View File

@@ -27,9 +27,9 @@ let
}; };
}; };
in { in {
sops = true; # Enabled to safeguard sensitive camera RTSP stream credentials requires.secrets = [ name ];
db = false; # Internal SQLite is used by default in Frigate
runtime = {
paths = [ paths = [
{ {
path = "${serverCfg.path.config}/frigate/"; path = "${serverCfg.path.config}/frigate/";
@@ -92,4 +92,5 @@ EOF
fi fi
''; '';
}; };
};
} }

View File

@@ -5,8 +5,12 @@ let
LDAP_DC_DOMAIN = "dc=ldap," + (lib.concatMapStringsSep "," (x: "dc=${x}") (lib.splitString "." serverCfg.domain)); LDAP_DC_DOMAIN = "dc=ldap," + (lib.concatMapStringsSep "," (x: "dc=${x}") (lib.splitString "." serverCfg.domain));
in { in {
sops = true; requires = {
db = true; secrets = [ name ];
databases = [ name ];
};
runtime = {
paths = [{ paths = [{
path="${serverCfg.path.data}/gitea"; path="${serverCfg.path.data}/gitea";
owner = "1000:1000"; owner = "1000:1000";
@@ -138,4 +142,5 @@ in {
echo "Completed Gitea Setup" echo "Completed Gitea Setup"
''; '';
}; };
};
} }

View File

@@ -2,12 +2,8 @@
let let
serverCfg = config.syscfg.server; serverCfg = config.syscfg.server;
version = "latest"; version = "latest";
routerName = if containerCfg.subpath != null
then "${containerCfg.subdomain}-${lib.strings.sanitizeDerivationName containerCfg.subpath}"
else containerCfg.subdomain;
in { in {
runtime = {
paths = [{ paths = [{
path = "${serverCfg.path.config}/handbrake"; path = "${serverCfg.path.config}/handbrake";
mode = "0755"; mode = "0755";
@@ -15,6 +11,8 @@ in {
containers = { containers = {
server = builder.mkContainer { server = builder.mkContainer {
authentik = true;
tmpfs = true;
subdomain = containerCfg.subdomain; subdomain = containerCfg.subdomain;
subpath = containerCfg.subpath; subpath = containerCfg.subpath;
image = "ghcr.io/jlesage/handbrake:${version}"; image = "ghcr.io/jlesage/handbrake:${version}";
@@ -27,12 +25,6 @@ in {
AUTOMATED_CONVERSION_FORMAT = "mkv"; AUTOMATED_CONVERSION_FORMAT = "mkv";
AUTOMATED_CONVERSION_OUTPUT_SUBDIR = "SAME_AS_SRC"; AUTOMATED_CONVERSION_OUTPUT_SUBDIR = "SAME_AS_SRC";
}; };
extraLabels = { } // (if serverCfg.containers ? authentik then {
"traefik.http.routers.${routerName}.middlewares" = "authentik";
} else {});
extraOptions = [
"--tmpfs=/tmp:rw,noexec,nosuid,size=512m"
];
overrides = { overrides = {
volumes = [ volumes = [
@@ -52,5 +44,5 @@ in {
''; '';
}; };
};
} }

View File

@@ -4,9 +4,10 @@ let
serverCfg = config.syscfg.server; serverCfg = config.syscfg.server;
in { in {
runtime = {
vm = { vm = {
portForward = [ 8123 ]; portForward = [ 8123 ];
cfg = {cfg,...}:{ cfg = {cfg,...}: {
services.home-assistant = { services.home-assistant = {
enable = true; enable = true;
openFirewall = true; openFirewall = true;
@@ -97,5 +98,5 @@ in {
fi fi
''; '';
}; };
};
} }

View File

@@ -258,9 +258,7 @@ let
];}#)];} ];}#)];}
]; ];
in { in {
sops = false; runtime = {
db = false;
containers = { containers = {
server = builder.mkContainer { server = builder.mkContainer {
subdomain = containerCfg.subdomain; subdomain = containerCfg.subdomain;
@@ -284,5 +282,5 @@ in {
}; };
}; };
}; };
};
} }

View File

@@ -4,9 +4,12 @@ let
serverCfg = config.syscfg.server; serverCfg = config.syscfg.server;
in { in {
sops = true; requires = {
db = true; secrets = [ name ];
databases = [ name ];
};
runtime = {
paths = [{ paths = [{
path = "${serverCfg.path.config}/immich"; path = "${serverCfg.path.config}/immich";
dirs = ["cache"]; dirs = ["cache"];
@@ -97,4 +100,5 @@ in {
''; '';
}; };
};
} }

View File

@@ -5,9 +5,12 @@ let
in { in {
sops = true; requires = {
db = true; secrets = [ name ];
databases = [ name ];
};
runtime = {
paths = [{ paths = [{
path = "${serverCfg.path.config}/influxdb/"; path = "${serverCfg.path.config}/influxdb/";
owner = "1500:1500"; owner = "1500:1500";
@@ -37,6 +40,7 @@ in {
# }; # };
server = builder.mkContainer { server = builder.mkContainer {
tmpfs = true;
subdomain = containerCfg.subdomain; subdomain = containerCfg.subdomain;
image = "influxdata/influxdb3-ui:${version}"; image = "influxdata/influxdb3-ui:${version}";
port = 8080; port = 8080;
@@ -45,9 +49,6 @@ in {
SESSION_SECRET_KEY = "7b0024c13ae770000f797c201e2f210b9932a689c04d34de04379faa44e88e97"; SESSION_SECRET_KEY = "7b0024c13ae770000f797c201e2f210b9932a689c04d34de04379faa44e88e97";
DATABASE_URL = "/db/sqlite.db"; DATABASE_URL = "/db/sqlite.db";
}; };
extraOptions = [
"--tmpfs=/tmp:rw,noexec,nosuid,size=512m"
];
overrides = { overrides = {
ports = [ "8080:8080" ]; ports = [ "8080:8080" ];
cmd = [ "--mode=admin" ]; cmd = [ "--mode=admin" ];
@@ -73,5 +74,5 @@ EOF
chmod -R 755 ${serverCfg.path.config}/influxdb chmod -R 755 ${serverCfg.path.config}/influxdb
''; '';
}; };
};
} }

View File

@@ -24,8 +24,12 @@ let
}; };
in { in {
sops = true; requires = {
db = true; secrets = [ name ];
databases = [ name ];
};
runtime = {
paths = [{ paths = [{
path="${serverCfg.path.config}/invidious"; path="${serverCfg.path.config}/invidious";
mode = "0755"; mode = "0755";
@@ -75,4 +79,5 @@ in {
${pkgs.gettext}/bin/envsubst < "${../data/invidious/config.yml}" > "${serverCfg.path.config}/invidious/config.yml" ${pkgs.gettext}/bin/envsubst < "${../data/invidious/config.yml}" > "${serverCfg.path.config}/invidious/config.yml"
''; '';
}; };
};
} }

View File

@@ -25,6 +25,7 @@ let
}; };
}; };
in { in {
runtime = {
paths = [ paths = [
{ {
path = "${serverCfg.path.config}/jellyfin/"; path = "${serverCfg.path.config}/jellyfin/";
@@ -35,6 +36,7 @@ in {
containers = { containers = {
server = builder.mkContainer { server = builder.mkContainer {
tmpfs = true;
subdomain = containerCfg.subdomain; subdomain = containerCfg.subdomain;
imageStream = image; imageStream = image;
port = 8096; port = 8096;
@@ -44,9 +46,6 @@ in {
JELLYFIN_HttpListenerHost__BindAddress= "0.0.0.0"; #we can use settings.xml override JELLYFIN_HttpListenerHost__BindAddress= "0.0.0.0"; #we can use settings.xml override
JELLYFIN_ServerName = if containerCfg.extra?name then containerCfg.extra.name else "Flix"; JELLYFIN_ServerName = if containerCfg.extra?name then containerCfg.extra.name else "Flix";
}; };
extraOptions = [
"--tmpfs=/tmp:rw,noexec,nosuid,size=512m"
];
overrides = { overrides = {
cmd = [ cmd = [
"--datadir" "/config/data" "--datadir" "/config/data"
@@ -172,5 +171,5 @@ EOF
''; '';
}; };
};
} }

View File

@@ -3,8 +3,12 @@ let
version = "31"; version = "31";
serverCfg = config.syscfg.server; serverCfg = config.syscfg.server;
in { in {
sops = true; requires = {
db = true; secrets = [ name ];
databases = [ name ];
};
runtime = {
paths = [{ paths = [{
path="${serverCfg.path.config}/nextcloud"; path="${serverCfg.path.config}/nextcloud";
owner = "33:33"; owner = "33:33";
@@ -13,6 +17,7 @@ in {
containers = { containers = {
server = builder.mkContainer { server = builder.mkContainer {
tmpfs = true;
subdomain = containerCfg.subdomain; subdomain = containerCfg.subdomain;
image = "nextcloud:${version}"; image = "nextcloud:${version}";
port = 80; port = 80;
@@ -40,9 +45,6 @@ in {
"traefik.http.middlewares.sts_headers.headers.stsSeconds" = "15552000"; "traefik.http.middlewares.sts_headers.headers.stsSeconds" = "15552000";
"traefik.http.middlewares.sts_headers.headers.stsIncludeSubdomains" = "true"; "traefik.http.middlewares.sts_headers.headers.stsIncludeSubdomains" = "true";
}; };
extraOptions = [
"--tmpfs=/tmp:rw,noexec,nosuid,size=512m"
];
overrides = { overrides = {
ports = if containerCfg.port!=null then [ "${toString containerCfg.port}:80" ] else []; ports = if containerCfg.port!=null then [ "${toString containerCfg.port}:80" ] else [];
volumes = [ volumes = [
@@ -193,4 +195,5 @@ in {
}; };
cron = [ "*/5 * * * * root ${pkgs.podman}/bin/podman --events-backend=none exec -u www-data nextcloud-server php -f /var/www/html/cron.php" ]; cron = [ "*/5 * * * * root ${pkgs.podman}/bin/podman --events-backend=none exec -u www-data nextcloud-server php -f /var/www/html/cron.php" ];
};
} }

View File

@@ -4,8 +4,7 @@ let
version = "5.1.4"; version = "5.1.4";
in { in {
sops = false; runtime = {
db = false;
paths = [ paths = [
{ path="${serverCfg.path.config}/openhab/conf"; owner="1000:1000"; mode = "0755"; } { path="${serverCfg.path.config}/openhab/conf"; owner="1000:1000"; mode = "0755"; }
{ path="${serverCfg.path.config}/openhab/userdata"; owner="1000:1000"; mode = "0755"; } { path="${serverCfg.path.config}/openhab/userdata"; owner="1000:1000"; mode = "0755"; }
@@ -74,4 +73,5 @@ in {
#Extra: AndroidTV/Jellyfin (Bind with lights + more) #Extra: AndroidTV/Jellyfin (Bind with lights + more)
''; '';
}; };
};
} }

View File

@@ -59,8 +59,9 @@ let
}; };
}); });
in { in {
sops = true; requires.secrets = [ name ];
runtime = {
containers = { containers = {
server = builder.mkContainer { server = builder.mkContainer {
subdomain = containerCfg.subdomain; subdomain = containerCfg.subdomain;
@@ -82,4 +83,5 @@ in {
}; };
}; };
}; };
};
} }

View File

@@ -2,11 +2,8 @@
let let
version = "latest"; version = "latest";
serverCfg = config.syscfg.server; serverCfg = config.syscfg.server;
routerName = if containerCfg.subpath != null
then "${containerCfg.subdomain}-${lib.strings.sanitizeDerivationName containerCfg.subpath}"
else containerCfg.subdomain;
in { in {
runtime = {
paths = [{ paths = [{
path = "${serverCfg.path.config}/selfmark/"; path = "${serverCfg.path.config}/selfmark/";
mode = "0444"; mode = "0444";
@@ -14,6 +11,7 @@ in {
containers = { containers = {
server = builder.mkContainer { server = builder.mkContainer {
authentik = true;
subdomain = containerCfg.subdomain; subdomain = containerCfg.subdomain;
subpath = containerCfg.subpath; subpath = containerCfg.subpath;
image = "ghcr.io/calibrain/shelfmark:${version}"; image = "ghcr.io/calibrain/shelfmark:${version}";
@@ -79,11 +77,6 @@ in {
EXT_BYPASSER_PATH = "/v1"; EXT_BYPASSER_PATH = "/v1";
EXT_BYPASSER_TIMEOUT = "60000"; EXT_BYPASSER_TIMEOUT = "60000";
}; };
extraLabels = {
} // (if serverCfg.containers ? authentik then {
"traefik.http.routers.${routerName}.middlewares" = "authentik";
} else {});
overrides = { overrides = {
volumes = [ volumes = [
"${serverCfg.path.dlComplete}:/books:rw" "${serverCfg.path.dlComplete}:/books:rw"
@@ -93,5 +86,5 @@ in {
}; };
}; };
}; };
};
} }

View File

@@ -30,9 +30,10 @@ let
in in
assert containerCfg.subpath == null || throw "Error: Servarr does not support subpath."; assert containerCfg.subpath == null || throw "Error: Servarr does not support subpath.";
{ {
sops = true; requires.secrets = [ name ];
# db = [ "prowlarr" "sonarr" "radarr" ]; -> one db for each # db = [ "prowlarr" "sonarr" "radarr" ]; -> one db for each
runtime = {
paths = [ paths = [
{ path = "${serverCfg.dataPath}/media/"; mode = "0755"; } { path = "${serverCfg.dataPath}/media/"; mode = "0755"; }
{ path = "${serverCfg.configPath}/servarr/prowlarr"; mode = "0755"; } { path = "${serverCfg.configPath}/servarr/prowlarr"; mode = "0755"; }
@@ -44,6 +45,8 @@ in
containers = { containers = {
}// lib.optionalAttrs (builtins.elem "prowlarr" (containerCfg.extra.modules or defaultModules)) { }// lib.optionalAttrs (builtins.elem "prowlarr" (containerCfg.extra.modules or defaultModules)) {
prowlarr = builder.mkContainer { prowlarr = builder.mkContainer {
authentik = true;
tmpfs = true;
subdomain = containerCfg.subdomain; subdomain = containerCfg.subdomain;
subpath = "prowlarr"; subpath = "prowlarr";
imageStream = images.prowlarr; imageStream = images.prowlarr;
@@ -58,17 +61,15 @@ in
}; };
extraOptions = [ extraOptions = [
"--user=0:0" "--user=0:0"
"--tmpfs=/tmp:rw,noexec,nosuid,size=512m"
"--passwd-entry=root:x:0:0:root:/root:/bin/sh" "--passwd-entry=root:x:0:0:root:/root:/bin/sh"
]; ];
extraLabels = { } // (if serverCfg.containers ? authentik then {
"traefik.http.routers.${containerCfg.subdomain}-prowlarr.middlewares" = "authentik";
} else {});
overrides.volumes = sharedVolumes ++ [ "${serverCfg.configPath}/servarr/prowlarr:/config" ]; overrides.volumes = sharedVolumes ++ [ "${serverCfg.configPath}/servarr/prowlarr:/config" ];
}; };
}// lib.optionalAttrs (builtins.elem "radarr" (containerCfg.extra.modules or defaultModules)) { }// lib.optionalAttrs (builtins.elem "radarr" (containerCfg.extra.modules or defaultModules)) {
radarr = builder.mkContainer { radarr = builder.mkContainer {
authentik = true;
tmpfs = true;
subdomain = containerCfg.subdomain; subdomain = containerCfg.subdomain;
subpath = "radarr"; subpath = "radarr";
imageStream = images.radarr; imageStream = images.radarr;
@@ -83,17 +84,15 @@ in
}; };
extraOptions = [ extraOptions = [
"--user=0:0" "--user=0:0"
"--tmpfs=/tmp:rw,noexec,nosuid,size=512m"
"--passwd-entry=root:x:0:0:root:/root:/bin/sh" "--passwd-entry=root:x:0:0:root:/root:/bin/sh"
]; ];
extraLabels = { } // (if serverCfg.containers ? authentik then {
"traefik.http.routers.${containerCfg.subdomain}-radarr.middlewares" = "authentik";
} else {});
overrides.volumes = sharedVolumes ++ [ "${serverCfg.configPath}/servarr/radarr:/config" ]; overrides.volumes = sharedVolumes ++ [ "${serverCfg.configPath}/servarr/radarr:/config" ];
}; };
}// lib.optionalAttrs (builtins.elem "sonarr" (containerCfg.extra.modules or defaultModules)) { }// lib.optionalAttrs (builtins.elem "sonarr" (containerCfg.extra.modules or defaultModules)) {
sonarr = builder.mkContainer { sonarr = builder.mkContainer {
authentik = true;
tmpfs = true;
subdomain = containerCfg.subdomain; subdomain = containerCfg.subdomain;
subpath = "sonarr"; subpath = "sonarr";
imageStream = images.sonarr; imageStream = images.sonarr;
@@ -108,17 +107,15 @@ in
}; };
extraOptions = [ extraOptions = [
"--user=0:0" "--user=0:0"
"--tmpfs=/tmp:rw,noexec,nosuid,size=512m"
"--passwd-entry=root:x:0:0:root:/root:/bin/sh" "--passwd-entry=root:x:0:0:root:/root:/bin/sh"
]; ];
extraLabels = { } // (if serverCfg.containers ? authentik then {
"traefik.http.routers.${containerCfg.subdomain}-sonarr.middlewares" = "authentik";
} else {});
overrides.volumes = sharedVolumes ++ [ "${serverCfg.configPath}/servarr/sonarr:/config" ]; overrides.volumes = sharedVolumes ++ [ "${serverCfg.configPath}/servarr/sonarr:/config" ];
}; };
}// lib.optionalAttrs (builtins.elem "lidarr" (containerCfg.extra.modules or defaultModules)) { }// lib.optionalAttrs (builtins.elem "lidarr" (containerCfg.extra.modules or defaultModules)) {
lidarr = builder.mkContainer { lidarr = builder.mkContainer {
authentik = true;
tmpfs = true;
subdomain = containerCfg.subdomain; subdomain = containerCfg.subdomain;
subpath = "lidarr"; subpath = "lidarr";
imageStream = images.lidarr; imageStream = images.lidarr;
@@ -133,12 +130,8 @@ in
}; };
extraOptions = [ extraOptions = [
"--user=0:0" "--user=0:0"
"--tmpfs=/tmp:rw,noexec,nosuid,size=512m"
"--passwd-entry=root:x:0:0:root:/root:/bin/sh" "--passwd-entry=root:x:0:0:root:/root:/bin/sh"
]; ];
extraLabels = { } // (if serverCfg.containers ? authentik then {
"traefik.http.routers.${containerCfg.subdomain}-lidarr.middlewares" = "authentik";
} else {});
overrides.volumes = sharedVolumes ++ [ "${serverCfg.configPath}/servarr/lidarr:/config" ]; overrides.volumes = sharedVolumes ++ [ "${serverCfg.configPath}/servarr/lidarr:/config" ];
}; };
@@ -526,4 +519,5 @@ in
''; '';
}; };
};
} }

View File

@@ -3,10 +3,13 @@ let
version = "stable"; version = "stable";
serverCfg = config.syscfg.server; serverCfg = config.syscfg.server;
in { in {
sops = true; requires = {
db =true; secrets = [ name ];
containers = { databases = [ name ];
};
runtime = {
containers = {
server = builder.mkContainer { server = builder.mkContainer {
subdomain = containerCfg.subdomain; subdomain = containerCfg.subdomain;
image = "ghcr.io/suwayomi/suwayomi-server:${version}"; image = "ghcr.io/suwayomi/suwayomi-server:${version}";
@@ -46,5 +49,5 @@ in {
}; };
}; };
}; };
};
} }

View File

@@ -11,7 +11,9 @@ let
}; };
}; };
in { in {
sops = true; requires.secrets = [ name ];
runtime = {
paths = [{ paths = [{
path="${serverCfg.path.config}/traefik"; path="${serverCfg.path.config}/traefik";
owner = "1000:1000"; owner = "1000:1000";
@@ -83,5 +85,5 @@ in {
}; };
}; };
}; };
};
} }

View File

@@ -13,10 +13,8 @@ let
}; };
}; };
}; };
routerName = if containerCfg.subpath != null
then "${containerCfg.subdomain}-${lib.strings.sanitizeDerivationName containerCfg.subpath}"
else containerCfg.subdomain;
in { in {
runtime = {
paths = [{ paths = [{
path = "${serverCfg.path.config}/transmission"; path = "${serverCfg.path.config}/transmission";
owner = "1000:1000"; owner = "1000:1000";
@@ -25,6 +23,7 @@ in {
containers = { containers = {
server = builder.mkContainer { server = builder.mkContainer {
authentik = true;
subdomain = containerCfg.subdomain; subdomain = containerCfg.subdomain;
subpath = containerCfg.subpath; subpath = containerCfg.subpath;
imageStream = image; imageStream = image;
@@ -36,10 +35,6 @@ in {
WHITELIST = "";# 127.0.0.1,::1,10.*"; WHITELIST = "";# 127.0.0.1,::1,10.*";
# HOST_WHITELIST = "traefik-server,authentik-server,authentik-worker"; # HOST_WHITELIST = "traefik-server,authentik-server,authentik-worker";
}; };
extraLabels = {
} // (if serverCfg.containers ? authentik then {
"traefik.http.routers.${routerName}.middlewares" = "authentik";
} else {});
overrides = { overrides = {
volumes = [ volumes = [
@@ -60,5 +55,5 @@ in {
${pkgs.gettext}/bin/envsubst < "${../data/transmission/settings.json}" > "${serverCfg.path.config}/transmission/config/settings.json" ${pkgs.gettext}/bin/envsubst < "${../data/transmission/settings.json}" > "${serverCfg.path.config}/transmission/config/settings.json"
''; '';
}; };
};
} }

View File

@@ -15,8 +15,12 @@ let
}; };
}; };
in { in {
sops = true; requires = {
db = true; secrets = [ name ];
databases = [ name ];
};
runtime = {
paths = [{ paths = [{
path = "${serverCfg.path.config}/umami/"; path = "${serverCfg.path.config}/umami/";
mode = "0444"; mode = "0444";
@@ -24,6 +28,8 @@ in {
containers = { containers = {
server = builder.mkContainer { server = builder.mkContainer {
authentik = true;
tmpfs = true;
subdomain = containerCfg.subdomain; subdomain = containerCfg.subdomain;
image = "${pkgs.umami.name}:${pkgs.umami.version}"; image = "${pkgs.umami.name}:${pkgs.umami.version}";
imageStream = image; imageStream = image;
@@ -39,16 +45,10 @@ in {
# DISABLE_LOGIN = "1";#(if serverCfg.containers?authentik then "1" else "0"); # DISABLE_LOGIN = "1";#(if serverCfg.containers?authentik then "1" else "0");
}; };
extraLabels = { } // ( if serverCfg.containers?authentik then {
"traefik.http.routers.${containerCfg.subdomain}.middlewares" = if serverCfg.containers?authentik then "authentik" else "";
} else {});
extraOptions = [
"--tmpfs=/tmp:rw,noexec,nosuid,size=512m"
];
overrides = { overrides = {
cmd = [ "start" ]; # Specific command for the umami binary cmd = [ "start" ]; # Specific command for the umami binary
}; };
}; };
}; };
};
} }

View File

@@ -1,16 +1,32 @@
{ config, lib, pkgs, serverCfg }: { config, lib, pkgs, serverCfg }:
let let
mkRouterName = { subdomain, subpath ? null }:
if subpath != null
then "${subdomain}-${lib.strings.sanitizeDerivationName subpath}"
else subdomain;
getOr = attrs: path: default: lib.attrByPath path default attrs;
mkTmpfsOption = size: "--tmpfs=/tmp:rw,noexec,nosuid,size=${size}";
mkAuthentikLabels =
{ subdomain
, subpath ? null
, routerName ? mkRouterName { inherit subdomain subpath; }
, middleware ? "authentik"
}:
lib.optionalAttrs (serverCfg.containers ? authentik) {
"traefik.http.routers.${routerName}.middlewares" = middleware;
};
contBuilder = contBuilder =
{ image ? null, imageStream ? null, imageFile ? null { image ? null, imageStream ? null, imageFile ? null
, secret ? null , secret ? null
, subdomain ? null, subpath?null, port ? null , subdomain ? null, subpath?null, port ? null
, authentik ? false
, tmpfs ? false
, tmpfsSize ? "512m"
, extraEnv ? { }, extraLabels ? { }, extraOptions ? [ ] , extraEnv ? { }, extraLabels ? { }, extraOptions ? [ ]
, overrides ? { } , overrides ? { }
}: }:
let let
routerName = if subpath != null routerName = mkRouterName { inherit subdomain subpath; };
then "${subdomain}-${lib.strings.sanitizeDerivationName subpath}"
else subdomain;
base = { base = {
image = if imageStream != null then "${imageStream.imageName}:${imageStream.imageTag}" image = if imageStream != null then "${imageStream.imageName}:${imageStream.imageTag}"
else if imageFile != null then "${imageFile.imageName}:${imageFile.imageTag}" else image; else if imageFile != null then "${imageFile.imageName}:${imageFile.imageTag}" else image;
@@ -33,11 +49,15 @@ let
"traefik.http.services.${routerName}.loadbalancer.server.port" = toString port; "traefik.http.services.${routerName}.loadbalancer.server.port" = toString port;
}) else { }) else {
"traefik.enable" = "false"; "traefik.enable" = "false";
}) // extraLabels; })
// lib.optionalAttrs authentik (mkAuthentikLabels { inherit subdomain subpath routerName; })
// extraLabels;
extraOptions = [ extraOptions = [
"--add-host=host.containers.internal:host-gateway" "--add-host=host.containers.internal:host-gateway"
] ++ extraOptions; ]
++ lib.optional tmpfs (mkTmpfsOption tmpfsSize)
++ extraOptions;
}; };
in lib.recursiveUpdate base overrides; in lib.recursiveUpdate base overrides;
vmBuilder = { name, vm }: ((import "${pkgs.path}/nixos/lib/eval-config.nix" { vmBuilder = { name, vm }: ((import "${pkgs.path}/nixos/lib/eval-config.nix" {
@@ -70,54 +90,27 @@ in {
mkContainer = contBuilder; mkContainer = contBuilder;
mkVm = vmBuilder; mkVm = vmBuilder;
mkApp = name: app: mkApp = name: app:
let {
# Keep legacy app modules working while storing a stricter internal contract.
legacySetup =
if app ? setup then app.setup else null;
in {
inherit name; inherit name;
requires = { requires = {
secrets = secrets = getOr app [ "requires" "secrets" ] [ ];
if app ? requires && app.requires ? secrets then app.requires.secrets databases = getOr app [ "requires" "databases" ] [ ];
else if app ? sops && app.sops then [ name ]
else [ ];
databases =
if app ? requires && app.requires ? databases then app.requires.databases
else if app ? db && app.db then [ name ]
else [ ];
}; };
exports = { exports = {
authentik = { authentik = {
blueprints = blueprints = getOr app [ "exports" "authentik" "blueprints" ] [ ];
if app ? exports && app.exports ? authentik && app.exports.authentik ? blueprints
then app.exports.authentik.blueprints
else [ ];
}; };
}; };
runtime = { runtime = {
paths = paths = getOr app [ "runtime" "paths" ] [ ];
if app ? runtime && app.runtime ? paths then app.runtime.paths containers = getOr app [ "runtime" "containers" ] { };
else if app ? paths then app.paths vm = getOr app [ "runtime" "vm" ] null;
else [ ]; cron = getOr app [ "runtime" "cron" ] [ ];
containers = setup = {
if app ? runtime && app.runtime ? containers then app.runtime.containers
else if app ? containers then app.containers
else { };
vm =
if app ? runtime && app.runtime ? vm then app.runtime.vm
else if app ? vm then app.vm
else null;
cron =
if app ? runtime && app.runtime ? cron then app.runtime.cron
else if app ? cron then app.cron
else [ ];
setup =
if app ? runtime && app.runtime ? setup then app.runtime.setup
else ({
trigger = ""; trigger = "";
script = null; script = null;
envFile = [ ]; envFile = [ ];
} // (if legacySetup != null then legacySetup else { })); } // getOr app [ "runtime" "setup" ] { };
}; };
}; };
mkData = { name, dir, vars?{} }: pkgs.runCommand name vars '' mkData = { name, dir, vars?{} }: pkgs.runCommand name vars ''

View File

@@ -2,38 +2,25 @@
let let
serverCfg = config.syscfg.server; serverCfg = config.syscfg.server;
builder = import ./builder.nix { inherit config lib pkgs serverCfg; }; builder = import ./builder.nix { inherit config lib pkgs serverCfg; };
loadApp = name: containerCfg:
in{ builder.mkApp name ((import (./apps + "/${name}.nix")) {
config = lib.mkMerge [{ inherit config pkgs lib containerCfg builder name;
syscfg.server.loadedContainers = lib.mapAttrs (name: containerCfg: });
builder.mkApp name ((import (./apps + "/${name}.nix")) { inherit config pkgs lib containerCfg builder name; }) loadedContainers = lib.mapAttrs loadApp serverCfg.containers;
) config.syscfg.server.containers; appsList = builtins.attrValues loadedContainers;
} (lib.mkIf ( serverCfg.containers != {} ) ( concatRuntimeLists = field: lib.concatMap (app: app.runtime.${field}) appsList;
let mkNamedUnits = mkUnit: items: lib.listToAttrs (map mkUnit items);
appsList = builtins.attrValues config.syscfg.server.loadedContainers;
mergedContainers = lib.concatMapAttrs (appName: app: mergedContainers = lib.concatMapAttrs (appName: app:
lib.mapAttrs' (cName: cCfg: lib.nameValuePair "${appName}-${cName}" cCfg) app.runtime.containers lib.mapAttrs' (cName: cCfg: lib.nameValuePair "${appName}-${cName}" cCfg) app.runtime.containers
) config.syscfg.server.loadedContainers; ) loadedContainers;
serverPathConfigs = map (path: { allPathConfigs = map (path: {
inherit path; inherit path;
mode = "0755"; mode = "0755";
}) (lib.unique (builtins.attrValues serverCfg.path)); }) (lib.unique (builtins.attrValues serverCfg.path)) ++ concatRuntimeLists "paths";
allPathConfigs = serverPathConfigs ++ lib.concatMap (app: app.runtime.paths) appsList; allSetupConfigs = map (app: ({ name = app.name; envFile = ""; } // app.runtime.setup)) appsList;
allSetupConfigs = lib.concatMap (app: allCronsConfigs = concatRuntimeLists "cron";
if app.runtime.setup ? script
then [ ({ name = app.name; envFile = ""; } // app.runtime.setup) ]
else [ ]
) appsList;
allCronsConfigs = lib.concatMap (app: app.runtime.cron) appsList;
allVMConfigs = builtins.filter (app: app.runtime.vm != null) appsList; allVMConfigs = builtins.filter (app: app.runtime.vm != null) appsList;
in{ mkPathSetup = cfg:
virtualisation.oci-containers = {
backend = "podman";
containers = mergedContainers;
};
system.activationScripts.container-setup-dirs = {
deps = [ "users" "groups" ];
text = lib.concatStringsSep "\n" (map (cfg:
let let
effectiveCfg = { effectiveCfg = {
owner = "root:root"; owner = "root:root";
@@ -45,8 +32,18 @@ in{
${lib.concatMapStringsSep "\n" (dir: "${pkgs.coreutils}/bin/mkdir -p ${effectiveCfg.path}/${lib.escapeShellArg dir}") effectiveCfg.dirs} ${lib.concatMapStringsSep "\n" (dir: "${pkgs.coreutils}/bin/mkdir -p ${effectiveCfg.path}/${lib.escapeShellArg dir}") effectiveCfg.dirs}
${pkgs.coreutils}/bin/chown ${effectiveCfg.owner} "${effectiveCfg.path}" ${pkgs.coreutils}/bin/chown ${effectiveCfg.owner} "${effectiveCfg.path}"
${pkgs.coreutils}/bin/chmod ${effectiveCfg.mode} "${effectiveCfg.path}" ${pkgs.coreutils}/bin/chmod ${effectiveCfg.mode} "${effectiveCfg.path}"
'';
'') allPathConfigs); in {
config = lib.mkMerge [{
syscfg.server.loadedContainers = loadedContainers;
} (lib.mkIf (loadedContainers != {}) {
virtualisation.oci-containers = {
backend = "podman";
containers = mergedContainers;
};
system.activationScripts.container-setup-dirs = {
deps = [ "users" "groups" ];
text = lib.concatStringsSep "\n" (map mkPathSetup allPathConfigs);
}; };
systemd.services = { systemd.services = {
@@ -60,7 +57,7 @@ in{
startAt = "weekly"; startAt = "weekly";
}; };
} }
// lib.listToAttrs (lib.concatMap (e: [{ // mkNamedUnits (e: {
name = "${e.name}-vm"; name = "${e.name}-vm";
value = { value = {
description = "Isolated NixOS Guest VM for ${e.name}"; description = "Isolated NixOS Guest VM for ${e.name}";
@@ -81,8 +78,8 @@ in{
''; '';
}; };
}; };
}]) allVMConfigs) }) allVMConfigs
// lib.listToAttrs (lib.concatMap (e: [{ // mkNamedUnits (e: {
name = "${e.name}-setup"; name = "${e.name}-setup";
value = { value = {
description = "Run ${e.name} setup"; description = "Run ${e.name} setup";
@@ -98,13 +95,11 @@ in{
User = "root"; User = "root";
}; };
}; };
}]) allSetupConfigs ); }) allSetupConfigs;
services.cron = { services.cron = {
enable = true; enable = true;
systemCronJobs = allCronsConfigs; systemCronJobs = allCronsConfigs;
}; };
})];
}))];
} }