diff --git a/flake.nix b/flake.nix index e2360cd..b32ff86 100755 --- a/flake.nix +++ b/flake.nix @@ -17,19 +17,11 @@ inputs.nixpkgs.follows = "nixpkgs"; }; - # hyprland = { - # url = "github:hyprwm/Hyprland"; - # inputs.nixpkgs.follows = "nixpkgs"; - # }; sops-nix = { url = "github:Mic92/sops-nix"; inputs.nixpkgs.follows = "nixpkgs"; }; nix-colors.url = "github:misterio77/nix-colors"; - - arion.url = "github:hercules-ci/arion"; - arion.inputs.nixpkgs.follows = "nixpkgs"; - }; outputs = inputs: diff --git a/generator.nix b/generator.nix index 42285bf..7428017 100755 --- a/generator.nix +++ b/generator.nix @@ -13,7 +13,6 @@ ./modules/nixos syscfg ./systems/${host} - inputs.arion.nixosModules.arion inputs.sops-nix.nixosModules.sops inputs.home-manager.nixosModules.home-manager { diff --git a/modules/server/containers/default.nix b/modules/server/containers/default.nix index 421dea4..97cbb9c 100644 --- a/modules/server/containers/default.nix +++ b/modules/server/containers/default.nix @@ -9,10 +9,12 @@ let containers = lib.mapAttrs' (cName: cValue: lib.nameValuePair "${name}-${cName}" cValue ) defs.containers; + paths = defs.paths or []; } ) enabledConfigs; mergedContainers = lib.attrsets.mergeAttrsList (lib.map(e: e.containers) containerSetsList); - allPathConfigs = lib.flatten (lib.map (e: e.paths or []) containerSetsList); + allPathConfigs = lib.flatten (lib.map (e: e.paths) containerSetsList); + allScriptConfigs = lib.flatten (lib.map (e: e.init or "") containerSetsList); in { config = lib.mkIf ( enabledConfigs != {} ) { @@ -35,9 +37,9 @@ in system.activationScripts.container-setup-dirs = { deps = [ "users" "groups" ]; text = lib.concatStringsSep "\n" (map (cfg: '' - mkdir -p "${cfg.path}" - chown ${cfg.owner} "${cfg.path}" - chmod ${cfg.mode} "${cfg.path}" + ${pkgs.coreutils}/bin/mkdir -p "${cfg.path}" + ${pkgs.coreutils}/bin/chown ${cfg.owner} "${cfg.path}" + ${pkgs.coreutils}/bin/chmod ${cfg.mode} "${cfg.path}" '') allPathConfigs); }; }; diff --git a/modules/server/containers/defs/authentik.nix b/modules/server/containers/defs/authentik.nix index 0b1557e..a1b30ce 100644 --- a/modules/server/containers/defs/authentik.nix +++ b/modules/server/containers/defs/authentik.nix @@ -4,11 +4,11 @@ version = "2026.2.2"; serverCfg = config.syscfg.server; in { paths = [{ - path="${serverCfg.dataPath}/authentik/media"; + path="${serverCfg.configPath}/authentik/media"; owner = "1000:1000"; mode = "0755"; }{ - path="${serverCfg.dataPath}/authentik/templates"; + path="${serverCfg.configPath}/authentik/templates"; owner = "1000:1000"; mode = "0755"; }]; @@ -39,8 +39,8 @@ in { cmd = [ "server" ]; ports = if containerCfg.pubPort != 0 && containerCfg.port != 0 then [ "${toString containerCfg.pubPort}:${toString containerCfg.port}" ] else []; volumes = [ - "${serverCfg.dataPath}/authentik/media:/media" - "${serverCfg.dataPath}/authentik/templates:/templates" + "${serverCfg.configPath}/authentik/media:/media" + "${serverCfg.configPath}/authentik/templates:/templates" ]; }; }; @@ -60,8 +60,8 @@ in { overrides = { cmd = [ "worker" ]; volumes = [ - "${serverCfg.dataPath}/authentik/media:/media" - "${serverCfg.dataPath}/authentik/templates:/templates" + "${serverCfg.configPath}/authentik/media:/media" + "${serverCfg.configPath}/authentik/templates:/templates" # "/var/run/podman/podman.sock:/var/run/docker.sock" #PODMAN GROUP FOR SOCKET ACCESS ]; }; diff --git a/modules/server/containers/defs/cloud.nix b/modules/server/containers/defs/cloud.nix deleted file mode 100644 index 77f734a..0000000 --- a/modules/server/containers/defs/cloud.nix +++ /dev/null @@ -1,152 +0,0 @@ -{ config, pkgs, lib, ... }: -let serverCfg = config.syscfg.server; -in { - project.name = "cloud"; - - networks = { - internal = { - name = lib.mkForce "internal"; - internal = true; - }; - external = { - name = lib.mkForce "external"; - internal = false; - }; - }; - - services = { - - cloud_nextcloud.service = { - image = "nextcloud:27"; - container_name = "cloud"; - restart = "unless-stopped"; - networks = [ "external" ]; - volumes = [ - "${serverCfg.configPath}/data/nextcloud:/var/www/html" - "${serverCfg.dataPath}/data/music:/media/music" - "${serverCfg.dataPath}/data/video:/media/video" - "${serverCfg.dataPath}/data/photo:/media/photo" - ]; - tmpfs = [ "/tmp" ]; - labels = { - "traefik.enable" = "true"; - "traefik.http.routers.nextcloud.entrypoints" = "web-secure"; - "traefik.http.routers.nextcloud.rule" = - "Host(`cloud.${serverCfg.hostDomain}`)"; - "traefik.http.routers.nextcloud.tls" = "true"; - "traefik.http.routers.nextcloud.middlewares" = - "sts_headers,nextcloud-caldav"; - - "traefik.http.middlewares.nextcloud-caldav.redirectregex.permanent" = - "true"; - "traefik.http.middlewares.nextcloud-caldav.redirectregex.regex" = - "^https://(.*)/.well-known/(card|cal)dav"; - "traefik.http.middlewares.nextcloud-caldav.redirectregex.replacement" = - "https://$\${1}/remote.php/dav/"; - "traefik.http.middlewares.sts_headers.headers.stsSeconds" = "15552000"; - "traefik.http.middlewares.sts_headers.headers.stsIncludeSubdomains" = - "true"; - }; - }; - - cloud_office.service = { - image = "collabora/code:latest"; - container_name = "cloud_office"; - restart = "unless-stopped"; - networks = [ "external" ]; - volumes = [ ]; - environment = { - username = "COLLABORA_USER"; - password = "COLLABORA_PASSWORD"; - aliasgroup1 = "https://cloud.${serverCfg.hostDomain}"; - server_name = "office.${serverCfg.hostDomain}"; - VIRTUAL_HOST = "office.${serverCfg.hostDomain}"; - VIRTUAL_PORT = "9980"; - VIRTUAL_PROTO = "http"; - DONT_GEN_SSL_CERT = "true"; - RESOLVE_TO_PROXY_IP = "true"; - NETWORK_ACCESS = "internal"; - extra_params = "--o:ssl.enable=false --o:ssl.termination=true"; - dictionaries = "en fr de jp"; - }; - labels = { - "traefik.enable" = "true"; - "traefik.http.routers.collabora.entrypoints" = "web-secure"; - "traefik.http.routers.collabora.rule" = - "Host(`office.${serverCfg.hostDomain}`)"; - "traefik.http.routers.collabora.tls" = "true"; - }; - }; - - cloud_etherpad.service = { - image = "etherpad/etherpad:latest"; - container_name = "etherpad"; - restart = "unless-stopped"; - networks = [ "external" ]; - volumes = [ - "${serverCfg.dataPath}/ether/etherpad/data:/opt/etherpad-lite/var" - "${serverCfg.dataPath}/ether/etherpad/APIKEY.txt:/opt/etherpad-lite/APIKEY.txt" - ]; - environment = { - NODE_ENV = "production"; - TITLE = "Helcel-Pad"; - DB_TYPE = "mysql"; - DB_HOST = serverCfg.dbHost; - DB_PORT = serverCfg.dbPort; - DB_NAME = "etherpad"; - DB_USER = "ETHERPAD_DB_USER"; - DB_PASS = "ETHERPAD_DB_PASSWORD"; - DB_CHARSET = "utf8mb4"; - DEFAULT_PAD_TEXT = "P A D"; - PAD_OPTIONS_SHOW_LINE_NUMBERS = "true"; - PAD_OPTIONS_USE_MONOSPACE_FONT = "true"; - ADMIN_PASSWORD = "ETHERPAD_ADMIN_PASSWORD"; - SKIN_VARIANTS = "super-dark-toolbar light-editor dark-background"; - }; - labels = { - "traefik.enable" = "true"; - "traefik.http.routers.etherpad.entrypoints" = "web-secure"; - "traefik.http.routers.etherpad.rule" = - "Host(`pad.${serverCfg.hostDomain}`)"; - "traefik.http.routers.etherpad.tls" = "true"; - }; - }; - - cloud_ethercalc.service = { - image = "audreyt/ethercalc:latest"; - container_name = "ethercalc"; - restart = "unless-stopped"; - networks = [ "external" "internal" ]; - volumes = [ - "${serverCfg.dataPath}/ether/etherpad/data:/opt/etherpad-lite/var" - "${serverCfg.dataPath}/ether/etherpad/APIKEY.txt:/opt/etherpad-lite/APIKEY.txt" - ]; - environment = { - NODE_ENV = "production"; - TITLE = "Helcel-Calc"; - REDIS_PORT_6379_TCP_ADDR = "ethercalc-redis"; - REDIS_PORT_6379_TCP_PORT = "6379"; - ADMIN_PASSWORD = "ETHERPAD_ADMIN_PASSWORD"; - SKIN_VARIANTS = "super-dark-toolbar light-editor dark-background"; - }; - labels = { - "traefik.enable" = "true"; - "traefik.http.routers.ethercalc.entrypoints" = "web-secure"; - "traefik.http.routers.ethercalc.rule" = - "Host(`calc.${serverCfg.hostDomain}`)"; - "traefik.http.routers.ethercalc.tls" = "true"; - }; - }; - - cloud_redis.service = { - image = "redis:latest"; - container_name = "ethercalc-redis"; - restart = "unless-stopped"; - networks = [ "internal" ]; - volumes = [ "${serverCfg.dataPath}/ether/ethercalc/redis:/data" ]; - environment = { }; - labels = { "traefik.enable" = "false"; }; - }; - - }; -} diff --git a/modules/server/containers/defs/collabora.nix b/modules/server/containers/defs/collabora.nix new file mode 100644 index 0000000..7b6f145 --- /dev/null +++ b/modules/server/containers/defs/collabora.nix @@ -0,0 +1,35 @@ +{ config, containerCfg, pkgs, lib, builder, ... }: +let +version = "latest"; +serverCfg = config.syscfg.server; +in { + containers = { + server = builder.mkContainer { + subdomain = containerCfg.subdomain; + image = "collabora/code:${version}"; + port = containerCfg.port; + ip = containerCfg.ip; + secret = "collabora"; + extraEnv = { + "username" = "COLLABORA_USER"; + "password" = "COLLABORA_PASSWORD"; + "aliasgroup1" = "https://${serverCfg.containers.nextcloud.subdomain}.${serverCfg.hostDomain}"; + "server_name" = "${containerCfg.subdomain}.${serverCfg.hostDomain}"; + "VIRTUAL_HOST" = "${containerCfg.subdomain}.${serverCfg.hostDomain}"; + "VIRTUAL_PORT" = "${containerCfg.port}"; + "VIRTUAL_PROTO" = "http"; + "DONT_GEN_SSL_CERT" = "true"; + "RESOLVE_TO_PROXY_IP" = "true"; + "extra_params" = "--o:ssl.enable=false --o:ssl.termination=true"; + "dictionaries" = "en fr de jp no"; + }; + + overrides = { + volumes = [ + "${pkgs.noto-fonts}/share/fonts/noto:/opt/collaboraoffice/share/fonts/truetype/noto:ro" + "${pkgs.ibm-plex}/share/fonts/opentype:/opt/collaboraoffice/share/fonts/opentype/plex:ro" + ]; + }; + }; + }; +} diff --git a/modules/server/containers/defs/etherpad.nix b/modules/server/containers/defs/etherpad.nix new file mode 100644 index 0000000..acc1e7d --- /dev/null +++ b/modules/server/containers/defs/etherpad.nix @@ -0,0 +1,49 @@ +{ config, containerCfg, pkgs, lib, builder, ... }: +let +version = "latest"; +serverCfg = config.syscfg.server; +in { + paths = [{ + path="${serverCfg.dataPath}/etherpad/data"; + owner = "1000:1000"; + mode = "0755"; + }{ + path="${serverCfg.dataPath}/etherpad/APIKEY.txt"; + owner = "1000:1000"; + mode = "0755"; + backup = true; + }]; + + containers = { + server = builder.mkContainer { + subdomain = containerCfg.subdomain; + image = "etherpad/etherpad:${version}"; + port = containerCfg.port; + ip = containerCfg.ip; + secret = "etherpad"; + extraEnv = { + NODE_ENV = "production"; + TITLE = "Pad"; + PORT = toString containerCfg.port; + DB_TYPE = "postgres"; + DB_HOST = builder.host; + DB_NAME = "etherpad_db"; + DB_USER = "etherpad_user"; + DB_PASS = "ETHERPAD_DB_PASSWORD"; + ADMIN_PASSWORD = "ETHERPAD_ADMIN_PASSWORD"; + "TRUST_PROXY" = "true"; + DB_CHARSET = "utf8mb4"; + DEFAULT_PAD_TEXT = ""; + PAD_OPTIONS_SHOW_LINE_NUMBERS = "true"; + PAD_OPTIONS_USE_MONOSPACE_FONT = "true"; + SKIN_VARIANTS = "super-dark-toolbar light-editor dark-background"; + }; + overrides = { + volumes = [ + "${serverCfg.dataPath}/etherpad/data:/opt/etherpad-lite/var" + "${serverCfg.dataPath}/etherpad/APIKEY.txt:/opt/etherpad-lite/APIKEY.txt" + ]; + }; + }; + }; +} diff --git a/modules/server/containers/defs/nextcloud.nix b/modules/server/containers/defs/nextcloud.nix new file mode 100644 index 0000000..47071b6 --- /dev/null +++ b/modules/server/containers/defs/nextcloud.nix @@ -0,0 +1,56 @@ +{ config, containerCfg, pkgs, lib, builder, ... }: +let +version = "27"; +serverCfg = config.syscfg.server; +in { + paths = [{ + path="${serverCfg.dataPath}/nextcloud/www"; + owner = "1000:1000"; + mode = "0755"; + }{ + path="${serverCfg.dataPath}/nextcloud/data"; + owner = "1000:1000"; + mode = "0755"; + backup = true; + }]; + + containers = { + server = builder.mkContainer { + subdomain = containerCfg.subdomain; + image = "nextcloud:${version}"; + port = containerCfg.port; + ip = containerCfg.ip; + secret = "nextcloud"; + extraEnv = { + "REDIS_HOST" = builder.host; + "POSTGRES_HOST" = builder.host; + "POSTGRES_USER" = "nextcloud_user"; + "POSTGRES_DB" = "nextcloud_db"; + "NEXTCLOUD_TRUSTED_DOMAINS " = "${containerCfg.subdomain}.${serverCfg.hostDomain}"; + "SMTP_HOST" = ${serverCfg.mailServer}; + "SMTP_NAME" = "mail_user"; + "SMTP_PASSWORD" = "mail_password"; + "MAIL_FROM_ADDRESS" = "${containerCfg.subdomain}@${serverCfg.hostDomain}"; + "MAIL_DOMAIN" = ${serverCfg.mailDomain}; + "TRUSTED_PROXIES" = "..."; + }; + extraLabels = { + "traefik.http.routers.${containerCfg.subdomain}.middlewares" = "sts_headers,${containerCfg.subdomain}-caldav"; + "traefik.http.middlewares.${containerCfg.subdomain}-caldav.redirectregex.permanent" = "true"; + "traefik.http.middlewares.${containerCfg.subdomain}-caldav.redirectregex.regex" = "^https://(.*)/.well-known/(card|cal)dav"; + "traefik.http.middlewares.${containerCfg.subdomain}-caldav.redirectregex.replacement" = "https://$\${1}/remote.php/dav/"; + "traefik.http.middlewares.sts_headers.headers.stsSeconds" = "15552000"; + "traefik.http.middlewares.sts_headers.headers.stsIncludeSubdomains" = "true"; + }; + overrides = { + ports = if containerCfg.pubPort != 0 && containerCfg.port != 0 then [ "${toString containerCfg.pubPort}:${toString containerCfg.port}" ] else []; + volumes = [ + "${serverCfg.dataPath}/nextcloud/www:/var/www/html" + "${serverCfg.dataPath}/nextcloud/data:/var/www/html/data" + ]; + tmpfs = [ "/tmp" ]; + }; + }; + + }; +} diff --git a/modules/server/containers/defs/sample.nix b/modules/server/containers/defs/sample.nix deleted file mode 100644 index 1a20639..0000000 --- a/modules/server/containers/defs/sample.nix +++ /dev/null @@ -1,30 +0,0 @@ -{ config, pkgs, lib, ... }: -let serverCfg = config.syscfg.server; -in { - project.name = "name"; - - networks = { - internal = { - name = lib.mkForce "internal"; - internal = true; - }; - external = { - name = lib.mkForce "external"; - internal = false; - }; - }; - - services = { - - NAME.service = { - image = "NAME:latest"; - container_name = "NAME"; - restart = "unless-stopped"; - networks = [ "internal" ]; - volumes = [ ]; - environment = { }; - labels = { "traefik.enable" = "false"; }; - }; - - }; -} diff --git a/modules/server/containers/defs/traefik.nix b/modules/server/containers/defs/traefik.nix index 903864c..68a208a 100644 --- a/modules/server/containers/defs/traefik.nix +++ b/modules/server/containers/defs/traefik.nix @@ -1,78 +1,41 @@ -{ config, pkgs, ... }: { - project.name = "traefik"; +{ config, containerCfg, pkgs, lib, builder, ... }: +let +version = "2026.2.2"; +serverCfg = config.syscfg.server; +in { + paths = [{ + path="${serverCfg.dataPath}/authentik/media"; + owner = "1000:1000"; + mode = "0755"; + }{ + path="${serverCfg.dataPath}/authentik/templates"; + owner = "1000:1000"; + mode = "0755"; + }]; - networks = { - internal = { - name = lib.mkForce "internal"; - internal = true; - }; - external = { - name = lib.mkForce "external"; - internal = false; - }; - }; - - services = { - - traefik.service = { - image = "traefik:latest"; - container_name = "traefik"; - restart = "unless-stopped"; - networks = [ "internal" "external" ]; - command = [ - "--api" - "--providers.docker=true" - "--entrypoints.web.address=:80" - "--entrypoints.web-secure.address=:443" - ]; - port = [ "443" "80" ]; - volumes = [ - "/var/run/docker.sock:/var/run/docker.sock:ro" - "${serverCfg.configPath}/traefik/traefik.yaml:/etc/traefik/traefik.yaml" - "${serverCfg.configPath}/traefik/access.log:/etc/traefik/access.log" - "${serverCfg.configPath}/traefik/acme.json:/acme.json" - ]; - environment = { + containers = { + server = builder.mkContainer { + subdomain = containerCfg.subdomain; + image = "traefik:${version}"; + port = containerCfg.port; + ip = containerCfg.ip; + extraEnv = { "INFOMANIAK_ACCESS_TOKEN" = config.sops.secrets.INFOMANIAK_API_KEY.path; }; - labels = { "traefik.enable" = "false"; }; - }; - - matomo.service = { - image = "matomo:latest"; - container_name = "matomo"; - restart = "unless-stopped"; - networks = [ "external" ]; - volumes = [ - "/etc/localtime:/etc/localtime:ro" - "${serverCfg.configPath}/matomo:/var/www/html/config:rw" - "${serverCfg.configPath}/traefik/access.log:/var/log/taccess.log:ro" - ]; - environment = { }; - labels = { - "traefik.http.routers.matomo.rule" = - "Host(`matomo.${serverCfg.hostDomain}`)"; - "traefik.http.routers.matomo.entrypoints" = "web-secure"; - "traefik.http.routers.matomo.tls" = "true"; - }; - }; - - searx.service = { - image = "searxng/searxng:latest"; - container_name = "searx"; - restart = "unless-stopped"; - networks = [ "external" ]; - volumes = [ "/etc/localtime:/etc/localtime:ro" ]; - environment = { - "BASE_URL" = "https://searx.${serverCfg.hostDomain}"; - "AUTOCOMPLETE" = "true"; - "INSTANCE_NAME" = "searx${serverCfg.shortName}"; - }; - labels = { - "traefik.http.routers.matomo.rule" = - "Host(`searx.${serverCfg.hostDomain}`)"; - "traefik.http.routers.matomo.entrypoints" = "web-secure"; - "traefik.http.routers.matomo.tls" = "true"; + overrides = { + cmd = [ + "--api" + "--providers.docker=true" + "--entrypoints.web.address=:80" + "--entrypoints.web-secure.address=:443" + ]; + ports = [ "443" "80" ]; + volumes = [ + "/var/run/docker.sock:/var/run/docker.sock:ro" + "${serverCfg.configPath}/traefik/traefik.yaml:/etc/traefik/traefik.yaml" + "${serverCfg.configPath}/traefik/access.log:/etc/traefik/access.log" + "${serverCfg.configPath}/traefik/acme.json:/acme.json" + ]; }; }; diff --git a/modules/server/nftables/default.nix b/modules/server/nftables/default.nix index a69d8aa..2fafad5 100644 --- a/modules/server/nftables/default.nix +++ b/modules/server/nftables/default.nix @@ -1,12 +1,6 @@ { config, lib, ... }: let cfg = config.syscfg.server; - - DBlistNames = config.syscfg.server.db; - DBcontainerNames = lib.mapAttrsToList - (name: cfg: name) - (lib.filterAttrs (name: cfg: cfg.db or false) config.syscfg.server.containers); - DBallApps = lib.unique (DBlistNames ++ DBcontainerNames); in{ boot.kernel.sysctl = { "net.ipv4.ip_forward" = 1; @@ -15,20 +9,6 @@ in{ networking.nftables.enable = true; networking.nftables.ruleset = '' - table inet filter { - chain input { - type filter hook input priority filter; policy drop; - ct state established,related accept - iifname "lo" accept - iifname { "podman*", "veth*" } accept - tcp dport {422, 22} accept - ${if builtins.length DBallApps > 0 then ''tcp dport {5432, 6379} accept'' else ""} - ${if cfg.web then ''tcp dport {80, 443} accept'' else ""} - ${if cfg.web then ''udp dport {80, 443} accept'' else ""} - ${if cfg.wireguard then ''tcp dport {1515} accept'' else ""} - ${if cfg.wireguard then ''udp dport {1515} accept'' else ""} - } - } ${if cfg.nftables.enable then '' table inet nat { chain prerouting { diff --git a/modules/server/sops/example.server.yaml b/modules/server/sops/example.server.yaml new file mode 100644 index 0000000..8f8d81c --- /dev/null +++ b/modules/server/sops/example.server.yaml @@ -0,0 +1,13 @@ +INFOMANIAK_API_KEY: abc +AUTHENTIK: | + DB_PASSWORD=abc + AUTHENTIK_POSTGRESQL__PASSWORD=abc + AUTHENTIK_POSTGRESQL__SSLMODE=disable + AUTHENTIK_SECRET_KEY=abc +NEXTCLOUD: | + DB_PASSWORD=abc + POSTGRES_PASSWORD=abc +ETHERPAD: | + DB_PASSWORD=abc + ETHERPAD_DB_PASSWORD=abc + ETHERPAD_ADMIN_PASSWORD=abc diff --git a/systems/sandbox/cfg.nix b/systems/sandbox/cfg.nix index 4d3f4b0..486ee04 100644 --- a/systems/sandbox/cfg.nix +++ b/systems/sandbox/cfg.nix @@ -40,6 +40,20 @@ port = 9000; pubPort = 9999; }; + collabora = { + enable = true; + db = false; + subdomain = "office"; + ip = "10.88.0.127"; + port = 9980; + }; + etherpad = { + enable = true; + db = true; + subdomain = "pad"; + ip = "10.88.0.128"; + port = 80; + }; }; }; };