Compare commits
27 Commits
4866426271
...
9a89479f66
| Author | SHA1 | Date | |
|---|---|---|---|
| 9a89479f66 | |||
| b82393272c | |||
| 1cb9e9b645 | |||
| b8735803c4 | |||
| 14bf297897 | |||
| 1fad610dff | |||
| 2c00901b04 | |||
| 2c0ac0db09 | |||
| 6be107374e | |||
| 9e4d8274b5 | |||
| f54dea8a13 | |||
| a6788f13a8 | |||
| 5b4af162b9 | |||
| 4e5c956f78 | |||
| 083549e3c6 | |||
| fada3c79b3 | |||
| ce72e4421b | |||
| ddc5c76a35 | |||
| d0b6718254 | |||
| c1c76ab3de | |||
| 558874731a | |||
| b14135274b | |||
| 5df88ac25a | |||
| 2d8e0da386 | |||
| 8f87c11cb5 | |||
| 7b8eeb917f | |||
| a2043cafe1 |
@@ -38,24 +38,27 @@
|
||||
};
|
||||
|
||||
outputs = inputs:
|
||||
let gen = import ./generator.nix { inherit inputs; };
|
||||
let
|
||||
lib = inputs.nixpkgs.lib;
|
||||
gen = import ./generator.nix { inherit inputs; };
|
||||
systemsDir = ./systems;
|
||||
systemNames = lib.attrNames (lib.filterAttrs
|
||||
(name: type: type == "directory" && builtins.pathExists (systemsDir + "/${name}/cfg.nix"))
|
||||
(builtins.readDir systemsDir));
|
||||
hostsByType = systemType:
|
||||
lib.filter
|
||||
(host: (import (systemsDir + "/${host}/cfg.nix")).syscfg.type == systemType)
|
||||
systemNames;
|
||||
generateHosts = systemType:
|
||||
builtins.listToAttrs (map
|
||||
(host: lib.nameValuePair host (gen.generate { inherit host; }))
|
||||
(hostsByType systemType));
|
||||
in {
|
||||
devShells = import ./shells { inherit inputs; };
|
||||
|
||||
nixosConfigurations = {
|
||||
valinor = gen.generate { host = "valinor"; };
|
||||
iriy = gen.generate { host = "iriy"; };
|
||||
efir = gen.generate { host = "efir"; };
|
||||
avalon = gen.generate { host = "avalon"; };
|
||||
ci = gen.generate { host = "ci"; };
|
||||
sandbox = gen.generate { host = "sandbox"; };
|
||||
gateway = gen.generate { host = "gateway"; };
|
||||
};
|
||||
darwinConfigurations = { asgard = gen.generate { host = "asgard"; }; };
|
||||
homeConfigurations = {
|
||||
yomi = gen.generate { host = "example"; };
|
||||
example = gen.generate { host = "example"; };
|
||||
};
|
||||
nixosConfigurations = generateHosts "nixos";
|
||||
darwinConfigurations = generateHosts "macos";
|
||||
homeConfigurations = generateHosts "home";
|
||||
};
|
||||
|
||||
# ===== Unsupported/NotImplemented ======
|
||||
|
||||
@@ -17,10 +17,14 @@ let
|
||||
};
|
||||
};
|
||||
in {
|
||||
sops = false;
|
||||
db = false;
|
||||
requires = {
|
||||
secrets = [ ];
|
||||
databases = [ ];
|
||||
};
|
||||
|
||||
runtime = {
|
||||
paths = [{
|
||||
path="${serverCfg.configPath}/example/";
|
||||
path="${serverCfg.path.config}/example/";
|
||||
mode = "0444";
|
||||
}];
|
||||
|
||||
@@ -46,4 +50,5 @@ in {
|
||||
...
|
||||
'';
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
@@ -16,15 +16,16 @@ let
|
||||
// (if serverCfg.containers?nextcloud then { NEXTCLOUD_DOMAIN = "${serverCfg.containers.nextcloud.subdomain}.${serverCfg.domain}";} else {});
|
||||
};
|
||||
in {
|
||||
sops = true;
|
||||
db = true;
|
||||
requires = {
|
||||
secrets = [ name ];
|
||||
databases = [ name ];
|
||||
};
|
||||
|
||||
runtime = {
|
||||
paths = [{
|
||||
path="${serverCfg.configPath}/authentik/media";
|
||||
owner = "1000:1000";
|
||||
mode = "0755";
|
||||
}{
|
||||
path="${serverCfg.configPath}/authentik/templates";
|
||||
path="${serverCfg.path.config}/authentik";
|
||||
owner = "1000:1000";
|
||||
dirs = ["media" "templates"];
|
||||
mode = "0755";
|
||||
}];
|
||||
|
||||
@@ -55,8 +56,8 @@ in {
|
||||
|
||||
cmd = [ "server" ];
|
||||
volumes = [
|
||||
"${serverCfg.configPath}/authentik/media:/media"
|
||||
"${serverCfg.configPath}/authentik/templates:/templates"
|
||||
"${serverCfg.path.config}/authentik/media:/media"
|
||||
"${serverCfg.path.config}/authentik/templates:/templates"
|
||||
"${authentikData}:/blueprints/custom:ro"
|
||||
];
|
||||
};
|
||||
@@ -77,8 +78,8 @@ in {
|
||||
overrides = {
|
||||
cmd = [ "worker" ];
|
||||
volumes = [
|
||||
"${serverCfg.configPath}/authentik/media:/media"
|
||||
"${serverCfg.configPath}/authentik/templates:/templates"
|
||||
"${serverCfg.path.config}/authentik/media:/media"
|
||||
"${serverCfg.path.config}/authentik/templates:/templates"
|
||||
"${authentikData}:/blueprints/custom:ro"
|
||||
];
|
||||
};
|
||||
@@ -114,4 +115,5 @@ in {
|
||||
echo "Completed Authentik Setup"
|
||||
'';
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
@@ -3,16 +3,7 @@ let
|
||||
version = "latest";
|
||||
serverCfg = config.syscfg.server;
|
||||
in {
|
||||
sops = false;
|
||||
db = false;
|
||||
paths = [
|
||||
{
|
||||
path = "${serverCfg.configPath}/calibre-web/";
|
||||
mode = "0755";
|
||||
dirs = ["library" "ingest"];
|
||||
}
|
||||
];
|
||||
|
||||
runtime = {
|
||||
containers = {
|
||||
server = builder.mkContainer {
|
||||
subdomain = containerCfg.subdomain;
|
||||
@@ -35,14 +26,14 @@ in {
|
||||
"traefik.http.routers.${containerCfg.subdomain}-login.tls" = "true";
|
||||
};
|
||||
overrides = {
|
||||
cmd = [ ];
|
||||
volumes = [
|
||||
"${serverCfg.configPath}/calibre-web/library/:/calibre-library"
|
||||
"${serverCfg.configPath}/calibre-web/ingest/:/cwa-book-ingest"
|
||||
"${serverCfg.path.book}:/calibre-library"
|
||||
"${serverCfg.path.dlBook}:/cwa-book-ingest"
|
||||
];
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
# curl 'https://books.test.helcel.net/admin/ajaxconfig' \
|
||||
# -X POST
|
||||
|
||||
@@ -3,7 +3,9 @@ let
|
||||
version = "latest";
|
||||
serverCfg = config.syscfg.server;
|
||||
in {
|
||||
sops = true;
|
||||
requires.secrets = [ name ];
|
||||
|
||||
runtime = {
|
||||
containers = {
|
||||
server = builder.mkContainer {
|
||||
subdomain = containerCfg.subdomain;
|
||||
@@ -31,4 +33,5 @@ in {
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
@@ -13,9 +13,11 @@ let
|
||||
};
|
||||
};
|
||||
in {
|
||||
sops = true;
|
||||
requires.secrets = [ name ];
|
||||
|
||||
runtime = {
|
||||
paths = [{
|
||||
path="${serverCfg.dataPath}/ethercalc/";
|
||||
path="${serverCfg.path.data}/ethercalc/";
|
||||
mode = "0666";
|
||||
}];
|
||||
|
||||
@@ -31,9 +33,10 @@ in {
|
||||
};
|
||||
overrides = {
|
||||
volumes = [
|
||||
"${serverCfg.dataPath}/ethercalc:/data"
|
||||
"${serverCfg.path.data}/ethercalc:/data"
|
||||
];
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
@@ -76,10 +76,14 @@ let
|
||||
};
|
||||
};
|
||||
in {
|
||||
sops = true;
|
||||
db = true;
|
||||
requires = {
|
||||
secrets = [ name ];
|
||||
databases = [ name ];
|
||||
};
|
||||
|
||||
runtime = {
|
||||
paths = [{
|
||||
path="${serverCfg.configPath}/etherpad/";
|
||||
path="${serverCfg.path.config}/etherpad/";
|
||||
mode = "0444";
|
||||
}];
|
||||
|
||||
@@ -107,7 +111,7 @@ in {
|
||||
cmd = [ "--settings" "/etc/etherpad/settings.json" "--apikey" "/etc/etherpad/APIKEY.txt" ];
|
||||
volumes = [
|
||||
"${settings}:/etc/etherpad/settings.json"
|
||||
"${serverCfg.configPath}/etherpad/APIKEY.txt:/etc/etherpad/APIKEY.txt:ro"
|
||||
"${serverCfg.path.config}/etherpad/APIKEY.txt:/etc/etherpad/APIKEY.txt:ro"
|
||||
];
|
||||
};
|
||||
};
|
||||
@@ -117,8 +121,9 @@ in {
|
||||
trigger = "server";
|
||||
envFile = config.sops.secrets."ETHERPAD".path;
|
||||
script = pkgs.writeShellScript "setup" ''
|
||||
echo "$APIKEY" > ${serverCfg.configPath}/etherpad/APIKEY.txt
|
||||
chmod 444 ${serverCfg.configPath}/etherpad/APIKEY.txt
|
||||
echo "$APIKEY" > ${serverCfg.path.config}/etherpad/APIKEY.txt
|
||||
chmod 444 ${serverCfg.path.config}/etherpad/APIKEY.txt
|
||||
'';
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
@@ -3,11 +3,15 @@ let
|
||||
version = "latest";
|
||||
serverCfg = config.syscfg.server;
|
||||
in {
|
||||
sops = true;
|
||||
db = true;
|
||||
requires = {
|
||||
secrets = [ name ];
|
||||
databases = [ name ];
|
||||
};
|
||||
|
||||
runtime = {
|
||||
paths = [
|
||||
{
|
||||
path = "${serverCfg.configPath}/freshrss";
|
||||
path = "${serverCfg.path.config}/freshrss";
|
||||
owner = "1000:1000";
|
||||
mode = "0755";
|
||||
}
|
||||
@@ -33,7 +37,7 @@ in {
|
||||
|
||||
overrides = {
|
||||
environmentFiles = [ config.sops.secrets."FRESHRSS".path config.sops.secrets."CUSTOM".path ];
|
||||
volumes = [];
|
||||
volumes = ["${serverCfg.path.config}/freshrss:/var/www/FreshRSS/data"];
|
||||
};
|
||||
};
|
||||
};
|
||||
@@ -53,4 +57,5 @@ in {
|
||||
|
||||
'';
|
||||
};
|
||||
};
|
||||
}
|
||||
@@ -27,12 +27,12 @@ let
|
||||
};
|
||||
};
|
||||
in {
|
||||
sops = true; # Enabled to safeguard sensitive camera RTSP stream credentials
|
||||
db = false; # Internal SQLite is used by default in Frigate
|
||||
requires.secrets = [ name ];
|
||||
|
||||
runtime = {
|
||||
paths = [
|
||||
{
|
||||
path = "${serverCfg.configPath}/frigate/";
|
||||
path = "${serverCfg.path.config}/frigate/";
|
||||
mode = "0755";
|
||||
}
|
||||
{
|
||||
@@ -53,7 +53,7 @@ in {
|
||||
overrides = {
|
||||
cmd = [ ];
|
||||
volumes = [
|
||||
"${serverCfg.configPath}/frigate:/config"
|
||||
"${serverCfg.path.config}/frigate:/config"
|
||||
"/var/lib/frigate/storage:/media/frigate"
|
||||
"/dev/bus/usb:/dev/bus/usb" # Passes Google Coral USB TPU to the container
|
||||
"/dev/dri:/dev/dri" # Passes Intel/AMD GPU for hardware video decoding
|
||||
@@ -66,12 +66,12 @@ in {
|
||||
trigger = "server";
|
||||
envFile = config.sops.secrets."FRIGATE_ENV".path;
|
||||
script = pkgs.writeShellScript "setup-frigate" ''
|
||||
mkdir -p "${serverCfg.configPath}/frigate"
|
||||
mkdir -p "${serverCfg.path.config}/frigate"
|
||||
mkdir -p "/var/lib/frigate/storage"
|
||||
|
||||
# Bootstrap a standard configuration layout if missing
|
||||
if [ ! -f "${serverCfg.configPath}/frigate/config.yml" ]; then
|
||||
cat <<EOF > "${serverCfg.configPath}/frigate/config.yml"
|
||||
if [ ! -f "${serverCfg.path.config}/frigate/config.yml" ]; then
|
||||
cat <<EOF > "${serverCfg.path.config}/frigate/config.yml"
|
||||
mqtt:
|
||||
enabled: False # Set to True and define host if connecting to Home Assistant
|
||||
|
||||
@@ -92,4 +92,5 @@ EOF
|
||||
fi
|
||||
'';
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
@@ -5,15 +5,16 @@ let
|
||||
|
||||
LDAP_DC_DOMAIN = "dc=ldap," + (lib.concatMapStringsSep "," (x: "dc=${x}") (lib.splitString "." serverCfg.domain));
|
||||
in {
|
||||
sops = true;
|
||||
db = true;
|
||||
requires = {
|
||||
secrets = [ name ];
|
||||
databases = [ name ];
|
||||
};
|
||||
|
||||
runtime = {
|
||||
paths = [{
|
||||
path="${serverCfg.dataPath}/gitea/data";
|
||||
owner = "1000:1000";
|
||||
mode = "0755";
|
||||
}{
|
||||
path="${serverCfg.dataPath}/gitea/data-runner";
|
||||
path="${serverCfg.path.data}/gitea";
|
||||
owner = "1000:1000";
|
||||
dirs = ["data" "runner"];
|
||||
mode = "0755";
|
||||
}];
|
||||
containers = {
|
||||
@@ -73,7 +74,7 @@ in {
|
||||
} else {});
|
||||
extraLabels = {
|
||||
"traefik.http.routers.${containerCfg.subdomain}-login.rule" = "Host(`${containerCfg.subdomain}.${serverCfg.domain}`) && Path(`/user/login`) ";
|
||||
"traefik.http.routers.${containerCfg.subdomain}-login.middlewares" = if (serverCfg.containers?authentik && false) then "authentik" else "";
|
||||
"traefik.http.routers.${containerCfg.subdomain}-login.middlewares" = if (serverCfg.containers?authentik && containerCg.extra?proxyauth) then "authentik" else "";
|
||||
"traefik.http.routers.${containerCfg.subdomain}-login.priority" = "100";
|
||||
"traefik.http.routers.${containerCfg.subdomain}-login.entrypoints" = "web-secure";
|
||||
"traefik.http.routers.${containerCfg.subdomain}-login.tls" = "true";
|
||||
@@ -81,7 +82,7 @@ in {
|
||||
|
||||
overrides = {
|
||||
volumes = [
|
||||
"${serverCfg.dataPath}/gitea/data:/data"
|
||||
"${serverCfg.path.data}/gitea/data:/data"
|
||||
];
|
||||
ports = [ "2222:22" ];
|
||||
};
|
||||
@@ -98,7 +99,7 @@ in {
|
||||
|
||||
overrides = {
|
||||
volumes = [
|
||||
"${serverCfg.dataPath}/gitea/data-runner:/data"
|
||||
"${serverCfg.path.data}/gitea/runner:/data"
|
||||
"/var/run/podman/podman.sock:/var/run/docker.sock"
|
||||
];
|
||||
# ports = [ "8088:8088" ];
|
||||
@@ -117,7 +118,7 @@ in {
|
||||
|
||||
$GT admin user create --username "$DEFAULT_ADMIN_USERNAME" --password "$DEFAULT_ADMIN_PASSWORD" --email "$DEFAULT_ADMIN_EMAIL" --admin || true
|
||||
|
||||
touch ${serverCfg.dataPath}/gitea/data-runner/config.yml
|
||||
touch ${serverCfg.path.data}/gitea/data-runner/config.yml
|
||||
|
||||
RUNNER_TOKEN=$($GT actions generate-runner-token)
|
||||
$GTR register \
|
||||
@@ -141,4 +142,5 @@ in {
|
||||
echo "Completed Gitea Setup"
|
||||
'';
|
||||
};
|
||||
};
|
||||
}
|
||||
@@ -2,22 +2,17 @@
|
||||
let
|
||||
serverCfg = config.syscfg.server;
|
||||
version = "latest";
|
||||
|
||||
routerName = if containerCfg.subpath != null
|
||||
then "${containerCfg.subdomain}-${lib.strings.sanitizeDerivationName containerCfg.subpath}"
|
||||
else containerCfg.subdomain;
|
||||
in {
|
||||
|
||||
runtime = {
|
||||
paths = [{
|
||||
path = "${serverCfg.configPath}/handbrake/config";
|
||||
mode = "0755";
|
||||
} {
|
||||
path = "${serverCfg.dataPath}/handbrake/";
|
||||
path = "${serverCfg.path.config}/handbrake";
|
||||
mode = "0755";
|
||||
}];
|
||||
|
||||
containers = {
|
||||
server = builder.mkContainer {
|
||||
authentik = true;
|
||||
tmpfs = true;
|
||||
subdomain = containerCfg.subdomain;
|
||||
subpath = containerCfg.subpath;
|
||||
image = "ghcr.io/jlesage/handbrake:${version}";
|
||||
@@ -30,18 +25,12 @@ in {
|
||||
AUTOMATED_CONVERSION_FORMAT = "mkv";
|
||||
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 = {
|
||||
volumes = [
|
||||
"${serverCfg.configPath}/handbrake/config:/config:rw"
|
||||
"${serverCfg.dataPath}/handbrake/watch:/watch:rw"
|
||||
"${serverCfg.dataPath}/handbrake/output:/output:rw"
|
||||
"${serverCfg.path.config}/handbrake:/config:rw"
|
||||
"${serverCfg.path.dlComplete}:/watch:rw"
|
||||
"${serverCfg.path.dlConverted}:/output:rw"
|
||||
];
|
||||
};
|
||||
};
|
||||
@@ -51,9 +40,9 @@ in {
|
||||
setup = {
|
||||
trigger = "server";
|
||||
script = pkgs.writeShellScript "setup" ''
|
||||
mkdir -p ${serverCfg.dataPath}/handbrake/{watch,output}
|
||||
mkdir -p ${serverCfg.path.data}/handbrake/{watch,output}
|
||||
|
||||
'';
|
||||
};
|
||||
|
||||
};
|
||||
}
|
||||
@@ -4,6 +4,7 @@ let
|
||||
serverCfg = config.syscfg.server;
|
||||
|
||||
in {
|
||||
runtime = {
|
||||
vm = {
|
||||
portForward = [ 8123 ];
|
||||
cfg = {cfg,...}: {
|
||||
@@ -97,5 +98,5 @@ in {
|
||||
fi
|
||||
'';
|
||||
};
|
||||
|
||||
};
|
||||
}
|
||||
@@ -258,9 +258,7 @@ let
|
||||
];}#)];}
|
||||
];
|
||||
in {
|
||||
sops = false;
|
||||
db = false;
|
||||
|
||||
runtime = {
|
||||
containers = {
|
||||
server = builder.mkContainer {
|
||||
subdomain = containerCfg.subdomain;
|
||||
@@ -284,5 +282,5 @@ in {
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
};
|
||||
}
|
||||
@@ -4,14 +4,19 @@ let
|
||||
serverCfg = config.syscfg.server;
|
||||
|
||||
in {
|
||||
sops = true;
|
||||
db = true;
|
||||
requires = {
|
||||
secrets = [ name ];
|
||||
databases = [ name ];
|
||||
};
|
||||
|
||||
runtime = {
|
||||
paths = [{
|
||||
path = "${serverCfg.configPath}/immich/cache";
|
||||
path = "${serverCfg.path.config}/immich";
|
||||
dirs = ["cache"];
|
||||
mode = "0750";
|
||||
}{
|
||||
path = "${serverCfg.dataPath}/immich/";
|
||||
path = "${serverCfg.path.data}/immich/";
|
||||
dirs = ["upload" "thumbs" "encoded-video" "backups"];
|
||||
mode = "0755";
|
||||
}];
|
||||
|
||||
@@ -33,7 +38,10 @@ in {
|
||||
};
|
||||
overrides = {
|
||||
volumes = [
|
||||
"${serverCfg.dataPath}/immich:/data"
|
||||
"${serverCfg.path.photo}:/data/upload"
|
||||
"${serverCfg.path.data}/immich/backups:/data/backups"
|
||||
"${serverCfg.path.config}/immich/thumbs:/data/thumbs"
|
||||
"${serverCfg.path.config}/immich/encoded-video:/data/encoded-video"
|
||||
];
|
||||
};
|
||||
};
|
||||
@@ -43,7 +51,7 @@ in {
|
||||
port = 3003;
|
||||
overrides = {
|
||||
volumes = [
|
||||
"${serverCfg.configPath}/immich/cache:/cache"
|
||||
"${serverCfg.path.config}/immich/cache:/cache"
|
||||
];
|
||||
};
|
||||
};
|
||||
@@ -57,8 +65,6 @@ in {
|
||||
$PSQL -d "immich_db" -tAc "CREATE EXTENSION IF NOT EXISTS vchord CASCADE;"
|
||||
$PSQL -d "immich_db" -tAc "CREATE EXTENSION IF NOT EXISTS earthdistance CASCADE;"
|
||||
|
||||
mkdir -p ${serverCfg.dataPath}/immich/{upload,library,thumbs,encoded-video,profile,backups}
|
||||
|
||||
IMMICH_URL="https://${containerCfg.subdomain}.${serverCfg.domain}"
|
||||
until [[ "$(${pkgs.curl}/bin/curl -s -o /dev/null -w "%{http_code}" "$IMMICH_URL")" =~ (200|301|302) ]]; do
|
||||
sleep 5
|
||||
@@ -94,4 +100,5 @@ in {
|
||||
|
||||
'';
|
||||
};
|
||||
};
|
||||
}
|
||||
@@ -5,14 +5,19 @@ let
|
||||
|
||||
|
||||
in {
|
||||
sops = true;
|
||||
db = true;
|
||||
requires = {
|
||||
secrets = [ name ];
|
||||
databases = [ name ];
|
||||
};
|
||||
|
||||
runtime = {
|
||||
paths = [{
|
||||
path = "${serverCfg.configPath}/influxdb/";
|
||||
path = "${serverCfg.path.config}/influxdb/";
|
||||
owner = "1500:1500";
|
||||
mode = "0700";
|
||||
}{
|
||||
path = "${serverCfg.dataPath}/influxdb/";
|
||||
path = "${serverCfg.path.data}/influxdb/";
|
||||
owner = "1500:1500";
|
||||
mode = "0700";
|
||||
}];
|
||||
|
||||
@@ -28,13 +33,14 @@ in {
|
||||
# };
|
||||
# overrides = {
|
||||
# volumes = [
|
||||
# "${serverCfg.dataPath}/influxdb:/db:rw"
|
||||
# "${serverCfg.configPath}/influxdb:/config:ro"
|
||||
# "${serverCfg.path.data}/influxdb:/db:rw"
|
||||
# "${serverCfg.path.config}/influxdb:/config:ro"
|
||||
# ];
|
||||
# };
|
||||
# };
|
||||
|
||||
server = builder.mkContainer {
|
||||
tmpfs = true;
|
||||
subdomain = containerCfg.subdomain;
|
||||
image = "influxdata/influxdb3-ui:${version}";
|
||||
port = 8080;
|
||||
@@ -43,15 +49,12 @@ in {
|
||||
SESSION_SECRET_KEY = "7b0024c13ae770000f797c201e2f210b9932a689c04d34de04379faa44e88e97";
|
||||
DATABASE_URL = "/db/sqlite.db";
|
||||
};
|
||||
extraOptions = [
|
||||
"--tmpfs=/tmp:rw,noexec,nosuid,size=512m"
|
||||
];
|
||||
overrides = {
|
||||
ports = [ "8080:8080" ];
|
||||
cmd = [ "--mode=admin" ];
|
||||
volumes = [
|
||||
"${serverCfg.dataPath}/influxdb:/db:rw"
|
||||
"${serverCfg.configPath}/influxdb/:/app-root/config:ro"
|
||||
"${serverCfg.path.data}/influxdb:/db:rw"
|
||||
"${serverCfg.path.config}/influxdb/:/app-root/config:ro"
|
||||
];
|
||||
};
|
||||
};
|
||||
@@ -60,7 +63,7 @@ in {
|
||||
setup = {
|
||||
trigger = "server";
|
||||
script = pkgs.writeShellScript "setup" ''
|
||||
cat > ${serverCfg.configPath}/influxdb/config.json << 'EOF'
|
||||
cat > ${serverCfg.path.config}/influxdb/config.json << 'EOF'
|
||||
{
|
||||
"DEFAULT_INFLUX_SERVER": "http://${builder.host}:8181",
|
||||
"DEFAULT_INFLUX_DATABASE": "main",
|
||||
@@ -68,8 +71,8 @@ in {
|
||||
"DEFAULT_SERVER_NAME": "${serverCfg.domain}"
|
||||
}
|
||||
EOF
|
||||
chmod -R 755 ${serverCfg.configPath}/influxdb
|
||||
chmod -R 755 ${serverCfg.path.config}/influxdb
|
||||
'';
|
||||
};
|
||||
|
||||
};
|
||||
}
|
||||
@@ -24,10 +24,14 @@ let
|
||||
};
|
||||
|
||||
in {
|
||||
sops = true;
|
||||
db = true;
|
||||
requires = {
|
||||
secrets = [ name ];
|
||||
databases = [ name ];
|
||||
};
|
||||
|
||||
runtime = {
|
||||
paths = [{
|
||||
path="${serverCfg.configPath}/invidious";
|
||||
path="${serverCfg.path.config}/invidious";
|
||||
mode = "0755";
|
||||
}];
|
||||
|
||||
@@ -49,7 +53,7 @@ in {
|
||||
};
|
||||
overrides = {
|
||||
volumes = [
|
||||
"${serverCfg.configPath}/invidious:/data:ro"
|
||||
"${serverCfg.path.config}/invidious:/data:ro"
|
||||
];
|
||||
};
|
||||
};
|
||||
@@ -72,7 +76,8 @@ in {
|
||||
export DB_HOST=${builder.host}
|
||||
export INVIDIOUS_DOMAIN=${containerCfg.subdomain}.${serverCfg.domain}
|
||||
|
||||
${pkgs.gettext}/bin/envsubst < "${../data/invidious/config.yml}" > "${serverCfg.configPath}/invidious/config.yml"
|
||||
${pkgs.gettext}/bin/envsubst < "${../data/invidious/config.yml}" > "${serverCfg.path.config}/invidious/config.yml"
|
||||
'';
|
||||
};
|
||||
};
|
||||
}
|
||||
@@ -25,14 +25,10 @@ let
|
||||
};
|
||||
};
|
||||
in {
|
||||
runtime = {
|
||||
paths = [
|
||||
{
|
||||
path = "${serverCfg.dataPath}/media/";
|
||||
owner = "1000:1000";
|
||||
mode = "0755";
|
||||
}
|
||||
{
|
||||
path = "${serverCfg.configPath}/jellyfin/";
|
||||
path = "${serverCfg.path.config}/jellyfin/";
|
||||
owner = "1000:1000";
|
||||
mode = "0755";
|
||||
}
|
||||
@@ -40,6 +36,7 @@ in {
|
||||
|
||||
containers = {
|
||||
server = builder.mkContainer {
|
||||
tmpfs = true;
|
||||
subdomain = containerCfg.subdomain;
|
||||
imageStream = image;
|
||||
port = 8096;
|
||||
@@ -49,9 +46,6 @@ in {
|
||||
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";
|
||||
};
|
||||
extraOptions = [
|
||||
"--tmpfs=/tmp:rw,noexec,nosuid,size=512m"
|
||||
];
|
||||
overrides = {
|
||||
cmd = [
|
||||
"--datadir" "/config/data"
|
||||
@@ -60,8 +54,8 @@ in {
|
||||
"--logdir" "/config/log"
|
||||
];
|
||||
volumes = [
|
||||
"${serverCfg.dataPath}/media:/media:ro"
|
||||
"${serverCfg.configPath}/jellyfin:/config"
|
||||
"${serverCfg.path.film}:/media:ro"
|
||||
"${serverCfg.path.config}/jellyfin:/config"
|
||||
];
|
||||
# If you have an Intel/AMD GPU for transcoding, add the device:
|
||||
devices = lib.optionals (builtins.pathExists "/dev/dri") [ "/dev/dri:/dev/dri" ];
|
||||
@@ -169,7 +163,7 @@ in {
|
||||
fi
|
||||
''}
|
||||
|
||||
${pkgs.sqlite}/bin/sqlite3 ${serverCfg.configPath}/jellyfin/data/data/jellyfin.db <<EOF
|
||||
${pkgs.sqlite}/bin/sqlite3 ${serverCfg.path.config}/jellyfin/data/data/jellyfin.db <<EOF
|
||||
INSERT OR IGNORE INTO ApiKeys (Id, AccessToken, Name, DateCreated, DateLastActivity)
|
||||
VALUES ( 1, "$HOMEPAGE_VAR_JELLYFIN_API", 'Home', strftime('%Y-%m-%d %H:%M:%S', 'now'), strftime('%Y-%m-%d %H:%M:%S', 'now'));
|
||||
EOF
|
||||
@@ -177,5 +171,5 @@ EOF
|
||||
|
||||
'';
|
||||
};
|
||||
|
||||
};
|
||||
}
|
||||
@@ -3,21 +3,21 @@ let
|
||||
version = "31";
|
||||
serverCfg = config.syscfg.server;
|
||||
in {
|
||||
sops = true;
|
||||
db = true;
|
||||
requires = {
|
||||
secrets = [ name ];
|
||||
databases = [ name ];
|
||||
};
|
||||
|
||||
runtime = {
|
||||
paths = [{
|
||||
path="${serverCfg.dataPath}/nextcloud/www";
|
||||
path="${serverCfg.path.config}/nextcloud";
|
||||
owner = "33:33";
|
||||
mode = "0755";
|
||||
}{
|
||||
path="${serverCfg.dataPath}/nextcloud/data";
|
||||
owner = "33:33";
|
||||
mode = "0755";
|
||||
backup = true;
|
||||
}];
|
||||
|
||||
containers = {
|
||||
server = builder.mkContainer {
|
||||
tmpfs = true;
|
||||
subdomain = containerCfg.subdomain;
|
||||
image = "nextcloud:${version}";
|
||||
port = 80;
|
||||
@@ -28,13 +28,14 @@ in {
|
||||
POSTGRES_USER = "nextcloud_user";
|
||||
POSTGRES_DB = "nextcloud_db";
|
||||
AUTHENTIK_POSTGRESQL__SSLMODE = "disable";
|
||||
"NEXTCLOUD_TRUSTED_DOMAINS " = "${containerCfg.subdomain}.${serverCfg.domain} nextcloud-server";
|
||||
"SMTP_HOST" = serverCfg.mailServer;
|
||||
"SMTP_NAME" = "mail_user";
|
||||
"SMTP_PASSWORD" = "mail_password";
|
||||
"MAIL_FROM_ADDRESS" = "${containerCfg.subdomain}@${serverCfg.domain}";
|
||||
"MAIL_DOMAIN" = serverCfg.mailDomain;
|
||||
"TRUSTED_PROXIES" = "10.10.0.0/16 192.168.0.0/16";
|
||||
NEXTCLOUD_TRUSTED_DOMAINS = "${containerCfg.subdomain}.${serverCfg.domain} nextcloud-server";
|
||||
SMTP_HOST = serverCfg.mail.server;
|
||||
SMTP_NAME = "mail_user";
|
||||
SMTP_PASSWORD = "mail_password";
|
||||
MAIL_FROM_ADDRESS = "${containerCfg.subdomain}@${serverCfg.domain}";
|
||||
MAIL_DOMAIN = serverCfg.mail.domain;
|
||||
TRUSTED_PROXIES = "10.10.0.0/16 192.168.0.0/16";
|
||||
NEXTCLOUD_DATA_DIR = "/var/www/html/data";
|
||||
};
|
||||
extraLabels = {
|
||||
"traefik.http.routers.${containerCfg.subdomain}.middlewares" = "sts_headers,${containerCfg.subdomain}-caldav";
|
||||
@@ -44,14 +45,11 @@ in {
|
||||
"traefik.http.middlewares.sts_headers.headers.stsSeconds" = "15552000";
|
||||
"traefik.http.middlewares.sts_headers.headers.stsIncludeSubdomains" = "true";
|
||||
};
|
||||
extraOptions = [
|
||||
"--tmpfs=/tmp:rw,noexec,nosuid,size=512m"
|
||||
];
|
||||
overrides = {
|
||||
ports = if containerCfg.port!=null then [ "${toString containerCfg.port}:80" ] else [];
|
||||
volumes = [
|
||||
"${serverCfg.dataPath}/nextcloud/www:/var/www/html"
|
||||
"${serverCfg.dataPath}/nextcloud/data:/var/www/html/data"
|
||||
"${serverCfg.path.config}/nextcloud:/var/www/html"
|
||||
"${serverCfg.path.cloud}:/var/www/html/data"
|
||||
];
|
||||
};
|
||||
};
|
||||
@@ -197,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" ];
|
||||
};
|
||||
}
|
||||
|
||||
@@ -4,12 +4,11 @@ let
|
||||
version = "5.1.4";
|
||||
|
||||
in {
|
||||
sops = false;
|
||||
db = false;
|
||||
runtime = {
|
||||
paths = [
|
||||
{ path="${serverCfg.configPath}/openhab/conf"; owner="1000:1000"; mode = "0755"; }
|
||||
{ path="${serverCfg.configPath}/openhab/userdata"; owner="1000:1000"; mode = "0755"; }
|
||||
{ path="${serverCfg.configPath}/openhab/addons"; 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/addons"; owner="1000:1000"; mode = "0755"; }
|
||||
];
|
||||
|
||||
containers = {
|
||||
@@ -31,9 +30,9 @@ in {
|
||||
];
|
||||
overrides = {
|
||||
volumes = [
|
||||
"${serverCfg.configPath}/openhab/conf:/openhab/conf"
|
||||
"${serverCfg.configPath}/openhab/userdata:/openhab/userdata"
|
||||
"${serverCfg.configPath}/openhab/addons:/opt/openhab/addons"
|
||||
"${serverCfg.path.config}/openhab/conf:/openhab/conf"
|
||||
"${serverCfg.path.config}/openhab/userdata:/openhab/userdata"
|
||||
"${serverCfg.path.config}/openhab/addons:/opt/openhab/addons"
|
||||
"/var/run/dbus/system_bus_socket:/var/run/dbus/system_bus_socket:ro"
|
||||
];
|
||||
};
|
||||
@@ -74,4 +73,5 @@ in {
|
||||
#Extra: AndroidTV/Jellyfin (Bind with lights + more)
|
||||
'';
|
||||
};
|
||||
};
|
||||
}
|
||||
@@ -59,12 +59,9 @@ let
|
||||
};
|
||||
});
|
||||
in {
|
||||
sops = true;
|
||||
# paths = [{
|
||||
# path="${serverCfg.dataPath}/searxng/";
|
||||
# mode = "0444";
|
||||
# }];
|
||||
requires.secrets = [ name ];
|
||||
|
||||
runtime = {
|
||||
containers = {
|
||||
server = builder.mkContainer {
|
||||
subdomain = containerCfg.subdomain;
|
||||
@@ -80,13 +77,11 @@ in {
|
||||
#SEARXNG_VALKEY_URL = "valkey://user:password@${builder.host}:6379/0}";
|
||||
};
|
||||
overrides = {
|
||||
cmd = [ ];
|
||||
volumes = [
|
||||
"${settings}:/etc/searxng/settings.yml"
|
||||
# "/path/to/your/logo.png:/usr/local/searxng/searx/static/themes/simple/img/searxng.png
|
||||
# "${serverCfg.dataPath}/searxng:/var/cache/searxng/"
|
||||
];
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
@@ -2,20 +2,16 @@
|
||||
let
|
||||
version = "latest";
|
||||
serverCfg = config.syscfg.server;
|
||||
|
||||
routerName = if containerCfg.subpath != null
|
||||
then "${containerCfg.subdomain}-${lib.strings.sanitizeDerivationName containerCfg.subpath}"
|
||||
else containerCfg.subdomain;
|
||||
in {
|
||||
sops = false;
|
||||
db = false;
|
||||
runtime = {
|
||||
paths = [{
|
||||
path = "${serverCfg.configPath}/selfmark/";
|
||||
path = "${serverCfg.path.config}/selfmark/";
|
||||
mode = "0444";
|
||||
}];
|
||||
|
||||
containers = {
|
||||
server = builder.mkContainer {
|
||||
authentik = true;
|
||||
subdomain = containerCfg.subdomain;
|
||||
subpath = containerCfg.subpath;
|
||||
image = "ghcr.io/calibrain/shelfmark:${version}";
|
||||
@@ -81,15 +77,14 @@ in {
|
||||
EXT_BYPASSER_PATH = "/v1";
|
||||
EXT_BYPASSER_TIMEOUT = "60000";
|
||||
};
|
||||
|
||||
extraLabels = {
|
||||
} // (if serverCfg.containers ? authentik then {
|
||||
"traefik.http.routers.${routerName}.middlewares" = "authentik";
|
||||
} else {});
|
||||
overrides = {
|
||||
volumes = [ ];
|
||||
volumes = [
|
||||
"${serverCfg.path.dlComplete}:/books:rw"
|
||||
"${serverCfg.path.books}:/output:rw"
|
||||
"${serverCfg.path.config}/selfmark:/config:rw"
|
||||
];
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -30,9 +30,10 @@ let
|
||||
in
|
||||
assert containerCfg.subpath == null || throw "Error: Servarr does not support subpath.";
|
||||
{
|
||||
sops = true;
|
||||
requires.secrets = [ name ];
|
||||
# db = [ "prowlarr" "sonarr" "radarr" ]; -> one db for each
|
||||
|
||||
runtime = {
|
||||
paths = [
|
||||
{ path = "${serverCfg.dataPath}/media/"; mode = "0755"; }
|
||||
{ path = "${serverCfg.configPath}/servarr/prowlarr"; mode = "0755"; }
|
||||
@@ -44,6 +45,8 @@ in
|
||||
containers = {
|
||||
}// lib.optionalAttrs (builtins.elem "prowlarr" (containerCfg.extra.modules or defaultModules)) {
|
||||
prowlarr = builder.mkContainer {
|
||||
authentik = true;
|
||||
tmpfs = true;
|
||||
subdomain = containerCfg.subdomain;
|
||||
subpath = "prowlarr";
|
||||
imageStream = images.prowlarr;
|
||||
@@ -58,17 +61,15 @@ in
|
||||
};
|
||||
extraOptions = [
|
||||
"--user=0:0"
|
||||
"--tmpfs=/tmp:rw,noexec,nosuid,size=512m"
|
||||
"--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" ];
|
||||
};
|
||||
|
||||
}// lib.optionalAttrs (builtins.elem "radarr" (containerCfg.extra.modules or defaultModules)) {
|
||||
radarr = builder.mkContainer {
|
||||
authentik = true;
|
||||
tmpfs = true;
|
||||
subdomain = containerCfg.subdomain;
|
||||
subpath = "radarr";
|
||||
imageStream = images.radarr;
|
||||
@@ -83,17 +84,15 @@ in
|
||||
};
|
||||
extraOptions = [
|
||||
"--user=0:0"
|
||||
"--tmpfs=/tmp:rw,noexec,nosuid,size=512m"
|
||||
"--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" ];
|
||||
};
|
||||
|
||||
}// lib.optionalAttrs (builtins.elem "sonarr" (containerCfg.extra.modules or defaultModules)) {
|
||||
sonarr = builder.mkContainer {
|
||||
authentik = true;
|
||||
tmpfs = true;
|
||||
subdomain = containerCfg.subdomain;
|
||||
subpath = "sonarr";
|
||||
imageStream = images.sonarr;
|
||||
@@ -108,17 +107,15 @@ in
|
||||
};
|
||||
extraOptions = [
|
||||
"--user=0:0"
|
||||
"--tmpfs=/tmp:rw,noexec,nosuid,size=512m"
|
||||
"--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" ];
|
||||
};
|
||||
|
||||
}// lib.optionalAttrs (builtins.elem "lidarr" (containerCfg.extra.modules or defaultModules)) {
|
||||
lidarr = builder.mkContainer {
|
||||
authentik = true;
|
||||
tmpfs = true;
|
||||
subdomain = containerCfg.subdomain;
|
||||
subpath = "lidarr";
|
||||
imageStream = images.lidarr;
|
||||
@@ -133,12 +130,8 @@ in
|
||||
};
|
||||
extraOptions = [
|
||||
"--user=0:0"
|
||||
"--tmpfs=/tmp:rw,noexec,nosuid,size=512m"
|
||||
"--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" ];
|
||||
};
|
||||
|
||||
@@ -526,4 +519,5 @@ in
|
||||
|
||||
'';
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
@@ -3,10 +3,13 @@ let
|
||||
version = "stable";
|
||||
serverCfg = config.syscfg.server;
|
||||
in {
|
||||
sops = true;
|
||||
db =true;
|
||||
containers = {
|
||||
requires = {
|
||||
secrets = [ name ];
|
||||
databases = [ name ];
|
||||
};
|
||||
|
||||
runtime = {
|
||||
containers = {
|
||||
server = builder.mkContainer {
|
||||
subdomain = containerCfg.subdomain;
|
||||
image = "ghcr.io/suwayomi/suwayomi-server:${version}";
|
||||
@@ -40,9 +43,11 @@ in {
|
||||
|
||||
overrides = {
|
||||
volumes = [
|
||||
"${serverCfg.path.manga}:/home/suwayomi/.local/share/Tachidesk/downloads"
|
||||
# "${serverCfg.path.config}/suwayomi:/home/suwayomi/.local/share/Tachidesk"
|
||||
];
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
};
|
||||
}
|
||||
@@ -11,9 +11,11 @@ let
|
||||
};
|
||||
};
|
||||
in {
|
||||
sops = true;
|
||||
requires.secrets = [ name ];
|
||||
|
||||
runtime = {
|
||||
paths = [{
|
||||
path="${serverCfg.configPath}/traefik";
|
||||
path="${serverCfg.path.config}/traefik";
|
||||
owner = "1000:1000";
|
||||
mode = "0755";
|
||||
}];
|
||||
@@ -77,11 +79,11 @@ in {
|
||||
ports = [ "443:443" "80:80" ] ++ (if containerCfg.port!=null then [ "${toString containerCfg.port}:8080" ] else []);
|
||||
volumes = [
|
||||
"/var/run/podman/podman.sock:/var/run/docker.sock"
|
||||
# "${serverCfg.configPath}/traefik/access.log:/etc/traefik/access.log"
|
||||
"${serverCfg.configPath}/traefik:/custom"
|
||||
# "${serverCfg.path.config}/traefik/access.log:/etc/traefik/access.log"
|
||||
"${serverCfg.path.config}/traefik:/custom"
|
||||
];
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -13,26 +13,17 @@ let
|
||||
};
|
||||
};
|
||||
};
|
||||
routerName = if containerCfg.subpath != null
|
||||
then "${containerCfg.subdomain}-${lib.strings.sanitizeDerivationName containerCfg.subpath}"
|
||||
else containerCfg.subdomain;
|
||||
in {
|
||||
runtime = {
|
||||
paths = [{
|
||||
path = "${serverCfg.dataPath}/transmission/complete";
|
||||
owner = "1000:1000";
|
||||
mode = "0755";
|
||||
}{
|
||||
path = "${serverCfg.dataPath}/transmission/incomplete";
|
||||
owner = "1000:1000";
|
||||
mode = "0755";
|
||||
}{
|
||||
path = "${serverCfg.configPath}/transmission/config";
|
||||
path = "${serverCfg.path.config}/transmission";
|
||||
owner = "1000:1000";
|
||||
mode = "0755";
|
||||
}];
|
||||
|
||||
containers = {
|
||||
server = builder.mkContainer {
|
||||
authentik = true;
|
||||
subdomain = containerCfg.subdomain;
|
||||
subpath = containerCfg.subpath;
|
||||
imageStream = image;
|
||||
@@ -44,17 +35,12 @@ in {
|
||||
WHITELIST = "";# 127.0.0.1,::1,10.*";
|
||||
# HOST_WHITELIST = "traefik-server,authentik-server,authentik-worker";
|
||||
};
|
||||
extraLabels = {
|
||||
} // (if serverCfg.containers ? authentik then {
|
||||
"traefik.http.routers.${routerName}.middlewares" = "authentik";
|
||||
} else {});
|
||||
|
||||
overrides = {
|
||||
cmd = [ ];
|
||||
volumes = [
|
||||
"${serverCfg.dataPath}/transmission/complete:/downloads/complete"
|
||||
"${serverCfg.dataPath}/transmission/incomplete:/downloads/incomplete"
|
||||
"${serverCfg.configPath}/transmission/config:/config"
|
||||
"${serverCfg.path.dlComplete}:/downloads/complete"
|
||||
"${serverCfg.path.dlIncomplete}:/downloads/incomplete"
|
||||
"${serverCfg.path.config}/transmission:/config"
|
||||
];
|
||||
};
|
||||
};
|
||||
@@ -66,8 +52,8 @@ in {
|
||||
envFile = [ config.sops.secrets."CUSTOM".path ];
|
||||
script = pkgs.writeShellScript "setup" ''
|
||||
|
||||
${pkgs.gettext}/bin/envsubst < "${../data/transmission/settings.json}" > "${serverCfg.configPath}/transmission/config/settings.json"
|
||||
${pkgs.gettext}/bin/envsubst < "${../data/transmission/settings.json}" > "${serverCfg.path.config}/transmission/config/settings.json"
|
||||
'';
|
||||
};
|
||||
|
||||
};
|
||||
}
|
||||
@@ -15,15 +15,21 @@ let
|
||||
};
|
||||
};
|
||||
in {
|
||||
sops = true;
|
||||
db = true;
|
||||
requires = {
|
||||
secrets = [ name ];
|
||||
databases = [ name ];
|
||||
};
|
||||
|
||||
runtime = {
|
||||
paths = [{
|
||||
path = "${serverCfg.configPath}/umami/";
|
||||
path = "${serverCfg.path.config}/umami/";
|
||||
mode = "0444";
|
||||
}];
|
||||
|
||||
containers = {
|
||||
server = builder.mkContainer {
|
||||
authentik = true;
|
||||
tmpfs = true;
|
||||
subdomain = containerCfg.subdomain;
|
||||
image = "${pkgs.umami.name}:${pkgs.umami.version}";
|
||||
imageStream = image;
|
||||
@@ -39,16 +45,10 @@ in {
|
||||
# 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 = {
|
||||
cmd = [ "start" ]; # Specific command for the umami binary
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
};
|
||||
}
|
||||
@@ -1,16 +1,32 @@
|
||||
{ config, lib, pkgs, serverCfg }:
|
||||
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 =
|
||||
{ image ? null, imageStream ? null, imageFile ? null
|
||||
, secret ? null
|
||||
, subdomain ? null, subpath?null, port ? null
|
||||
, authentik ? false
|
||||
, tmpfs ? false
|
||||
, tmpfsSize ? "512m"
|
||||
, extraEnv ? { }, extraLabels ? { }, extraOptions ? [ ]
|
||||
, overrides ? { }
|
||||
}:
|
||||
let
|
||||
routerName = if subpath != null
|
||||
then "${subdomain}-${lib.strings.sanitizeDerivationName subpath}"
|
||||
else subdomain;
|
||||
routerName = mkRouterName { inherit subdomain subpath; };
|
||||
base = {
|
||||
image = if imageStream != null then "${imageStream.imageName}:${imageStream.imageTag}"
|
||||
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;
|
||||
}) else {
|
||||
"traefik.enable" = "false";
|
||||
}) // extraLabels;
|
||||
})
|
||||
// lib.optionalAttrs authentik (mkAuthentikLabels { inherit subdomain subpath routerName; })
|
||||
// extraLabels;
|
||||
|
||||
extraOptions = [
|
||||
"--add-host=host.containers.internal:host-gateway"
|
||||
] ++ extraOptions;
|
||||
]
|
||||
++ lib.optional tmpfs (mkTmpfsOption tmpfsSize)
|
||||
++ extraOptions;
|
||||
};
|
||||
in lib.recursiveUpdate base overrides;
|
||||
vmBuilder = { name, vm }: ((import "${pkgs.path}/nixos/lib/eval-config.nix" {
|
||||
@@ -69,6 +89,30 @@ let
|
||||
in {
|
||||
mkContainer = contBuilder;
|
||||
mkVm = vmBuilder;
|
||||
mkApp = name: app:
|
||||
{
|
||||
inherit name;
|
||||
requires = {
|
||||
secrets = getOr app [ "requires" "secrets" ] [ ];
|
||||
databases = getOr app [ "requires" "databases" ] [ ];
|
||||
};
|
||||
exports = {
|
||||
authentik = {
|
||||
blueprints = getOr app [ "exports" "authentik" "blueprints" ] [ ];
|
||||
};
|
||||
};
|
||||
runtime = {
|
||||
paths = getOr app [ "runtime" "paths" ] [ ];
|
||||
containers = getOr app [ "runtime" "containers" ] { };
|
||||
vm = getOr app [ "runtime" "vm" ] null;
|
||||
cron = getOr app [ "runtime" "cron" ] [ ];
|
||||
setup = {
|
||||
trigger = "";
|
||||
script = null;
|
||||
envFile = [ ];
|
||||
} // getOr app [ "runtime" "setup" ] { };
|
||||
};
|
||||
};
|
||||
mkData = { name, dir, vars?{} }: pkgs.runCommand name vars ''
|
||||
mkdir -p $out
|
||||
cp -r ${./data + "/${dir}"}/. $out/
|
||||
|
||||
@@ -2,30 +2,25 @@
|
||||
let
|
||||
serverCfg = config.syscfg.server;
|
||||
builder = import ./builder.nix { inherit config lib pkgs serverCfg; };
|
||||
|
||||
in{
|
||||
config = lib.mkMerge [{
|
||||
syscfg.server.loadedContainers = lib.mapAttrs (name: containerCfg:
|
||||
(import (./apps + "/${name}.nix")) { inherit config pkgs lib containerCfg builder name; }
|
||||
) config.syscfg.server.containers;
|
||||
} (lib.mkIf ( serverCfg.containers != {} ) (
|
||||
let
|
||||
appsList = builtins.attrValues config.syscfg.server.loadedContainers;
|
||||
loadApp = name: containerCfg:
|
||||
builder.mkApp name ((import (./apps + "/${name}.nix")) {
|
||||
inherit config pkgs lib containerCfg builder name;
|
||||
});
|
||||
loadedContainers = lib.mapAttrs loadApp serverCfg.containers;
|
||||
appsList = builtins.attrValues loadedContainers;
|
||||
concatRuntimeLists = field: lib.concatMap (app: app.runtime.${field}) appsList;
|
||||
mkNamedUnits = mkUnit: items: lib.listToAttrs (map mkUnit items);
|
||||
mergedContainers = lib.concatMapAttrs (appName: app:
|
||||
lib.mapAttrs' (cName: cCfg: lib.nameValuePair "${appName}-${cName}" cCfg) app.containers
|
||||
) config.syscfg.server.loadedContainers;
|
||||
allPathConfigs = lib.concatMap (app: app.paths) appsList;
|
||||
allSetupConfigs = lib.concatMap (app: if app.setup?script then [({name = app.name; envFile="";} // app.setup)] else []) appsList;
|
||||
allCronsConfigs = lib.concatMap (app: app.cron) appsList;
|
||||
allVMConfigs = builtins.filter (app: app.vm != null) appsList;
|
||||
in{
|
||||
virtualisation.oci-containers = {
|
||||
backend = "podman";
|
||||
containers = mergedContainers;
|
||||
};
|
||||
system.activationScripts.container-setup-dirs = {
|
||||
deps = [ "users" "groups" ];
|
||||
text = lib.concatStringsSep "\n" (map (cfg:
|
||||
lib.mapAttrs' (cName: cCfg: lib.nameValuePair "${appName}-${cName}" cCfg) app.runtime.containers
|
||||
) loadedContainers;
|
||||
allPathConfigs = map (path: {
|
||||
inherit path;
|
||||
mode = "0755";
|
||||
}) (lib.unique (builtins.attrValues serverCfg.path)) ++ concatRuntimeLists "paths";
|
||||
allSetupConfigs = map (app: ({ name = app.name; envFile = ""; } // app.runtime.setup)) appsList;
|
||||
allCronsConfigs = concatRuntimeLists "cron";
|
||||
allVMConfigs = builtins.filter (app: app.runtime.vm != null) appsList;
|
||||
mkPathSetup = cfg:
|
||||
let
|
||||
effectiveCfg = {
|
||||
owner = "root:root";
|
||||
@@ -37,8 +32,18 @@ in{
|
||||
${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/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 = {
|
||||
@@ -52,7 +57,7 @@ in{
|
||||
startAt = "weekly";
|
||||
};
|
||||
}
|
||||
// lib.listToAttrs (lib.concatMap (e: [{
|
||||
// mkNamedUnits (e: {
|
||||
name = "${e.name}-vm";
|
||||
value = {
|
||||
description = "Isolated NixOS Guest VM for ${e.name}";
|
||||
@@ -69,12 +74,12 @@ in{
|
||||
RestartSec = "10s";
|
||||
ExecStartPre = "${pkgs.coreutils}/bin/mkdir -p /media/data/kvm";
|
||||
ExecStart = ''
|
||||
${builder.mkVm { name = e.name; vm = e.vm; }}/bin/run-${e.name}-vm -nographic
|
||||
${builder.mkVm { name = e.name; vm = e.runtime.vm; }}/bin/run-${e.name}-vm -nographic
|
||||
'';
|
||||
};
|
||||
};
|
||||
}]) allVMConfigs)
|
||||
// lib.listToAttrs (lib.concatMap (e: [{
|
||||
}) allVMConfigs
|
||||
// mkNamedUnits (e: {
|
||||
name = "${e.name}-setup";
|
||||
value = {
|
||||
description = "Run ${e.name} setup";
|
||||
@@ -90,13 +95,11 @@ in{
|
||||
User = "root";
|
||||
};
|
||||
};
|
||||
}]) allSetupConfigs );
|
||||
}) allSetupConfigs;
|
||||
|
||||
services.cron = {
|
||||
enable = true;
|
||||
systemCronJobs = allCronsConfigs;
|
||||
};
|
||||
|
||||
}))];
|
||||
|
||||
})];
|
||||
}
|
||||
@@ -3,7 +3,7 @@
|
||||
let
|
||||
|
||||
listNames = config.syscfg.server.db;
|
||||
containerNames = builtins.attrNames (lib.filterAttrs (appName: app: app.db) config.syscfg.server.loadedContainers);
|
||||
containerNames = lib.concatMap (app: app.requires.databases) (builtins.attrValues config.syscfg.server.loadedContainers);
|
||||
allApps = lib.unique (listNames ++ containerNames);
|
||||
in {
|
||||
config = lib.mkIf ( builtins.length allApps > 0) {
|
||||
@@ -47,9 +47,10 @@ in {
|
||||
environment = {
|
||||
INFLUXDB3_NODE_IDENTIFIER_PREFIX = "node0";
|
||||
INFLUXDB3_OBJECT_STORE = "file";
|
||||
INFLUXDB3_DATA_DIR = "${config.syscfg.server.dataPath}/influxdb";
|
||||
INFLUXDB3_DB_DIR = "${config.syscfg.server.dataPath}/influxdb";
|
||||
INFLUXDB3_DATA_DIR = "${config.syscfg.server.path.data}/influxdb";
|
||||
INFLUXDB3_DB_DIR = "${config.syscfg.server.path.data}/influxdb";
|
||||
INFLUXDB3_ENABLE_INTERNAL_DB = "true";
|
||||
INFLUXDB3_AUTH_TOKEN = "b27686e85a883437666f61586e084f7deb763958497739479ca48bc913ee90afd1a920332156133c89fb8674cb197ced17706074e6a42fc7ce6b2d54ac6119c9";
|
||||
INFLUXDB3_INITIAL_ADMIN_TOKEN = "b27686e85a883437666f61586e084f7deb763958497739479ca48bc913ee90afd1a920332156133c89fb8674cb197ced17706074e6a42fc7ce6b2d54ac6119c9";
|
||||
};
|
||||
serviceConfig = {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{ config, lib, pkgs, ... }:
|
||||
let
|
||||
listNames = config.syscfg.server.db;
|
||||
containerNames = builtins.attrNames (lib.filterAttrs (appName: app: app.sops) config.syscfg.server.loadedContainers);
|
||||
containerNames = lib.concatMap (app: app.requires.secrets) (builtins.attrValues config.syscfg.server.loadedContainers);
|
||||
allApps = lib.unique (listNames ++ containerNames);
|
||||
in{
|
||||
sops.secrets = {
|
||||
|
||||
@@ -3,16 +3,32 @@ let
|
||||
|
||||
in with lib; {
|
||||
domain = mkOption { type = types.str; };
|
||||
mailDomain = mkOption { type = types.str; };
|
||||
mailServer = mkOption { type = types.str; };
|
||||
mail = {
|
||||
domain = mkOption { type = types.str; default = null;};
|
||||
server = mkOption { type = types.str; default = null;};
|
||||
|
||||
configPath = mkOption {
|
||||
type = types.str;
|
||||
default = "/media/config";
|
||||
};
|
||||
dataPath = mkOption {
|
||||
type = types.str;
|
||||
default = "/media/data";
|
||||
|
||||
path = mkOption {
|
||||
type = types.submodule {
|
||||
freeformType = types.attrsOf types.str;
|
||||
options = {
|
||||
config = mkOption { type = types.str; default = "/media/config"; };
|
||||
data = mkOption { type = types.str; default = "/media/data"; };
|
||||
download = mkOption { type = types.str; default = "/media/data/download"; };
|
||||
cloud = mkOption { type = types.str; default ="/media/media/cloud"; };
|
||||
film = mkOption { type = types.str; default ="/media/media/film"; };
|
||||
book = mkOption { type = types.str; default ="/media/media/book"; };
|
||||
manga = mkOption { type = types.str; default ="/media/media/manga"; };
|
||||
photo = mkOption { type = types.str; default ="/media/media/photo"; };
|
||||
# music = mkOption { type = types.str; default ="/media/media/music"; };
|
||||
|
||||
dlComplete = mkOption { type = types.str; default ="/media/download/complete"; };
|
||||
dlIncomplete = mkOption { type = types.str; default ="/media/download/incomplete"; };
|
||||
dlConverted = mkOption { type = types.str; default ="/media/download/converted"; };
|
||||
};
|
||||
};
|
||||
default = {};
|
||||
};
|
||||
|
||||
colorScheme = mkOption {
|
||||
@@ -24,18 +40,44 @@ in with lib; {
|
||||
type = lib.types.attrsOf (lib.types.submodule ({ name, ... }: {
|
||||
options = {
|
||||
name = lib.mkOption {type = lib.types.str; default = name;};
|
||||
sops = lib.mkOption {type = lib.types.bool; default = false;};
|
||||
db = lib.mkOption {type = lib.types.bool; default = false;};
|
||||
requires = {
|
||||
secrets = lib.mkOption {
|
||||
type = lib.types.listOf lib.types.str;
|
||||
default = [ ];
|
||||
};
|
||||
databases = lib.mkOption {
|
||||
type = lib.types.listOf lib.types.str;
|
||||
default = [ ];
|
||||
};
|
||||
};
|
||||
|
||||
exports = {
|
||||
authentik = {
|
||||
blueprints = lib.mkOption {
|
||||
type = lib.types.listOf lib.types.str;
|
||||
default = [ ];
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
runtime = {
|
||||
paths = lib.mkOption {type = lib.types.listOf lib.types.attrs; default = [ ];};
|
||||
containers = lib.mkOption {type = lib.types.attrsOf lib.types.attrs; default = { };};
|
||||
vm = lib.mkOption {type = lib.types.nullOr lib.types.attrs; default = null;};
|
||||
cron = lib.mkOption {type = lib.types.listOf lib.types.str; default = [ ];};
|
||||
|
||||
setup = {
|
||||
setup = lib.mkOption {
|
||||
type = lib.types.submodule {
|
||||
options = {
|
||||
trigger = lib.mkOption {type = lib.types.str; default = "";};
|
||||
script = lib.mkOption {type = lib.types.nullOr lib.types.package; default = null;};
|
||||
envFile = lib.mkOption {type = with lib.types; coercedTo str (x: [x]) (listOf str); default = [];};
|
||||
envFile = lib.mkOption {
|
||||
type = with lib.types; coercedTo str (x: [x]) (listOf str);
|
||||
default = [ ];
|
||||
};
|
||||
};
|
||||
};
|
||||
default = { };
|
||||
};
|
||||
};
|
||||
};
|
||||
}));
|
||||
|
||||
@@ -27,8 +27,6 @@
|
||||
# user = ...
|
||||
# ...
|
||||
# };
|
||||
mailDomain = "test@helcel";
|
||||
mailServer = "infomaniak.ch";
|
||||
|
||||
containers = {
|
||||
# ===== BASE =====
|
||||
|
||||
Reference in New Issue
Block a user