diff --git a/hosts/sobotka/server.nix b/hosts/sobotka/server.nix index 02a21b52..33ae668c 100644 --- a/hosts/sobotka/server.nix +++ b/hosts/sobotka/server.nix @@ -1,5 +1,4 @@ -{ config, ... }: -{ +{config, ...}: { server = { enable = true; email = "adam@cnst.dev"; @@ -9,11 +8,6 @@ uid = 994; gid = 993; - mounts = { - fast = "/mnt/user"; - config = "/persist/opt/services"; - }; - unbound = { enable = true; }; @@ -73,6 +67,7 @@ podman = { enable = true; gluetun.enable = true; + dashy.enable = true; qbittorrent = { enable = true; port = 8080; diff --git a/modules/server/caddy/default.nix b/modules/server/caddy/default.nix index 1d56d065..1d52a054 100644 --- a/modules/server/caddy/default.nix +++ b/modules/server/caddy/default.nix @@ -2,43 +2,37 @@ config, lib, ... -}: -let +}: let inherit (lib) mkIf mkEnableOption; cfg = config.server.caddy; - getCloudflareCredentials = - hostname: - if hostname == "ziggy" then - config.age.secrets.cloudflareDnsCredentialsZiggy.path - else if hostname == "sobotka" then - config.age.secrets.cloudflareDnsCredentials.path - else - throw "Unknown hostname: ${hostname}"; - in -{ + getCloudflareCredentials = hostname: + if hostname == "ziggy" + then config.age.secrets.cloudflareDnsCredentialsZiggy.path + else if hostname == "sobotka" + then config.age.secrets.cloudflareDnsCredentials.path + else throw "Unknown hostname: ${hostname}"; +in { options = { server.caddy.enable = mkEnableOption "Enables caddy"; }; config = mkIf cfg.enable { - networking.firewall = - let - ports = [ - 80 - 443 - ]; - in - { - allowedTCPPorts = ports; - }; + networking.firewall = let + ports = [ + 80 + 443 + ]; + in { + allowedTCPPorts = ports; + }; security.acme = { acceptTerms = true; defaults.email = config.server.email; certs.${config.server.domain} = { - reloadServices = [ "caddy.service" ]; + reloadServices = ["caddy.service"]; domain = "${config.server.domain}"; - extraDomainNames = [ "*.${config.server.domain}" ]; + extraDomainNames = ["*.${config.server.domain}"]; dnsProvider = "cloudflare"; dnsResolver = "1.1.1.1:53"; dnsPropagationCheck = true; diff --git a/modules/server/dashy/default.nix b/modules/server/dashy/default.nix index 8b1f72f5..f9bb9ff1 100644 --- a/modules/server/dashy/default.nix +++ b/modules/server/dashy/default.nix @@ -1,11 +1,15 @@ -{ config, lib, ... }: -let +{ + pkgs, + config, + lib, + ... +}: let unit = "dashy"; cfg = config.server.${unit}; srv = config.server; hl = config.server; - mergedServices = hl // (hl.podman or { }); + mergedServices = hl // (hl.podman or {}); dashyCategories = [ "Arr" @@ -15,42 +19,70 @@ let "Smart Home" ]; - getServicesByCategory = - cat: + getServicesByCategory = cat: lib.attrsets.filterAttrs (name: value: (value ? category && value.category == cat)) mergedServices; - mkItems = - services: + # This function was missing its 'services' argument at the end of the call. + mkItems = services: lib.attrsets.mapAttrsToList (name: value: { title = value.name or name; description = value.description or ""; url = - if value ? href then - value.href - else - (if value ? url then "https://${value.url}${value.path or ""}" else ""); + if value ? href + then value.href + else if value ? url + then "https://${value.url}${value.path or ""}" + else ""; icon = value.icon or ""; - }) services; -in -{ + }) + services; # <-- FIX: Added the 'services' argument here. + + esc = s: lib.replaceStrings ["\""] ["\\\""] (toString s); + + renderSection = { + name, + icon, + items, + }: '' + - name: "${esc name}" + icon: "${esc icon}" + items: + ${lib.concatStringsSep "\n" ( + lib.lists.map (item: '' + - title: "${esc item.title}" + description: "${esc item.description}" + url: "${esc item.url}" + icon: "${esc item.icon}" + '') + items + )} + ''; +in { options.server.${unit} = { enable = lib.mkEnableOption { description = "Enable ${unit}"; }; + configFile = lib.mkOption { + type = lib.types.path; + readOnly = true; + internal = true; + description = "Path to the generated Dashy config file."; + }; + misc = lib.mkOption { - default = [ ]; + default = []; type = lib.types.listOf ( lib.types.attrsOf ( lib.types.submodule { options = { - name = lib.mkOption { type = lib.types.str; }; + name = lib.mkOption {type = lib.types.str;}; description = lib.mkOption { type = lib.types.str; default = ""; }; - href = lib.mkOption { type = lib.types.str; }; - icon = lib.mkOption { type = lib.types.str; }; + href = lib.mkOption {type = lib.types.str;}; + icon = lib.mkOption {type = lib.types.str;}; }; } ) @@ -61,72 +93,59 @@ in config = lib.mkIf cfg.enable { services.glances.enable = true; - services.${unit} = { - enable = true; - port = cfg.port or 8081; - extraOptions = [ - "-p" - "${toString config.services.${unit}.port}:80" - ]; + server.dashy.configFile = pkgs.writeText "conf.yml" '' + pageInfo: + title: "${esc "${srv.domain} Homelab"}" + description: "${esc "Homelab made with NixOS"}" + navLinks: + - title: "GitHub" + path: "https://github.com/cnsta/cnix" - settings = { - pageInfo = { - title = "${srv.domain} Homelab"; - description = "Homelab made with NixOS"; - navLinks = [ - { - title = "GitHub"; - path = "https://github.com/cnsta/cnix"; + appConfig: + theme: "material-dark" + layout: "auto" + iconSize: "medium" + language: "en" + statusCheck: true + hideComponents: + hideSettings: false + + sections: + ${lib.concatStringsSep "\n" ( + lib.lists.map ( + cat: + renderSection { + name = cat; + icon = "fas fa-box"; + items = mkItems (getServicesByCategory cat); } - ]; - }; - - appConfig = { - theme = "material-dark"; - layout = "auto"; - iconSize = "medium"; - language = "en"; - statusCheck = true; - hideComponents.hideSettings = false; - }; - - sections = - (lib.lists.forEach dashyCategories (cat: { - name = cat; - icon = "fas fa-box"; # adjust per category - items = mkItems (getServicesByCategory cat); - })) - ++ [ - { - name = "Misc"; - icon = "fas fa-ellipsis-h"; - items = lib.lists.map (x: { - title = x.name; - description = x.description or ""; - url = x.href or ""; - icon = x.icon or ""; - }) cfg.misc; - } - { - name = "Monitoring"; - icon = "fas fa-monitor-heart-rate"; - items = [ - { - title = "Glances"; - url = "http://localhost:${toString config.services.glances.port}"; - icon = "hl-glances"; - } - ]; - } - ]; - }; - }; - - services.caddy.virtualHosts."${srv.domain}" = { - useACMEHost = srv.domain; - extraConfig = '' - reverse_proxy http://127.0.0.1:${toString config.services.${unit}.port} - ''; - }; + ) + dashyCategories + )} + ${renderSection { + name = "Misc"; + icon = "fas fa-ellipsis-h"; + items = + lib.lists.map (x: { + title = x.name; + description = x.description or ""; + url = x.href or ""; + icon = x.icon or ""; + }) + cfg.misc; + }} + ${renderSection { + name = "Monitoring"; + icon = "fas fa-monitor-heart-rate"; + items = [ + { + title = "Glances"; + description = "System Monitoring"; + url = "http://localhost:${toString config.services.glances.port}"; + icon = "hl-glances"; + } + ]; + }} + ''; }; } diff --git a/modules/server/podman/default.nix b/modules/server/podman/default.nix index 71cb6679..fecade3d 100644 --- a/modules/server/podman/default.nix +++ b/modules/server/podman/default.nix @@ -2,32 +2,40 @@ config, lib, ... -}: -let +}: let srv = config.server; cfg = config.server.podman; piholeUrl = - if config.networking.hostName == "sobotka" then - "pihole0" - else if config.networking.hostName == "ziggy" then - "pihole1" - else - throw "Unknown hostname"; + if config.networking.hostName == "sobotka" + then "pihole0" + else if config.networking.hostName == "ziggy" + then "pihole1" + else throw "Unknown hostname"; - getPiholeSecret = - hostname: - if hostname == "ziggy" then - [ config.age.secrets.piholeZiggy.path ] - else if hostname == "sobotka" then - [ config.age.secrets.pihole.path ] - else - throw "Unknown hostname: ${hostname}"; -in -{ + getPiholeSecret = hostname: + if hostname == "ziggy" + then [config.age.secrets.piholeZiggy.path] + else if hostname == "sobotka" + then [config.age.secrets.pihole.path] + else throw "Unknown hostname: ${hostname}"; +in { options.server.podman = { enable = lib.mkEnableOption "Enables Podman"; gluetun.enable = lib.mkEnableOption "Enables gluetun"; + dashy = { + enable = lib.mkEnableOption "Enable dashy"; + port = lib.mkOption { + type = lib.types.int; + default = 8081; + description = "The port to host Dashy on."; + }; + url = lib.mkOption { + type = lib.types.str; + default = "dashy.${srv.domain}"; + }; + }; + qbittorrent = { enable = lib.mkEnableOption "Enable qBittorrent"; url = lib.mkOption { @@ -141,6 +149,15 @@ in }; services.caddy.virtualHosts = lib.mkMerge [ + (lib.mkIf cfg.dashy.enable { + "${cfg.dashy.url}" = { + useACMEHost = srv.domain; + extraConfig = '' + reverse_proxy http://127.0.0.1:${toString cfg.dashy.port} + ''; + }; + }) + (lib.mkIf cfg.qbittorrent.enable { "${cfg.qbittorrent.url}" = { useACMEHost = srv.domain; @@ -181,12 +198,12 @@ in "5031:5031" "50300:50300" ]; - devices = [ "/dev/net/tun:/dev/net/tun" ]; + devices = ["/dev/net/tun:/dev/net/tun"]; autoStart = true; extraOptions = [ "--cap-add=NET_ADMIN" ]; - volumes = [ "/var:/gluetun" ]; + volumes = ["/var:/gluetun"]; environmentFiles = [ config.age.secrets.gluetunEnvironment.path ]; @@ -199,11 +216,22 @@ in }; }) + (lib.mkIf cfg.dashy.enable { + dashy = { + image = "lissy93/dashy:latest"; + autoStart = true; + ports = ["${toString cfg.dashy.port}:80"]; + volumes = [ + "${srv.dashy.configFile}:/app/user-data/conf.yml" + ]; + }; + }) + (lib.mkIf cfg.qbittorrent.enable { qbittorrent = { image = "ghcr.io/hotio/qbittorrent:latest"; autoStart = true; - dependsOn = [ "gluetun" ]; + dependsOn = ["gluetun"]; ports = [ "8080:8080" "58846:58846" @@ -231,7 +259,7 @@ in slskd = { image = "slskd/slskd:latest"; autoStart = true; - dependsOn = [ "gluetun" ]; + dependsOn = ["gluetun"]; ports = [ "5030:5030" "5031:5031"