Compare commits
27 Commits
cd4c727255
...
e1a80bb7ce
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e1a80bb7ce | ||
| 7d95ba04a9 | |||
| 9169205357 | |||
| 74721f6b09 | |||
| 668c0107f9 | |||
| 331291c54d | |||
| d10f53e485 | |||
| 82aea8268f | |||
| 050eaedca2 | |||
| be9cb270aa | |||
| a5e0e96b52 | |||
| 4366232f18 | |||
| 4398b1d888 | |||
| c4b5c47aa4 | |||
| ff64e6c231 | |||
| e7d656141a | |||
| cf3c2428fb | |||
| a2dc050b1c | |||
| 8bf332caf2 | |||
| 20d3786547 | |||
| 79422c180a | |||
| 65fc9c6df2 | |||
| a59cbd13a3 | |||
| 5f04ef7ae5 | |||
| 0aff508cda | |||
| 30df106b94 | |||
| 3abdb6d637 |
44
modules/server/containers/apps/.template.nix
Normal file
44
modules/server/containers/apps/.template.nix
Normal file
@@ -0,0 +1,44 @@
|
||||
{ config, containerCfg, pkgs, lib, builder, name,... }:
|
||||
let
|
||||
serverCfg = config.syscfg.server;
|
||||
image = pkgs.dockerTools.streamLayeredImage {
|
||||
name = "EXAMPLE";
|
||||
tag = "0.0.0";
|
||||
contents = [ pkgs.bashInteractive ];
|
||||
config = {
|
||||
Entrypoint = [ "echo 1" ];
|
||||
ExposedPorts = { };
|
||||
};
|
||||
};
|
||||
templateData = builder.mkData { name = "template"; dir = "template"; vars = {
|
||||
_ARGUMENT = "template";
|
||||
};
|
||||
};
|
||||
in {
|
||||
paths = [{
|
||||
path="${serverCfg.configPath}/example/";
|
||||
mode = "0444";
|
||||
}];
|
||||
|
||||
containers = {
|
||||
server = builder.mkContainer {
|
||||
subdomain = containerCfg.subdomain;
|
||||
imageStream = image;
|
||||
port = 8080;
|
||||
secret = name;
|
||||
extraEnv = { };
|
||||
overrides = {
|
||||
cmd = [ ];
|
||||
volumes = [ ];
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
setup = {
|
||||
trigger = "server";
|
||||
envFile = config.sops.secrets."EXAMPLE".path;
|
||||
script = pkgs.writeShellScript "setup" ''
|
||||
...
|
||||
'';
|
||||
};
|
||||
}
|
||||
@@ -2,3 +2,7 @@
|
||||
|
||||
RSS: TTRSS / FreshRSS
|
||||
Monitoring: Telegraf + InfluxDB
|
||||
https://github.com/tarampampam/error-pages ?
|
||||
|
||||
- JellyFin external mkData for config (system.xml)
|
||||
- Transmission Cfg and API/Token handling
|
||||
|
||||
@@ -10,6 +10,8 @@ let
|
||||
};
|
||||
};
|
||||
in {
|
||||
sops = true;
|
||||
db = true;
|
||||
paths = [{
|
||||
path="${serverCfg.configPath}/authentik/media";
|
||||
owner = "1000:1000";
|
||||
@@ -25,7 +27,6 @@ in {
|
||||
subdomain = containerCfg.subdomain;
|
||||
image = "ghcr.io/goauthentik/server:${version}";
|
||||
port = 9000;
|
||||
ip = containerCfg.ip;
|
||||
secret = name;
|
||||
extraEnv = {
|
||||
"AUTHENTIK_REDIS__HOST" = builder.host;
|
||||
|
||||
@@ -3,12 +3,12 @@ let
|
||||
version = "latest";
|
||||
serverCfg = config.syscfg.server;
|
||||
in {
|
||||
sops = true;
|
||||
containers = {
|
||||
server = builder.mkContainer {
|
||||
subdomain = containerCfg.subdomain;
|
||||
image = "collabora/code:${version}";
|
||||
port = 9980;
|
||||
ip = containerCfg.ip;
|
||||
secret = name;
|
||||
extraEnv = {
|
||||
"aliasgroup1" = "https://${serverCfg.containers.nextcloud.subdomain}.${serverCfg.hostDomain}";
|
||||
|
||||
@@ -13,6 +13,7 @@ let
|
||||
};
|
||||
};
|
||||
in {
|
||||
sops = true;
|
||||
paths = [{
|
||||
path="${serverCfg.dataPath}/ethercalc/";
|
||||
mode = "0666";
|
||||
@@ -23,7 +24,6 @@ in {
|
||||
subdomain = containerCfg.subdomain;
|
||||
imageStream = image;
|
||||
port = 8080;
|
||||
ip = containerCfg.ip;
|
||||
secret = name;
|
||||
extraEnv = {
|
||||
ETHERCALC_PORT = "8080";
|
||||
|
||||
@@ -76,6 +76,8 @@ let
|
||||
};
|
||||
};
|
||||
in {
|
||||
sops = true;
|
||||
db = true;
|
||||
paths = [{
|
||||
path="${serverCfg.configPath}/etherpad/";
|
||||
mode = "0444";
|
||||
@@ -86,7 +88,6 @@ in {
|
||||
subdomain = containerCfg.subdomain;
|
||||
imageStream = image;
|
||||
port = 8080;
|
||||
ip = containerCfg.ip;
|
||||
secret = name;
|
||||
extraEnv = {
|
||||
TITLE = "Pad";
|
||||
|
||||
@@ -3,7 +3,8 @@ let
|
||||
version = "latest";
|
||||
serverCfg = config.syscfg.server;
|
||||
in {
|
||||
|
||||
sops = true;
|
||||
db = true;
|
||||
paths = [{
|
||||
path="${serverCfg.dataPath}/gitea/data";
|
||||
owner = "1000:1000";
|
||||
@@ -18,7 +19,6 @@ in {
|
||||
subdomain = containerCfg.subdomain;
|
||||
image = "gitea/gitea:${version}";
|
||||
port = 8080;
|
||||
ip = containerCfg.ip;
|
||||
secret = name;
|
||||
|
||||
extraEnv = { # app.ini -> GITEA__<section>__<KEY> = "<VALUE>";
|
||||
|
||||
3
modules/server/containers/apps/immich.nix
Normal file
3
modules/server/containers/apps/immich.nix
Normal file
@@ -0,0 +1,3 @@
|
||||
{...}:{
|
||||
|
||||
}
|
||||
@@ -1,3 +1,58 @@
|
||||
{...}:{
|
||||
|
||||
{ config, containerCfg, pkgs, lib, builder, name, ... }:
|
||||
let
|
||||
serverCfg = config.syscfg.server;
|
||||
image = pkgs.dockerTools.streamLayeredImage {
|
||||
name = pkgs.jellyfin.name;
|
||||
tag = pkgs.jellyfin.version;
|
||||
contents = [
|
||||
pkgs.cacert
|
||||
];
|
||||
config = {
|
||||
Entrypoint = [ "${pkgs.jellyfin}/bin/jellyfin" ];
|
||||
ExposedPorts = { "8096/tcp" = { }; };
|
||||
};
|
||||
};
|
||||
in {
|
||||
paths = [
|
||||
{
|
||||
path = "${serverCfg.dataPath}/media/";
|
||||
mode = "0755";
|
||||
}
|
||||
{
|
||||
path = "${serverCfg.configPath}/jellyfin/";
|
||||
mode = "0755";
|
||||
}
|
||||
];
|
||||
|
||||
containers = {
|
||||
server = builder.mkContainer {
|
||||
subdomain = containerCfg.subdomain;
|
||||
imageStream = image;
|
||||
port = 8096;
|
||||
# secret = name;
|
||||
extraEnv = {
|
||||
DOTNET_SYSTEM_GLOBALIZATION_INVARIANT = "1";
|
||||
# JELLYFIN_WEB_DIR = "${pkgs.jellyfin-web}/share/jellyfin-web";
|
||||
JELLYFIN_HttpListenerHost__BindAddress= "0.0.0.0"; #we can use settings.xml override
|
||||
};
|
||||
extraOptions = [
|
||||
"--tmpfs=/tmp:rw,noexec,nosuid,size=512m"
|
||||
];
|
||||
overrides = {
|
||||
cmd = [
|
||||
"--datadir" "/config/data"
|
||||
"--cachedir" "/config/cache"
|
||||
"--configdir" "/config/config"
|
||||
"--logdir" "/config/log"
|
||||
];
|
||||
volumes = [
|
||||
"${serverCfg.dataPath}/movies:/media/movies:ro"
|
||||
"${serverCfg.dataPath}/series:/media/series:ro"
|
||||
"${serverCfg.configPath}/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" ];
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
@@ -3,6 +3,8 @@ let
|
||||
version = "31";
|
||||
serverCfg = config.syscfg.server;
|
||||
in {
|
||||
sops = true;
|
||||
db = true;
|
||||
paths = [{
|
||||
path="${serverCfg.dataPath}/nextcloud/www";
|
||||
owner = "33:33";
|
||||
@@ -19,7 +21,6 @@ in {
|
||||
subdomain = containerCfg.subdomain;
|
||||
image = "nextcloud:${version}";
|
||||
port = 80;
|
||||
ip = containerCfg.ip;
|
||||
secret = name;
|
||||
extraEnv = {
|
||||
REDIS_HOST = builder.host;
|
||||
|
||||
@@ -1,3 +1,92 @@
|
||||
{...}:{
|
||||
|
||||
{ config, containerCfg, pkgs, lib, builder, name,... }:
|
||||
let
|
||||
version= "latest";
|
||||
serverCfg = config.syscfg.server;
|
||||
settings = pkgs.writeText"settings.yml" (pkgs.lib.generators.toYAML {}{
|
||||
use_default_settings = true;
|
||||
brand = {
|
||||
issue_url = "";
|
||||
docs_url = "";
|
||||
public_instances = "";
|
||||
wiki_url = "";
|
||||
custom = {
|
||||
links = {
|
||||
"Home" = "https://${serverCfg.hostDomain}";
|
||||
# "Status" = "https://status.${serverCfg.hostDomain}";
|
||||
};
|
||||
};
|
||||
pwa_colors = {
|
||||
theme_color_light = "${serverCfg.colorScheme.palette.base0C}";
|
||||
background_color_light = "${serverCfg.colorScheme.palette.base07}";
|
||||
theme_color_dark = "${serverCfg.colorScheme.palette.base0C}";
|
||||
background_color_dark = "${serverCfg.colorScheme.palette.base02}";
|
||||
theme_color_black = "${serverCfg.colorScheme.palette.base0C}";
|
||||
background_color_black = "${serverCfg.colorScheme.palette.base01}";
|
||||
};
|
||||
};
|
||||
general = {
|
||||
debug = false;
|
||||
instance_name = if containerCfg.extra ? instanceName then containerCfg.extra.instanceName else "SearXNG";
|
||||
privacypolicy_url = false;
|
||||
donation_url = false;
|
||||
contact_url = false;
|
||||
enable_metrics = false;
|
||||
};
|
||||
search = {
|
||||
safe_search = 0;
|
||||
autocomplete = if containerCfg.extra ? autocomplete then containerCfg.extra.autocomplete else "";
|
||||
languages = [ "all" "en" "en-US" "ja" "de-CH" "fr-CH" "nb" ];
|
||||
};
|
||||
server = {
|
||||
# secret_key = ""; SET BY ENV VAR
|
||||
};
|
||||
ui = {
|
||||
default_locale = if containerCfg.extra ? defaultLocale then containerCfg.extra.defaultLocale else "en";
|
||||
# query_in_title = "true";
|
||||
#default_theme = "custom";
|
||||
custom_css = "footer { display: none !important; }";
|
||||
};
|
||||
# categories_as_tabs = {
|
||||
# general = {};
|
||||
# images ={};
|
||||
# videos = {};
|
||||
# news = {};
|
||||
# files = {};
|
||||
# };
|
||||
plugins = {
|
||||
"searx.plugins.infinite_scroll.SXNGPlugin".active = true;
|
||||
"searx.plugins.tracker_url_remover.SXNGPlugin".active = true;
|
||||
};
|
||||
});
|
||||
in {
|
||||
sops = true;
|
||||
# paths = [{
|
||||
# path="${serverCfg.dataPath}/searxng/";
|
||||
# mode = "0444";
|
||||
# }];
|
||||
|
||||
containers = {
|
||||
server = builder.mkContainer {
|
||||
subdomain = containerCfg.subdomain;
|
||||
image = "searxng/searxng:${version}";
|
||||
port = 8080;
|
||||
secret = name;
|
||||
extraEnv = {
|
||||
SEARXNG_BASE_URL = "https://${containerCfg.subdomain}.${serverCfg.hostDomain}";
|
||||
SEARXNG_PORT = "8080";
|
||||
SEARXNG_BIND_ADDRESS = "[::]";
|
||||
SEARXNG_PUBLIC_INSTANCE = "false";
|
||||
SEARXNG_SETTINGS_PATH = "/etc/searxng/settings.yml";
|
||||
#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/"
|
||||
];
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
@@ -1,3 +1,73 @@
|
||||
{...}:{
|
||||
|
||||
{ config, containerCfg, pkgs, lib, builder, name, ... }:
|
||||
let
|
||||
serverCfg = config.syscfg.server;
|
||||
|
||||
mkServarrImage = appName: appPkg: binaryPath: pkgs.dockerTools.streamLayeredImage {
|
||||
name = appPkg.name;
|
||||
tag = appPkg.version;
|
||||
contents = with pkgs; [ cacert openssl ];
|
||||
config = {
|
||||
Cmd = [ "${appPkg}/${binaryPath}" "-nobrowser" "-data=/config" ];
|
||||
Env = [ "DOTNET_SYSTEM_GLOBALIZATION_INVARIANT=1" ];
|
||||
};
|
||||
};
|
||||
|
||||
images = {
|
||||
prowlarr = mkServarrImage "prowlarr" pkgs.prowlarr "bin/Prowlarr";
|
||||
radarr = mkServarrImage "radarr" pkgs.radarr "bin/Radarr";
|
||||
sonarr = mkServarrImage "sonarr" pkgs.sonarr "bin/Sonarr";
|
||||
bazarr = mkPythonImage "bazarr" pkgs.bazarr "bin/bazarr";
|
||||
lidarr = mkServarrImage "lidarr" pkgs.lidarr "bin/Lidarr";
|
||||
readarr = mkServarrImage "readarr" pkgs.readarr "bin/Readarr";
|
||||
};
|
||||
|
||||
sharedVolumes = [
|
||||
"${serverCfg.mediaPath or "/mnt/media"}:/media" # Fast hardlinking requires a single shared root
|
||||
"${serverCfg.configPath}/servarr:/config-root"
|
||||
];
|
||||
in {
|
||||
# Initialize atomic configuration structures
|
||||
paths = [
|
||||
{ path = "${serverCfg.configPath}/servarr/prowlarr"; mode = "0755"; }
|
||||
{ path = "${serverCfg.configPath}/servarr/radarr"; mode = "0755"; }
|
||||
{ path = "${serverCfg.configPath}/servarr/sonarr"; mode = "0755"; }
|
||||
];
|
||||
|
||||
containers = {
|
||||
prowlarr = builder.mkContainer {
|
||||
subdomain = containerCfg.subdomain;
|
||||
subpath = "prowlarr";
|
||||
imageStream = images.prowlarr;
|
||||
port = 9696;
|
||||
secret = name;
|
||||
overrides.volumes = sharedVolumes ++ [ "${serverCfg.configPath}/servarr/prowlarr:/config" ];
|
||||
};
|
||||
|
||||
radarr = builder.mkContainer {
|
||||
subdomain = containerCfg.subdomain;
|
||||
subpath = "radarr";
|
||||
imageStream = images.radarr;
|
||||
port = 7878;
|
||||
secret = name;
|
||||
overrides.volumes = sharedVolumes ++ [ "${serverCfg.configPath}/servarr/radarr:/config" ];
|
||||
};
|
||||
|
||||
sonarr = builder.mkContainer {
|
||||
subdomain = containerCfg.subdomain
|
||||
subpath = "sonarr";
|
||||
imageStream = images.sonarr;
|
||||
port = 8989;
|
||||
secret = name;
|
||||
overrides.volumes = sharedVolumes ++ [ "${serverCfg.configPath}/servarr/sonarr:/config" ];
|
||||
};
|
||||
};
|
||||
|
||||
# setup = {
|
||||
# trigger = "prowlarr"; # Triggers atomic environment verification on main controller
|
||||
# envFile = config.sops.secrets."SERVARR".path;
|
||||
# script = pkgs.writeShellScript "setup-servarr" ''
|
||||
# echo "Validating multi-container path permission nodes..."
|
||||
# # mkdir -p ${serverCfg.configPath}/servarr/{prowlarr,radarr,sonarr}
|
||||
# '';
|
||||
# };
|
||||
}
|
||||
@@ -11,6 +11,7 @@ let
|
||||
};
|
||||
};
|
||||
in {
|
||||
sops = true;
|
||||
paths = [{
|
||||
path="${serverCfg.configPath}/traefik";
|
||||
owner = "1000:1000";
|
||||
@@ -21,7 +22,6 @@ in {
|
||||
server = builder.mkContainer {
|
||||
imageStream = image;
|
||||
subdomain = containerCfg.subdomain;
|
||||
ip = containerCfg.ip;
|
||||
port = 8080;
|
||||
secret = name;
|
||||
extraLabels = {
|
||||
@@ -55,15 +55,19 @@ in {
|
||||
"--entrypoints.web.http.redirections.entrypoint.scheme=https"
|
||||
"--entrypoints.web-secure.transport.respondingtimeouts.readtimeout=0s"
|
||||
"--entrypoints.web-secure.proxyprotocol.trustedips=127.0.0.1/32,192.168.1.1/16,10.10.0.0/16"
|
||||
] ++ (if containerCfg.extra ? provider then [
|
||||
] ++ (if serverCfg.containers ? umami then [
|
||||
"--experimental.plugins.umami-feeder.moduleName=github.com/astappiev/traefik-umami-feeder"
|
||||
"--experimental.plugins.umami-feeder.version=v1.4.1"
|
||||
"--entrypoints.web-secure.http.middlewares=umami-global@docker"
|
||||
] else []) ++ (if containerCfg.extra ? provider then [
|
||||
"--certificatesresolvers.default.acme.email=acme@${serverCfg.hostDomain}"
|
||||
"--certificatesresolvers.default.acme.dnschallenge=true"
|
||||
"--certificatesresolvers.default.acme.dnschallenge.provider=${containerCfg.extra.provider}"
|
||||
"--certificatesresolvers.default.acme.storage=/custom/acme.json"
|
||||
] else (if serverCfg.hostDomain != "localhost" then [
|
||||
] else []) ++ (if serverCfg.hostDomain != "localhost" then [
|
||||
"--certificatesresolvers.default.acme.httpchallenge=false"
|
||||
"--certificatesresolvers.default.acme.tlschallenge=true"
|
||||
] else [ ]));
|
||||
] else []);
|
||||
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"
|
||||
|
||||
@@ -1,3 +1,57 @@
|
||||
{...}:{
|
||||
|
||||
{ config, containerCfg, pkgs, lib, builder, name, ... }:
|
||||
let
|
||||
serverCfg = config.syscfg.server;
|
||||
image = pkgs.dockerTools.streamLayeredImage {
|
||||
name = pkgs.transmission_4.name;
|
||||
tag = pkgs.transmission_4.version;
|
||||
contents = [ pkgs.cacert ];
|
||||
config = {
|
||||
Cmd = [ "${pkgs.transmission_4}/bin/transmission-daemon" "--foreground" "--config-dir" "/config" ];
|
||||
ExposedPorts = {
|
||||
"9091/tcp" = {};
|
||||
"51413/tcp" = {}; "51413/udp" = {};
|
||||
};
|
||||
};
|
||||
};
|
||||
in {
|
||||
paths = [{
|
||||
path = "${serverCfg.dataPath}/transmission/complete";
|
||||
owner = "1000:1000";
|
||||
mode = "0755";
|
||||
}{
|
||||
path = "${serverCfg.dataPath}/transmission/incomplete";
|
||||
owner = "1000:1000";
|
||||
mode = "0755";
|
||||
}{
|
||||
path = "${serverCfg.dataPath}/transmission/config";
|
||||
owner = "1000:1000";
|
||||
mode = "0755";
|
||||
}];
|
||||
|
||||
containers = {
|
||||
server = builder.mkContainer {
|
||||
subdomain = containerCfg.subdomain;
|
||||
imageStream = image;
|
||||
port = 9091;
|
||||
|
||||
extraEnv = {
|
||||
PUID = "1000";
|
||||
PGID = "1000";
|
||||
TZ = "Europe/Zurich";
|
||||
};
|
||||
extraLabels = { } // (if serverCfg.containers ? authentik then {
|
||||
"traefik.http.routers.${containerCfg.subdomain}.middlewares" = "authentik";
|
||||
} else {});
|
||||
|
||||
overrides = {
|
||||
cmd = [ ];
|
||||
volumes = [
|
||||
"${serverCfg.dataPath}/transmission/complete:/downloads/complete"
|
||||
"${serverCfg.dataPath}/transmission/incomplete:/downloads/incomplete"
|
||||
"${serverCfg.dataPath}/transmission/config:/config"
|
||||
];
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
}
|
||||
@@ -1,3 +1,58 @@
|
||||
{...}:{
|
||||
|
||||
{ config, containerCfg, pkgs, lib, builder, name,... }:
|
||||
let
|
||||
serverCfg = config.syscfg.server;
|
||||
|
||||
# Umami image built from nixpkgs
|
||||
image = pkgs.dockerTools.streamLayeredImage {
|
||||
name = pkgs.umami.name;
|
||||
tag = pkgs.umami.version;
|
||||
contents = [ pkgs.cacert ];
|
||||
config = {
|
||||
# Umami in nixpkgs typically provides a binary or script to start the server
|
||||
Entrypoint = [ "${pkgs.umami}/bin/umami-server" ];
|
||||
ExposedPorts = { "3000/tcp" = {}; };
|
||||
Env = [ "NODE_ENV=production" ];
|
||||
};
|
||||
};
|
||||
in {
|
||||
sops = true;
|
||||
db = true;
|
||||
paths = [{
|
||||
path = "${serverCfg.configPath}/umami/";
|
||||
mode = "0444";
|
||||
}];
|
||||
|
||||
containers = {
|
||||
server = builder.mkContainer {
|
||||
subdomain = containerCfg.subdomain;
|
||||
imageStream = image;
|
||||
port = 3000;
|
||||
secret = name;
|
||||
extraEnv = {
|
||||
PORT = "3000";
|
||||
# HOSTNAME = "${containerCfg.subdomain}.${serverCfg.hostDomain}";
|
||||
DATABASE_TYPE = "postgresql";
|
||||
REDIS_URL = "redis://${builder.host}";
|
||||
CLIENT_IP_HEADER = "X-Forwarded-For";
|
||||
BASE_PATH = lib.optionalString (containerCfg.subpath or null != null) "/${containerCfg.subpath}";
|
||||
# DISABLE_LOGIN = "1";#(if serverCfg.containers?authentik then "1" else "0");
|
||||
|
||||
};
|
||||
extraLabels = {
|
||||
"traefik.http.middlewares.umami-global.plugin.umami-feeder.umamiHost" = "http://umami-server:3000";
|
||||
"traefik.http.middlewares.umami-global.plugin.umami-feeder.umamiUsername" = "admin";
|
||||
"traefik.http.middlewares.umami-global.plugin.umami-feeder.umamiPassword" = "umami";
|
||||
"traefik.http.middlewares.umami-global.plugin.umami-feeder.createNewWebsites" = "true";
|
||||
} // ( 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,34 +1,41 @@
|
||||
{ config, lib, pkgs, serverCfg }:
|
||||
let
|
||||
builder =
|
||||
{ image ? null, imageStream ? null
|
||||
{ image ? null, imageStream ? null, imageFile ? null
|
||||
, secret ? null
|
||||
, subdomain ? null, ip ? null, port ? 0
|
||||
, subdomain ? null, subpath?null, port ? 0
|
||||
, extraEnv ? { }, extraLabels ? { }, extraOptions ? [ ]
|
||||
, overrides ? { }
|
||||
}:
|
||||
let base = {
|
||||
let
|
||||
routerName = if subpath != null
|
||||
then "${subdomain}-${lib.strings.sanitizeDerivationName subpath}"
|
||||
else subdomain;
|
||||
base = {
|
||||
image = if imageStream != null then "${imageStream.imageName}:${imageStream.imageTag}"
|
||||
else image;
|
||||
imageStream = imageStream;
|
||||
imageFile = imageFile;
|
||||
|
||||
environmentFiles = if secret!=null then [ config.sops.secrets."${lib.toUpper secret}".path ] else [];
|
||||
environment = {} // extraEnv;
|
||||
|
||||
labels = (if subdomain!=null then ({
|
||||
"traefik.enable" = "true";
|
||||
"traefik.http.routers.${subdomain}.entrypoints" = "web-secure";
|
||||
"traefik.http.routers.${subdomain}.rule" = "Host(`${subdomain}.${serverCfg.hostDomain}`)";
|
||||
"traefik.http.routers.${subdomain}.tls" = "true";
|
||||
"traefik.http.routers.${routerName}.entrypoints" = "web-secure";
|
||||
"traefik.http.routers.${routerName}.rule" = if subpath != null
|
||||
then "Host(`${subdomain}.${serverCfg.hostDomain}`) && PathPrefix(`/${subpath}`)"
|
||||
else "Host(`${subdomain}.${serverCfg.hostDomain}`)";
|
||||
"traefik.http.routers.${routerName}.tls" = "true";
|
||||
} // lib.optionalAttrs (port!=null) {
|
||||
"traefik.http.services.${subdomain}.loadbalancer.server.port" = toString port;
|
||||
"traefik.http.services.${routerName}.loadbalancer.server.port" = toString port;
|
||||
}) else {
|
||||
"traefik.enable" = "false";
|
||||
}) // extraLabels;
|
||||
|
||||
extraOptions = extraOptions ++ [
|
||||
"--add-host=host.containers.internal:host-gateway"
|
||||
] ++ lib.optional (ip!=null) "--ip=${ip}";
|
||||
];
|
||||
};
|
||||
in lib.recursiveUpdate base overrides;
|
||||
in {
|
||||
|
||||
@@ -2,80 +2,77 @@
|
||||
let
|
||||
serverCfg = config.syscfg.server;
|
||||
builder = import ./builder.nix { inherit config lib pkgs serverCfg; };
|
||||
enabledConfigs = lib.filterAttrs (name: c: c.enable) serverCfg.containers;
|
||||
containerSetsList = lib.mapAttrsToList (name: containerCfg:
|
||||
let apps = import (./apps + "/${name}.nix") {inherit config pkgs lib containerCfg builder name;};
|
||||
in{
|
||||
name = name;
|
||||
containers = lib.mapAttrs' (cName: cValue:
|
||||
lib.nameValuePair "${name}-${cName}" cValue
|
||||
) apps.containers;
|
||||
paths = apps.paths or [];
|
||||
setup = apps.setup or null;
|
||||
cron = apps.cron or [];
|
||||
}
|
||||
) enabledConfigs;
|
||||
mergedContainers = lib.attrsets.mergeAttrsList (lib.map(e: e.containers) containerSetsList);
|
||||
allPathConfigs = lib.flatten (lib.map (e: e.paths) containerSetsList);
|
||||
allCronsConfigs = lib.flatten (lib.map (e: e.cron or []) containerSetsList);
|
||||
in
|
||||
{
|
||||
config = lib.mkIf ( enabledConfigs != {} ) {
|
||||
|
||||
virtualisation.oci-containers = {
|
||||
backend = "podman";
|
||||
containers = mergedContainers;
|
||||
};
|
||||
|
||||
system.activationScripts.container-setup-dirs = {
|
||||
deps = [ "users" "groups" ];
|
||||
text = lib.concatStringsSep "\n" (map (cfg:
|
||||
let
|
||||
effectiveCfg = {
|
||||
owner = "root:root";
|
||||
mode = "0400";
|
||||
} // cfg;
|
||||
in ''
|
||||
${pkgs.coreutils}/bin/mkdir -p "${effectiveCfg.path}"
|
||||
${pkgs.coreutils}/bin/chown ${effectiveCfg.owner} "${effectiveCfg.path}"
|
||||
${pkgs.coreutils}/bin/chmod ${effectiveCfg.mode} "${effectiveCfg.path}"
|
||||
'') allPathConfigs);
|
||||
};
|
||||
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;
|
||||
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;
|
||||
allCronsConfigs = lib.concatMap (app: app.cron) appsList;
|
||||
in{
|
||||
|
||||
systemd.services = {
|
||||
podman-gc = {
|
||||
description = "Podman garbage collection";
|
||||
serviceConfig.Type = "oneshot";
|
||||
script = ''
|
||||
${pkgs.podman}/bin/podman container prune -f
|
||||
${pkgs.podman}/bin/podman image prune -f
|
||||
'';
|
||||
startAt = "weekly";
|
||||
virtualisation.oci-containers = {
|
||||
backend = "podman";
|
||||
containers = mergedContainers;
|
||||
};
|
||||
} // lib.listToAttrs (lib.concatMap (containerSet:
|
||||
if containerSet.setup != null then [{
|
||||
name = "${containerSet.name}-setup";
|
||||
value = {
|
||||
description = "Run ${containerSet.name} setup";
|
||||
after = [ "podman-${containerSet.name}-${containerSet.setup.trigger}.service" ];
|
||||
wants = [ "podman-${containerSet.name}-${containerSet.setup.trigger}.service" ];
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
serviceConfig = {
|
||||
Type = "oneshot";
|
||||
TimeoutStartSec = "360s";
|
||||
EnvironmentFile = if (containerSet.setup ? envFile) then containerSet.setup.envFile else [ ];
|
||||
ExecStart = "${containerSet.setup.script}";
|
||||
RemainAfterExit = true;
|
||||
User = "root";
|
||||
};
|
||||
|
||||
system.activationScripts.container-setup-dirs = {
|
||||
deps = [ "users" "groups" ];
|
||||
text = lib.concatStringsSep "\n" (map (cfg:
|
||||
let
|
||||
effectiveCfg = {
|
||||
owner = "root:root";
|
||||
mode = "0400";
|
||||
} // cfg;
|
||||
in ''
|
||||
${pkgs.coreutils}/bin/mkdir -p "${effectiveCfg.path}"
|
||||
${pkgs.coreutils}/bin/chown ${effectiveCfg.owner} "${effectiveCfg.path}"
|
||||
${pkgs.coreutils}/bin/chmod ${effectiveCfg.mode} "${effectiveCfg.path}"
|
||||
'') allPathConfigs);
|
||||
};
|
||||
|
||||
systemd.services = {
|
||||
podman-gc = {
|
||||
description = "Podman garbage collection";
|
||||
serviceConfig.Type = "oneshot";
|
||||
script = ''
|
||||
${pkgs.podman}/bin/podman container prune -f
|
||||
${pkgs.podman}/bin/podman image prune -f
|
||||
'';
|
||||
startAt = "weekly";
|
||||
};
|
||||
}] else []
|
||||
) containerSetsList);
|
||||
} // lib.listToAttrs (lib.concatMap (containerSet:
|
||||
if containerSet.setup.script != null then [{
|
||||
name = "${containerSet.name}-setup";
|
||||
value = {
|
||||
description = "Run ${containerSet.name} setup";
|
||||
after = [ "podman-${containerSet.name}-${containerSet.setup.trigger}.service" ];
|
||||
wants = [ "podman-${containerSet.name}-${containerSet.setup.trigger}.service" ];
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
serviceConfig = {
|
||||
Type = "oneshot";
|
||||
TimeoutStartSec = "360s";
|
||||
EnvironmentFile = if (containerSet.setup ? envFile) then containerSet.setup.envFile else [ ];
|
||||
ExecStart = "${containerSet.setup.script}";
|
||||
RemainAfterExit = true;
|
||||
User = "root";
|
||||
};
|
||||
};
|
||||
}] else []
|
||||
) appsList);
|
||||
|
||||
services.cron = {
|
||||
enable = true;
|
||||
systemCronJobs = allCronsConfigs;
|
||||
};
|
||||
services.cron = {
|
||||
enable = true;
|
||||
systemCronJobs = allCronsConfigs;
|
||||
};
|
||||
|
||||
}))];
|
||||
|
||||
};
|
||||
}
|
||||
@@ -1,14 +1,10 @@
|
||||
|
||||
{ config, lib, pkgs, ... }:
|
||||
let
|
||||
|
||||
listNames = config.syscfg.server.db;
|
||||
|
||||
containerNames = lib.mapAttrsToList
|
||||
(name: cfg: name)
|
||||
(lib.filterAttrs (name: cfg: cfg.db or false) config.syscfg.server.containers);
|
||||
|
||||
containerNames = builtins.attrNames (lib.filterAttrs (appName: app: app.db) config.syscfg.server.loadedContainers);
|
||||
allApps = lib.unique (listNames ++ containerNames);
|
||||
|
||||
in {
|
||||
config = lib.mkIf ( builtins.length allApps > 0) {
|
||||
services.postgresql = {
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
{ config, lib, pkgs, ... }:
|
||||
let
|
||||
listNames = config.syscfg.server.db;
|
||||
containerNames = lib.mapAttrsToList (name: cfg: name)
|
||||
(lib.filterAttrs (name: cfg: ((cfg.db or false) || (cfg.sops or false))) config.syscfg.server.containers);
|
||||
containerNames = builtins.attrNames (lib.filterAttrs (appName: app: app.sops) config.syscfg.server.loadedContainers);
|
||||
allApps = lib.unique (listNames ++ containerNames);
|
||||
in{
|
||||
sops.secrets = {
|
||||
|
||||
@@ -26,3 +26,9 @@ GITEA: |
|
||||
GITEA__database__PASSWD=...
|
||||
GITEA__security__SECRET_KEY=...
|
||||
GITEA__security__INTERNAL_TOKEN=...
|
||||
SEARXNG: |
|
||||
SEARXNG_SECRET=...
|
||||
UMAMI: |
|
||||
DB_PASSWORD=...
|
||||
DATABASE_URL=postgresql://username:mypassword@localhost:5432/mydb
|
||||
APP_SECRET=...
|
||||
|
||||
@@ -6,6 +6,8 @@ COLLABORA: ENC[AES256_GCM,data:cLGEziks5dyxTF1jugfpQE0l0nSkDP7MpROzCxCM94jv49sgu
|
||||
ETHERPAD: ENC[AES256_GCM,data:PSr06GyOgY0HDNC4Hr2XUjbNUszGlfBjxDbrrKNQOqSMSVfZj4iFIGamrS72WO0un4U7IENx0T6CTBN/ELoq7J/+W9zf879uzKWuNaAulLVtBqrUbbqA7hTJpidnveZXzdwZRvlz/bU8kWAmXyhiDb2Q42Sz3BDb6duM3PO1AgG8Ko1pi2IemCPjO3uzudeT8FAlO8NnCUxKgwIKSz8CodOXFVGk66NX4xJd4ycfdNYXvKBNlzt1+WuWsZeZzeWmF7WD2dt4wWA9fWxB90fnth6ZV5LdeXjyYnzwkFOWoyNazgqV4jBv+aXKVwX4fYvspu13cVdrak3gc698bS2N1guDss4A/sfXMbtaYPGm98xXkqz1LP7sXQzKUdZf9sAS9gtOVv2tmg==,iv:uQ0Roe+XefzMjZCF3It+U2D1MWPMT5f6CPwlz0gQ5W0=,tag:wSgp0CVr6Y6M3eqcoTy8cw==,type:str]
|
||||
ETHERCALC: ENC[AES256_GCM,data:0ScnDsUNBt6wYJC4hTXn8huuTptBTDKZV4yFVQ4fuBWc6auWNWhDQlTc0ImJoK6efr2uyp3sVu3o+KlCNvUGhDOJ1you6socyTgRP0q7oLPC+Ln+bFP8gWG8v2nyEFY=,iv:YqvVjBFG/WZg1l4aMAiioOruWZ9zcTMr74DVW+1+2DQ=,tag:ePBXd4ddipJtxhFE1amfMg==,type:str]
|
||||
GITEA: ENC[AES256_GCM,data:TGsye52g8DVOk51o1dWfF6x3m6BFPe0MtUbOayxYejaYSZ4cDCfx02EPAhiL3FJGLfidZt7+WpjhVqJvFeCvJ1OXdYMQyuL3akPBCmEjmBgBhJvEjVtVgV3aNMS21gy3o0RG/MXDXOLpjHeaXn3G/XWKsv5bw+gg94bDirOguLC5eaFxddn5/UGFvfwXzDmkoNmc9zufGvVpUkRy8rju/TjOz4Q5GZk1gXWtJWdkTGhuVYVBDDHIQq9DBS0qXi8tP3FvY8prOi/c5ZbyyZjTOgNpWB9uU4HkHz4aUTMFIrPFwUeWmNMIdyUmarSQ7tDDdhBfIiLhb94jaMATHq+PfwwpCcmiTfBEG3OS/3SXPMWg6jhfUxvxsKNT2HQca31B9IRqlitaio3r6KEPBTYh2nWtFO9d5Is7TUWkGsOaV+0JSiNPNh5uD7kNyBxsKUKcND7JXMxW/TZOqARY64x6IwDrbcypsyMW5i+4Er1/0HCvZ7FBH1XkTul8vBGF5ZGD/tYp/m6Ld26GKYkj967eYIwlNFcOMGNue5PyJfFCq0qWbLWO9dFA9c2e9r81DCD8y/0S3Ts7X7TkXVGShm7JoMqb8dzg9i6CoNlmbPAM5GwoNV3ftQugvqEGMk5UIvf05YsgSNvq4UJbhsT4bZqpV0plnxYD5TswCGF/XQ3nwwFTudmf1OLcgYwM2NckbVui128o1Rw=,iv:vo6l0QirLIUvwLN675LYkffkXejJecvBesLJvoW/bjY=,tag:zyLyiCskF84A3QVoq5X3iw==,type:str]
|
||||
SEARXNG: ENC[AES256_GCM,data:gtKhEmMemzLRl4c3cYhMAQ+5vUth1IhWQeLvW1YtaG5TbhQHBR4PDREQOlGt+tlfGQrft+FeNhMSN/SKOp8gmScVWa+9qmltzxRGRpLm3m/VuBZvOlGdeUcKAX8zEH6A,iv:B2UEtjTRIjT6W+tH2gtcl6XMvZNgbvZUXTiBePGOu24=,tag:SHIF6eaWBLwy9RrEy1N9kg==,type:str]
|
||||
UMAMI: ENC[AES256_GCM,data:O3kQ6YTWH3xbu4Tkpyh2S0HZvqymUUDDYQbN3I6TX3OUxoNZcogPn+X8AY9FoaS2/amqo0X4YCQCimEgCfdXqknydmMD5x957H5Lc/XyYxB9zk6DIdU9gN6yO4uZClG34TqOsjpjZkExivykNsTzaFfPRcmCz1EVXpY4GVAAKNWxmr7M/99bnT6mSE8zQUj0g/gskCeWGP4bRbpMFtvPOvGChmwjSoMDp5GmYdISiZsacHSv0Zp0o9XSYBWbux4ePHcFvWP+alnToY0oF9g+NJPyzj2X1ihtbcZxgLLHyfGkI5uYKNsuUjB9K+D8u1xLE2AGRPyBrRQPZftSw/Zu1brIpz13HicDbJkR+0zmWBxG1WsTnyhIbIn12o2lwO6CVPLWhuRIx5hv7xm8hTfBdOwsVZZfXCr/ZWkERSzQhp/yDN2Fq5IpyZHdhmMnpkkg1G1oiWtN,iv:7HPZ7b6OlxCoXSkdDlLNpQT1xkF0Uj8IYs+Cx701CYU=,tag:+PFDVpzkbd2tM5JKnNpIUw==,type:str]
|
||||
sops:
|
||||
age:
|
||||
- recipient: age1sxzuhh2fcd4pmaz4mdqq95t683d32ft22w9t2r7pk258u0s8wymsqdj7lg
|
||||
@@ -26,8 +28,8 @@ sops:
|
||||
S1NaTVFTL0FCdm1EQmRsUnlhclZNZlEKEgIe60qkvY8+UocjQU+WM2dTL/1y3Kqk
|
||||
d4RrlLP9NSozwVsPYI4ntygvMSApbT4v0YvoO7gV90lkGWEvW1YDfA==
|
||||
-----END AGE ENCRYPTED FILE-----
|
||||
lastmodified: "2026-05-11T22:33:41Z"
|
||||
mac: ENC[AES256_GCM,data:276HHpEW56HOvKKbNPM79QrEBYDM590bOLfsgssSb79jm+LzrgLlYk2QImmXArADWby4Ai4jBPL4EahNm+a3aBazMEbwAu+EorvORE2P12W5C1ztskx5XUI3yDKY96jlZvmpXsqefa2pOQc1USk8ai/Obd5MLK06kMr2w3a7P9s=,iv:NJoe1lvw1hrWNL79Ux065UkSEDEEc0+NqlqB4tk3mAw=,tag:YTjIvEP1BO69Pa0qispMLQ==,type:str]
|
||||
lastmodified: "2026-05-12T19:20:38Z"
|
||||
mac: ENC[AES256_GCM,data:j/fFN/zTHHSbH+RUdu/wK80Gu+qfoVDiVSDQWrBfL1Orezohf3hlGWJrXu8UtYa82CRVJ5BHzp589GQJTgI8pMaDirbQfpRA6jnYvLaWIU0lN66cnyZ8x919Lc67ceZPqih1q8CDCjRG40NZSwOpRqQVqpJMiuZjFaJqec0BDMM=,iv:7QIA0DfLPmXOjKvbsquYQIWqXbyPGWa+SLCEHH7IawU=,tag:jNFpqDDKF3mUQclpmwvGQg==,type:str]
|
||||
pgp:
|
||||
- created_at: "2026-05-05T23:46:27Z"
|
||||
enc: |-
|
||||
|
||||
@@ -5,161 +5,9 @@ let
|
||||
(name: type: type == "directory" && builtins.pathExists (systemsDir + "/${name}/cfg.nix"))
|
||||
(builtins.readDir systemsDir));
|
||||
|
||||
userOpt = with lib; {
|
||||
username = mkOption { type = types.str; };
|
||||
pubssh = mkOption { type = types.str; default=""; };
|
||||
wm = mkOption {
|
||||
type = types.enum [ "Wayland" "X11" "-" ];
|
||||
default = "-";
|
||||
};
|
||||
git = {
|
||||
username = mkOption { type = types.str; default = "Anonymous";};
|
||||
email = mkOption { type = types.str; default = "anonymous@domain"; };
|
||||
key = mkOption { type = types.nullOr types.str; default=null; };
|
||||
};
|
||||
};
|
||||
netOpt = with lib; {
|
||||
ble = {
|
||||
enable = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
};
|
||||
};
|
||||
wlp = {
|
||||
enable = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
};
|
||||
nif = mkOption {
|
||||
type = types.str;
|
||||
default = "";
|
||||
};
|
||||
};
|
||||
wg = {
|
||||
enable = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
};
|
||||
ip4 = mkOption {
|
||||
type = types.str;
|
||||
default = "";
|
||||
};
|
||||
ip6 = mkOption {
|
||||
type = types.str;
|
||||
default = "";
|
||||
};
|
||||
pubkey = mkOption {
|
||||
type = types.str;
|
||||
default = "";
|
||||
};
|
||||
};
|
||||
};
|
||||
makeOpt = with lib; {
|
||||
cli = mkOption {
|
||||
type = types.bool;
|
||||
default = true;
|
||||
};
|
||||
gui = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
};
|
||||
virt = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
};
|
||||
power = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
};
|
||||
game = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
};
|
||||
develop = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
};
|
||||
};
|
||||
serverOpt = with lib; {
|
||||
hostDomain = mkOption { type = types.str; };
|
||||
mailDomain = mkOption { type = types.str; };
|
||||
mailServer = mkOption { type = types.str; };
|
||||
|
||||
configPath = mkOption {
|
||||
type = types.str;
|
||||
default = "/media/config";
|
||||
};
|
||||
dataPath = mkOption {
|
||||
type = types.str;
|
||||
default = "/media/data";
|
||||
};
|
||||
|
||||
colorScheme = mkOption {
|
||||
#type = types.submodule {
|
||||
# options = {
|
||||
# slug = mkOption { type = types.str; };
|
||||
# name = mkOption { type = types.str; };
|
||||
# palette = mkOption {
|
||||
type = types.attrs; #default = {};# };
|
||||
#};
|
||||
# };
|
||||
default = (lib.evalModules { modules =[ { freeformType = with lib.types; attrsOf anything; } ../colors ];}).config.colorScheme ;
|
||||
};
|
||||
containers = mkOption {
|
||||
type = types.attrsOf (types.submodule {
|
||||
options = {
|
||||
enable = mkOption { type = types.bool;default = false; };
|
||||
db = mkOption { type = types.bool;default = false; };
|
||||
sops = mkOption { type = types.bool;default = false; };
|
||||
ip = mkOption { type = types.nullOr types.str; default = null;};
|
||||
subdomain = mkOption { type = types.nullOr types.str; default=null;};
|
||||
port = mkOption { type = types.nullOr types.port; default = null; };
|
||||
extra = mkOption { type = types.attrs; default = {}; };
|
||||
};
|
||||
});
|
||||
default = {};
|
||||
};
|
||||
openssh = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
};
|
||||
wireguard = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
};
|
||||
web = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
};
|
||||
ipfw = {
|
||||
enable = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
};
|
||||
ifs = mkOption {
|
||||
type = types.listOf types.str;
|
||||
default = [ ];
|
||||
};
|
||||
ports = mkOption {
|
||||
type = types.listOf (types.listOf (types.oneOf [ types.str types.int ]));
|
||||
default = [];
|
||||
description = "Forwarding rules: [ [srcInterface dstAddr srcPort dstPort] ... ]";
|
||||
example = [
|
||||
[ "ens3" "10.10.1.2" "IPV6" 22 2222 ]
|
||||
[ "ens3" "10.10.1.2" "IPV6" 80 80 ]
|
||||
[ "ens3" "10.10.1.2" "IPV6" 443 443 ]
|
||||
];
|
||||
};
|
||||
};
|
||||
|
||||
db = mkOption {
|
||||
type = types.listOf (types.str);
|
||||
default = [ ];
|
||||
};
|
||||
|
||||
};
|
||||
in with lib; {
|
||||
options.usercfg = userOpt;
|
||||
options.usercfg = import ./user.nix {inherit lib;};
|
||||
options.syscfg = {
|
||||
hostname = mkOption { type = types.str; };
|
||||
type = mkOption {
|
||||
@@ -171,20 +19,17 @@ in with lib; {
|
||||
default = "x86_64-linux";
|
||||
};
|
||||
defaultUser = mkOption { type = types.str; };
|
||||
make = makeOpt;
|
||||
net = netOpt;
|
||||
make = import ./make.nix {inherit lib;};
|
||||
net = import ./net.nix {inherit lib;};
|
||||
users = mkOption {
|
||||
type = types.listOf (types.submodule { options = userOpt; });
|
||||
type = types.listOf (types.submodule { options = import ./user.nix {inherit lib;}; });
|
||||
default = [ ];
|
||||
};
|
||||
peers = mkOption {
|
||||
default = map (name: import (systemsDir + "/${name}/cfg.nix")) systemNames;
|
||||
};
|
||||
server = mkOption {
|
||||
type = types.oneOf [
|
||||
types.bool
|
||||
(types.submodule { options = serverOpt; })
|
||||
];
|
||||
type = types.oneOf [ types.bool (types.submodule { options = import ./server.nix {inherit lib;}; }) ];
|
||||
default = false;
|
||||
};
|
||||
};
|
||||
|
||||
9
modules/shared/syscfg/make.nix
Normal file
9
modules/shared/syscfg/make.nix
Normal file
@@ -0,0 +1,9 @@
|
||||
{ lib,... }:
|
||||
with lib; {
|
||||
cli = mkOption { type = types.bool; default = true; };
|
||||
gui = mkOption { type = types.bool; default = false; };
|
||||
virt = mkOption { type = types.bool; default = false; };
|
||||
power = mkOption { type = types.bool; default = false; };
|
||||
game = mkOption { type = types.bool; default = false; };
|
||||
develop = mkOption { type = types.bool; default = false; };
|
||||
}
|
||||
14
modules/shared/syscfg/net.nix
Normal file
14
modules/shared/syscfg/net.nix
Normal file
@@ -0,0 +1,14 @@
|
||||
{ lib,... }:
|
||||
with lib; {
|
||||
ble.enable = mkOption { type = types.bool; default = false; };
|
||||
wlp = {
|
||||
enable = mkOption { type = types.bool; default = false; };
|
||||
nif = mkOption { type = types.str; default = ""; };
|
||||
};
|
||||
wg = {
|
||||
enable = mkOption { type = types.bool; default = false; };
|
||||
ip4 = mkOption { type = types.str; default = ""; };
|
||||
ip6 = mkOption { type = types.str; default = ""; };
|
||||
pubkey = mkOption { type = types.str; default = ""; };
|
||||
};
|
||||
}
|
||||
92
modules/shared/syscfg/server.nix
Normal file
92
modules/shared/syscfg/server.nix
Normal file
@@ -0,0 +1,92 @@
|
||||
{ lib,... }:
|
||||
let
|
||||
|
||||
in with lib; {
|
||||
hostDomain = mkOption { type = types.str; };
|
||||
mailDomain = mkOption { type = types.str; };
|
||||
mailServer = mkOption { type = types.str; };
|
||||
|
||||
configPath = mkOption {
|
||||
type = types.str;
|
||||
default = "/media/config";
|
||||
};
|
||||
dataPath = mkOption {
|
||||
type = types.str;
|
||||
default = "/media/data";
|
||||
};
|
||||
|
||||
colorScheme = mkOption {
|
||||
type = types.attrs;
|
||||
default = (lib.evalModules { modules =[ { freeformType = with lib.types; attrsOf anything; } ../colors ];}).config.colorScheme ;
|
||||
};
|
||||
loadedContainers = lib.mkOption {
|
||||
readOnly = true;
|
||||
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;};
|
||||
|
||||
paths = lib.mkOption {type = lib.types.listOf lib.types.attrs; default = [ ];};
|
||||
containers = lib.mkOption {type = lib.types.attrsOf lib.types.attrs; default = { };};
|
||||
cron = lib.mkOption {type = lib.types.listOf lib.types.str; default = [ ];};
|
||||
|
||||
setup = {
|
||||
trigger = lib.mkOption {type = lib.types.str; default = "";};
|
||||
script = lib.mkOption {type = lib.types.nullOr lib.types.package; default = null;};
|
||||
envFile = lib.mkOption {type = lib.types.nullOr lib.types.str; default = null;};
|
||||
};
|
||||
};
|
||||
}));
|
||||
|
||||
};
|
||||
containers = mkOption {
|
||||
type = types.attrsOf (types.submodule {
|
||||
options = {
|
||||
subdomain = mkOption { type = types.nullOr types.str; default=null;};
|
||||
subpath = mkOption { type = types.nullOr types.str; default=null;};
|
||||
port = mkOption { type = types.nullOr types.port; default = null; };
|
||||
extra = mkOption { type = types.attrs; default = {}; };
|
||||
};
|
||||
});
|
||||
default = {};
|
||||
};
|
||||
openssh = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
};
|
||||
wireguard = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
};
|
||||
web = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
};
|
||||
ipfw = {
|
||||
enable = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
};
|
||||
ifs = mkOption {
|
||||
type = types.listOf types.str;
|
||||
default = [ ];
|
||||
};
|
||||
ports = mkOption {
|
||||
type = types.listOf (types.listOf (types.oneOf [ types.str types.int ]));
|
||||
default = [];
|
||||
description = "Forwarding rules: [ [srcInterface dstAddr srcPort dstPort] ... ]";
|
||||
example = [
|
||||
[ "ens3" "10.10.1.2" "IPV6" 22 2222 ]
|
||||
[ "ens3" "10.10.1.2" "IPV6" 80 80 ]
|
||||
[ "ens3" "10.10.1.2" "IPV6" 443 443 ]
|
||||
];
|
||||
};
|
||||
};
|
||||
|
||||
db = mkOption {
|
||||
type = types.listOf (types.str);
|
||||
default = [ ];
|
||||
};
|
||||
|
||||
}
|
||||
14
modules/shared/syscfg/user.nix
Normal file
14
modules/shared/syscfg/user.nix
Normal file
@@ -0,0 +1,14 @@
|
||||
{ lib,... }:
|
||||
with lib; {
|
||||
username = mkOption { type = types.str; };
|
||||
pubssh = mkOption { type = types.str; default=""; };
|
||||
wm = mkOption {
|
||||
type = types.enum [ "Wayland" "X11" "-" ];
|
||||
default = "-";
|
||||
};
|
||||
git = {
|
||||
username = mkOption { type = types.str; default = "Anonymous";};
|
||||
email = mkOption { type = types.str; default = "anonymous@domain"; };
|
||||
key = mkOption { type = types.nullOr types.str; default=null; };
|
||||
};
|
||||
}
|
||||
@@ -29,37 +29,44 @@
|
||||
containers = {
|
||||
|
||||
traefik = {
|
||||
enable = true;
|
||||
sops = true;
|
||||
subdomain = "traefik";
|
||||
extra={provider="infomaniak";};
|
||||
};
|
||||
authentik = {
|
||||
enable = true;
|
||||
db = true;
|
||||
subdomain = "sso";
|
||||
port = 9000;
|
||||
};
|
||||
nextcloud = {
|
||||
enable = true;
|
||||
db = true;
|
||||
subdomain = "cloud";
|
||||
};
|
||||
collabora = {
|
||||
enable = true;
|
||||
sops = true;
|
||||
subdomain = "office";
|
||||
};
|
||||
etherpad = {
|
||||
enable = true;
|
||||
db = true;
|
||||
subdomain = "pad";
|
||||
};
|
||||
ethercalc = {
|
||||
subdomain = "pad";
|
||||
};
|
||||
gitea = {
|
||||
enable = true;
|
||||
db = true;
|
||||
subdomain = "git";
|
||||
};
|
||||
searxng = {
|
||||
subdomain = "searx";
|
||||
};
|
||||
jellyfin = {
|
||||
subdomain = "flix";
|
||||
};
|
||||
transmission = {
|
||||
subdomain = "rflix";
|
||||
subpath = "p2p";
|
||||
};
|
||||
servarr = {
|
||||
subdomain = "arr";
|
||||
};
|
||||
umami = {
|
||||
subdomain = "umami";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user