From b768ad0ca4208e8b3588b881067c43d85246e967 Mon Sep 17 00:00:00 2001 From: Collin Williams <96917990+bluedragon1221@users.noreply.github.com> Date: Fri, 2 Oct 2026 11:23:45 -0500 Subject: experiment with modular services; more unix domain sockets, clean up old code --- modules/services/nixos/btopweb.nix | 119 ++++++++++----- modules/services/nixos/cgit/default.nix | 36 +++-- modules/services/nixos/default.nix | 5 +- modules/services/nixos/dufs.nix | 73 +++++++++ modules/services/nixos/filebrowser.nix | 52 ------- modules/services/nixos/glance.nix | 227 +++++++++++++++++----------- modules/services/nixos/goaccess.nix | 143 +++++++++++------- modules/services/nixos/jta/assignments.html | 148 ------------------ modules/services/nixos/jta/default.nix | 48 ------ modules/services/nixos/jta/go.mod | 5 - modules/services/nixos/jta/go.sum | 2 - modules/services/nixos/jta/index.html | 134 ---------------- modules/services/nixos/jta/main.go | 142 ----------------- modules/services/nixos/jta/md_template.html | 11 -- modules/services/nixos/jta/pkg.nix | 6 - modules/services/nixos/jta/style.css | 172 --------------------- modules/services/nixos/minecraft.nix | 2 +- modules/services/nixos/qbittorrent.nix | 3 - modules/services/options.nix | 39 +++-- 19 files changed, 418 insertions(+), 949 deletions(-) create mode 100644 modules/services/nixos/dufs.nix delete mode 100644 modules/services/nixos/filebrowser.nix delete mode 100644 modules/services/nixos/jta/assignments.html delete mode 100644 modules/services/nixos/jta/default.nix delete mode 100644 modules/services/nixos/jta/go.mod delete mode 100644 modules/services/nixos/jta/go.sum delete mode 100644 modules/services/nixos/jta/index.html delete mode 100644 modules/services/nixos/jta/main.go delete mode 100644 modules/services/nixos/jta/md_template.html delete mode 100644 modules/services/nixos/jta/pkg.nix delete mode 100644 modules/services/nixos/jta/style.css (limited to 'modules') diff --git a/modules/services/nixos/btopweb.nix b/modules/services/nixos/btopweb.nix index 9c78295..74a2447 100644 --- a/modules/services/nixos/btopweb.nix +++ b/modules/services/nixos/btopweb.nix @@ -6,46 +6,89 @@ }: let cfg = config.collinux.services.btopweb; - btopSettings = pkgs.writeText "btop.conf" '' - color_theme = "tomorrow-night" - enable_mouse = true - background_update = false - - proc_tree = true - proc_colors = true - ''; + modularService = { + lib, + config, + options, + ... + }: let + cfg = config.btopweb; + in { + options.btopweb = { + ttydPackage = lib.mkOption { + description = "the `ttyd` package"; + type = lib.types.package; + }; + btopPackage = lib.mkOption { + description = "the `btop` package"; + type = lib.types.package; + }; + btopSettings = lib.mkOption { + description = "configuration file for btop"; + type = lib.types.lines; + }; + }; + + config = + { + configData."btop.conf".text = cfg.btopSettings; + process.argv = [ + (lib.getExe cfg.ttydPackage) + "-W" + "-i" + "/run/btopweb/ttyd.sock" + "-t" + "renderType=canvas" + "-t" + "fontSize=16" + (lib.getExe cfg.btopPackage) + "-c" + config.configData."btop.conf".path + ]; + } + // lib.optionalAttrs (options ? systemd) { + systemd.service = { + description = "Host btop on a website"; + wants = ["network-online.target"]; + after = ["network-online.target"]; + wantedBy = ["multi-user.target"]; + + serviceConfig = { + DynamicUser = true; + Group = "caddy"; + + RuntimeDirectory = "btopweb"; + RuntimeDirectoryMode = "0750"; + UMask = "0002"; + + # allow btop to monitor system stats + ProtectProc = "default"; + ProcSubset = "all"; + + ProtectSystem = "strict"; + ProtectHome = true; + PrivateTmp = true; + NoNewPrivileges = true; + + Restart = "on-failure"; + }; + }; + }; + }; in { config = lib.mkIf cfg.enable { - users.groups."btopweb" = {}; - users.users."btopweb" = { - isSystemUser = true; - group = "btopweb"; - }; - users.users.caddy.extraGroups = ["btopweb"]; - - systemd.services."btopweb" = { - description = "Host btop on a website"; - restartIfChanged = true; - wants = ["network-online.target"]; - after = ["network-online.target"]; - wantedBy = ["multi-user.target"]; - - serviceConfig = { - User = "btopweb"; - Group = "btopweb"; - Type = "simple"; - - RuntimeDirectory = "btopweb"; - RuntimeDirectoryMode = "0770"; - UMask = "0007"; - - ExecStart = '' - ${lib.getExe pkgs.ttyd} \ - -W \ - -i /run/btopweb/ttyd.sock \ - -t renderType=canvas \ - -t fontSize=16 \ - ${pkgs.btop}/bin/btop -c ${btopSettings} + system.services."btopweb" = { + imports = [modularService]; + btopweb = { + ttydPackage = pkgs.ttyd; + btopPackage = pkgs.btop; + btopSettings = '' + color_theme = "tomorrow-night" + enable_mouse = true + background_update = false + + proc_tree = true + proc_colors = true ''; }; }; diff --git a/modules/services/nixos/cgit/default.nix b/modules/services/nixos/cgit/default.nix index eaa1682..1da463c 100644 --- a/modules/services/nixos/cgit/default.nix +++ b/modules/services/nixos/cgit/default.nix @@ -63,7 +63,7 @@ in { root-desc=Git repos for my various personal projects readme=:README.md - about-filter=${md2html}/bin/md2html.sh + about-filter=${lib.getExe md2html} source-filter=${pkgs.cgit}/lib/cgit/filters/syntax-highlighting.py head-include=${./cgit-head.html} footer= @@ -72,31 +72,35 @@ in { scan-path=/var/lib/cgit ''; - services.fcgiwrap.instances."cgit" = { - process = { - user = "git"; - group = "git"; + systemd.sockets."fcgiwrap-cgit" = { + wantedBy = ["sockets.target"]; + listenStreams = ["/run/cgit/fcgiwrap.sock"]; + socketConfig = { + SocketMode = "0660"; + SocketGroup = "caddy"; }; + }; - socket = { - user = "caddy"; - group = "caddy"; - type = "unix"; - address = "/run/fcgiwrap-cgit.sock"; + systemd.services."fcgiwrap-cgit" = { + after = ["nss-user-lookup.target"]; + serviceConfig = { + ExecStart = "${lib.getExe pkgs.fcgiwrap} -c 1"; + User = "git"; + Group = "git"; }; }; services.caddy.virtualHosts."git.collin.williamsfam.us.com".extraConfig = '' @assets path /cgit.css /cgit.js /favicon.svg /robots.txt handle @assets { - root * ${custom_cgit} - file_server + root * ${custom_cgit} + file_server } - reverse_proxy unix//run/fcgiwrap-cgit.sock { - transport fastcgi { - env SCRIPT_FILENAME ${custom_cgit}/cgit.cgi - } + reverse_proxy unix//run/cgit/fcgiwrap.sock { + transport fastcgi { + env SCRIPT_FILENAME ${custom_cgit}/cgit.cgi + } } ''; diff --git a/modules/services/nixos/default.nix b/modules/services/nixos/default.nix index 9aea299..44609a7 100644 --- a/modules/services/nixos/default.nix +++ b/modules/services/nixos/default.nix @@ -7,14 +7,11 @@ ./btopweb.nix ./cgit ./ganyupload - ./jta ./glance.nix - ./filebrowser.nix + ./dufs.nix ./minecraft.nix ./ngircd.nix ./qbittorrent.nix ]; - - users.groups."fileserver" = {}; } diff --git a/modules/services/nixos/dufs.nix b/modules/services/nixos/dufs.nix new file mode 100644 index 0000000..966d973 --- /dev/null +++ b/modules/services/nixos/dufs.nix @@ -0,0 +1,73 @@ +{ + lib, + pkgs, + config, + ... +}: let + cfg = config.collinux.services.dufs; + + modularService = { + lib, + config, + options, + ... + }: let + cfg = config.dufs; + in { + options.dufs = { + package = lib.mkOption { + description = "the `dufs` package"; + type = lib.types.package; + }; + dir = lib.mkOption { + description = "root directory of the fileserver"; + type = lib.types.str; + }; + }; + config = + {process.argv = [(lib.getExe cfg.package) cfg.dir "--bind" "/run/dufs/dufs.sock"];} + // lib.optionalAttrs (options ? systemd) { + systemd.service = { + wants = ["network-online.target"]; + after = ["network-online.target"]; + wantedBy = ["multi-user.target"]; + + serviceConfig = { + DynamicUser = true; + Group = "caddy"; + SupplementaryGroups = "fileserver"; + + RuntimeDirectory = "dufs"; + RuntimeDirectoryMode = "0750"; + UMask = "0002"; + + ProtectSystem = "strict"; + ProtectHome = true; + PrivateTmp = true; + NoNewPrivileges = true; + }; + }; + }; + }; +in + lib.mkIf cfg.enable { + users.groups."fileserver" = {}; + + system.services."dufs" = { + imports = [modularService]; + dufs = { + package = pkgs.dufs; + dir = "/media"; + }; + }; + + services.caddy.virtualHosts."files.ganymede".extraConfig = '' + tls internal + reverse_proxy unix//run/dufs/dufs.sock + ''; + + collinux.services.glance.homelabServices."files" = { + url = "https://files.ganymede"; + icon = "mdi:folder"; + }; + } diff --git a/modules/services/nixos/filebrowser.nix b/modules/services/nixos/filebrowser.nix deleted file mode 100644 index 9791f8d..0000000 --- a/modules/services/nixos/filebrowser.nix +++ /dev/null @@ -1,52 +0,0 @@ -{ - lib, - pkgs, - config, - ... -}: let - cfg = config.collinux.services.filebrowser; -in - lib.mkIf cfg.enable { - users.groups."dufs" = {}; - users.users."dufs" = { - isSystemUser = true; - group = "dufs"; - extraGroups = ["fileserver"]; - }; - users.users.caddy.extraGroups = ["dufs"]; - - systemd.services."dufs" = { - description = "dufs file server"; - restartIfChanged = true; - wants = ["network-online.target"]; - after = ["network-online.target"]; - wantedBy = ["multi-user.target"]; - - serviceConfig = { - ExecStart = "${lib.getExe pkgs.dufs} /media --bind /run/dufs/dufs.sock"; - - RuntimeDirectory = "dufs"; - - User = "dufs"; - Group = "dufs"; - UMask = "0007"; - - ProtectSystem = "strict"; - ProtectHome = true; - PrivateTmp = true; - NoNewPrivileges = true; - - Restart = "on-failure"; - }; - }; - - services.caddy.virtualHosts."files.ganymede".extraConfig = '' - tls internal - reverse_proxy unix//run/dufs/dufs.sock - ''; - - collinux.services.glance.homelabServices."files" = { - url = "https://files.ganymede"; - icon = "mdi:folder"; - }; - } diff --git a/modules/services/nixos/glance.nix b/modules/services/nixos/glance.nix index 8d305a5..2b7ba0b 100644 --- a/modules/services/nixos/glance.nix +++ b/modules/services/nixos/glance.nix @@ -6,111 +6,158 @@ }: let cfg = config.collinux.services.glance; - servicesLinks = builtins.attrValues cfg.homelabServices; - - settings = { - server = { - inherit (cfg) port; - proxied = true; - host = "127.0.0.1"; - assets-path = "/var/lib/glance"; + modularService = { + lib, + config, + options, + ... + }: let + cfg = config.glance; + in { + options.glance = { + package = lib.mkOption { + description = "the `glance` package"; + type = lib.types.package; + }; + settings = lib.mkOption { + description = "glance configuration file contents"; + type = (pkgs.formats.json {}).type; + }; }; - - branding.hide-footer = true; - pages = [ + config = { - name = "Dashboard"; - width = "slim"; - hide-desktop-navigation = true; - center-vertically = true; - columns = [ + configData."config.yml".text = builtins.toJSON ( { - size = "full"; - widgets = [ - { - type = "search"; - autofocus = true; - search-engine = "duckduckgo"; - bangs = [ - { - title = "GitHub"; - shortcut = "gh"; - url = "https://github.com/search?q={QUERY}&type=repositories"; - } - { - title = "I'm Feeling Lucky"; - shortcut = "!"; - url = "https://www.google.com/search?q={QUERY}&btnI=&sourceid=navclient&gfns=1"; - } - { - title = "YouTube Music"; - shortcut = "ytm"; - url = "https://music.youtube.com/search?q={QUERY}"; - } - { - title = "Google AI Mode"; - shortcut = "ai"; - url = "https://www.google.com/search?udm=50&q={QUERY}"; - } - ]; - } - { - type = "server-stats"; - servers = [ - { - type = "local"; - name = "ganymede"; - hide-mountpoints-by-default = true; - mountpoints = { - "/".hide = false; - "/media".hide = false; - }; - } - ]; - } - { - type = "monitor"; - cache = "1m"; - title = "Services"; - sites = servicesLinks; - } - ]; + server = { + port = 8080; + proxied = true; + host = "127.0.0.1"; + assets-path = "/var/lib/glance"; + }; } - ]; + // cfg.settings + ); + process.argv = [(lib.getExe cfg.package) "-config" config.configData."config.yml".path]; } - ]; - }; + // lib.optionalAttrs (options ? systemd) { + systemd.service = { + wantedBy = ["multi-user.target"]; - settingsFile = (pkgs.formats.yaml {}).generate "config.yml" settings; -in { - config = lib.mkIf cfg.enable { - systemd.services."glance" = { - restartIfChanged = true; - wants = ["network-online.target"]; - after = ["network-online.target"]; - wantedBy = ["multi-user.target"]; + serviceConfig = { + DynamicUser = true; + StateDirectory = "glance"; - serviceConfig = { - Type = "simple"; + PrivateNetwork = true; + NoNewPrivileges = true; + PrivateTmp = true; + ProtectSystem = "strict"; + ProtectHome = true; + ProtectKernelTunables = true; + ProtectKernelModules = true; + ProtectControlGroups = true; + }; + }; - DynamicUser = true; - StateDirectory = "glance"; + systemd.sockets."glance-proxy" = { + wantedBy = ["sockets.target"]; + listenStreams = ["/run/glance/glance.sock"]; + socketConfig = { + SocketMode = "0660"; + SocketGroup = "caddy"; + }; + }; - ExecStart = "${lib.getExe pkgs.glance} -config ${settingsFile}"; + systemd.services."glance-proxy" = { + requires = ["glance.service"]; + after = ["glance.service"]; + unitConfig.JoinsNamespaceOf = "glance.service"; - NoNewPrivileges = true; - PrivateTmp = true; - ProtectSystem = "strict"; - ProtectHome = true; - ProtectKernelTunables = true; - ProtectKernelModules = true; - ProtectControlGroups = true; + serviceConfig = { + ExecStart = "${pkgs.systemd}/lib/systemd/systemd-socket-proxyd 127.0.0.1:8080"; + DynamicUser = true; + PrivateNetwork = true; + PrivateTmp = true; + NoNewPrivileges = true; + ProtectSystem = "strict"; + ProtectHome = true; + }; + }; + }; + }; +in { + config = lib.mkIf cfg.enable { + system.services."glance" = { + imports = [modularService]; + glance = { + package = pkgs.glance; + settings = let + servicesLinks = builtins.attrValues cfg.homelabServices; + wrap = x: [x]; + in { + branding.hide-footer = true; + pages = wrap { + name = "Dashboard"; + width = "slim"; + hide-desktop-navigation = true; + center-vertically = true; + columns = wrap { + size = "full"; + widgets = [ + { + type = "search"; + autofocus = true; + search-engine = "duckduckgo"; + bangs = [ + { + title = "GitHub"; + shortcut = "gh"; + url = "https://github.com/search?q={QUERY}&type=repositories"; + } + { + title = "I'm Feeling Lucky"; + shortcut = "!"; + url = "https://www.google.com/search?q={QUERY}&btnI=&sourceid=navclient&gfns=1"; + } + { + title = "YouTube Music"; + shortcut = "ytm"; + url = "https://music.youtube.com/search?q={QUERY}"; + } + { + title = "Google AI Mode"; + shortcut = "ai"; + url = "https://www.google.com/search?udm=50&q={QUERY}"; + } + ]; + } + { + type = "server-stats"; + servers = wrap { + type = "local"; + name = "ganymede"; + hide-mountpoints-by-default = true; + mountpoints = { + "/".hide = false; + "/media".hide = false; + }; + }; + } + { + type = "monitor"; + cache = "1m"; + title = "Services"; + sites = servicesLinks; + } + ]; + }; + }; + }; }; }; services.caddy.virtualHosts."home.ganymede".extraConfig = '' tls internal - reverse_proxy 127.0.0.1:${toString cfg.port} + reverse_proxy unix///run/glance/glance.sock ''; }; } diff --git a/modules/services/nixos/goaccess.nix b/modules/services/nixos/goaccess.nix index f0b6c34..15a3768 100644 --- a/modules/services/nixos/goaccess.nix +++ b/modules/services/nixos/goaccess.nix @@ -7,78 +7,107 @@ }: let cfg = config.collinux.services.goaccess; - settings = { - date-format = "%s"; - log-format = "CADDY"; - tz = config.time.timeZone; - log-file = "/var/log/caddy/access-williamsfam.us.com.log"; - geoip-database = inputs.geolite-db; + modularService = { + lib, + config, + options, + ... + }: let + cfg = config.goaccess; - ws-url = "wss://stats.ganymede:443/ws"; # url that the frontend uses to fetch data - unix-socket = "/run/goaccess/goaccess.sock"; + settings = + cfg.settings + // { + unix-socket = "/run/goaccess/goaccess.sock"; + output = "/run/goaccess/www/index.html"; + }; + in { + options.goaccess = { + package = lib.mkOption { + description = "the `goaccess` package"; + type = lib.types.package; + }; + settings = lib.mkOption { + description = "goaccess.conf options"; + type = lib.types.attrsOf lib.types.str; + }; + }; - real-time-html = "true"; - output = "/var/lib/goaccess/index.html"; - external-assets = "true"; - all-static-files = "false"; - html-report-title = "stats@ganymede"; - hl-header = "true"; - agent-list = "false"; - with-output-resolver = "false"; - http-method = "yes"; - http-protocol = "yes"; - "4xx-to-unique-count" = "false"; - ignore-crawlers = "false"; - crawlers-only = "false"; - unknowns-as-crawlers = "false"; - real-os = "true"; - }; + config = + { + configData."goaccess.conf".text = + settings + |> lib.mapAttrsToList (k: v: "${k} ${v}") + |> lib.concatStringsSep "\n"; - settingsFile = pkgs.writeText "goaccess.conf" (settings |> builtins.mapAttrs (k: v: "${k} ${toString v}") |> builtins.attrValues |> lib.concatStringsSep "\n"); -in { - config = lib.mkIf cfg.enable { - users.groups."goaccess" = {}; - users.users."goaccess" = { - isSystemUser = true; - group = "goaccess"; - extraGroups = ["caddy"]; # to read caddy log files - }; - users.users.caddy.extraGroups = ["goaccess"]; + process.argv = [(lib.getExe cfg.package) "-p" config.configData."goaccess.conf".path]; + } + // lib.optionalAttrs (options ? systemd) { + systemd.service = { + description = "GoAccess Real-Time Log Analyzer"; + restartIfChanged = true; + wants = ["network-online.target" "caddy.service"]; + after = ["network-online.target" "caddy.service"]; + wantedBy = ["multi-user.target"]; - systemd.services."goaccess" = { - description = "GoAccess Real-Time Log Analyzer"; - restartIfChanged = true; - wants = ["network-online.target" "caddy.service"]; - after = ["network-online.target" "caddy.service"]; - wantedBy = ["multi-user.target"]; + serviceConfig = { + DynamicUser = true; + Group = "caddy"; - serviceConfig = { - User = "goaccess"; - Type = "simple"; + RuntimeDirectory = ["goaccess" "goaccess/www"]; + RuntimeDirectoryMode = "0750"; + UMask = "0007"; # socket -> 0770, files -> 0660 - RuntimeDirectory = "goaccess"; - RuntimeDirectoryMode = "0770"; - UMask = "0007"; + NoNewPrivileges = true; + PrivateTmp = true; + ProtectSystem = "strict"; + ProtectHome = true; + ProtectKernelTunables = true; + ProtectKernelModules = true; + ProtectControlGroups = true; - StateDirectory = "goaccess"; - StateDirectoryMode = "0750"; # caddy must read this dir + Restart = "on-failure"; + }; + }; + }; + }; +in { + config = lib.mkIf cfg.enable { + system.services."goaccess" = { + imports = [modularService]; + goaccess = { + package = pkgs.goaccess; + settings = { + date-format = "%s"; + log-format = "CADDY"; + tz = config.time.timeZone; + log-file = "/var/log/caddy/access-williamsfam.us.com.log"; + geoip-database = toString inputs.geolite-db; - ExecStart = "${lib.getExe pkgs.goaccess} -p ${settingsFile}"; + ws-url = "wss://stats.ganymede:443/ws"; # url that the frontend uses to fetch data - NoNewPrivileges = true; - PrivateTmp = true; - ProtectSystem = "strict"; - ProtectHome = true; - ProtectKernelTunables = true; - ProtectKernelModules = true; - ProtectControlGroups = true; + real-time-html = "true"; + external-assets = "true"; + all-static-files = "false"; + html-report-title = "stats@ganymede"; + hl-header = "true"; + agent-list = "false"; + with-output-resolver = "false"; + http-method = "yes"; + http-protocol = "yes"; + "4xx-to-unique-count" = "false"; + ignore-crawlers = "false"; + crawlers-only = "false"; + unknowns-as-crawlers = "false"; + real-os = "true"; + }; }; }; services.caddy.virtualHosts."stats.ganymede".extraConfig = '' tls internal - root * /var/lib/goaccess + root * /run/goaccess/www file_server reverse_proxy /ws unix//run/goaccess/goaccess.sock diff --git a/modules/services/nixos/jta/assignments.html b/modules/services/nixos/jta/assignments.html deleted file mode 100644 index 3031a29..0000000 --- a/modules/services/nixos/jta/assignments.html +++ /dev/null @@ -1,148 +0,0 @@ - - -
- - -Public landing page. Login is required to view assignments and all other pages.
- -