diff --git a/homes/x86_64-linux/admin@jallen-nas/default.nix b/homes/x86_64-linux/admin@jallen-nas/default.nix index 7b3aa74..f7d480a 100755 --- a/homes/x86_64-linux/admin@jallen-nas/default.nix +++ b/homes/x86_64-linux/admin@jallen-nas/default.nix @@ -1,10 +1,18 @@ { pkgs, config, + inputs, namespace, ... }: { + # steam-rom-manager HM module is needed for the steam-rom-manager program + # options. On NixOS hosts it's provided via sharedModules; here we add it + # explicitly so the standalone homeConfiguration build also includes it. + imports = [ + inputs.steam-rom-manager.homeManagerModules.default + ]; + home = { username = "admin"; packages = diff --git a/lib/module/default.nix b/lib/module/default.nix index 5a2c664..afe7828 100644 --- a/lib/module/default.nix +++ b/lib/module/default.nix @@ -17,12 +17,9 @@ let in rec { - # Conditionally enable modules based on system - enableForSystem = - system: modules: - builtins.filter ( - mod: mod.systems or [ ] == [ ] || builtins.elem system (mod.systems or [ ]) - ) modules; + # --------------------------------------------------------------------------- + # NixOS service module helpers + # --------------------------------------------------------------------------- # Create a NixOS module with standard options (enable, port, reverseProxy, # firewall, user, postgresql, redis) and optional caller-supplied options and @@ -61,7 +58,6 @@ rec { ''; }; - # Open firewall networking.firewall = lib.mkIf cfg.openFirewall { allowedTCPPorts = [ cfg.port ]; allowedUDPPorts = [ cfg.port ]; @@ -76,11 +72,8 @@ rec { groups.${name} = { }; }; - # Ensure the service waits for the filesystem that hosts configDir and - # dataDir to be mounted before starting. RequiresMountsFor is the - # idiomatic systemd way to express this: if the paths live on the root - # filesystem the directive is silently ignored, so it is safe on every - # host — not just the NAS. + # RequiresMountsFor is silently ignored when the paths live on the root + # filesystem, so this is safe on non-NAS hosts too. systemd.services.${serviceName}.unitConfig.RequiresMountsFor = [ cfg.configDir cfg.dataDir @@ -107,10 +100,6 @@ rec { { lib, ... }: { imports = [ - # defaultConfig and moduleConfig are kept as separate inline modules so - # the NixOS module system handles all merging (mkIf, mkForce, mkMerge, - # etc.) correctly, rather than merging raw attrsets with // or - # recursiveUpdate which can silently clobber mkIf wrappers. { config = lib.mkIf cfg.enable defaultConfig; } { config = lib.mkIf cfg.enable moduleConfig; } ]; @@ -165,6 +154,147 @@ rec { }; }; + # Wraps mkModule for Podman/OCI container services. Generates all the + # standard mkModule options plus the container definition. The serviceName + # is set to "podman-" automatically. + # + # Required args: + # config — the NixOS config attrset (pass through from the module args) + # name — service name (used for the container name and option path) + # image — OCI image reference string + # internalPort — port the container listens on internally + # + # Optional args: + # description — human-readable description (defaults to name) + # options — extra mkModule options attrset + # volumes — extra volume strings (in addition to none) + # environment — extra environment variables (merged with PUID/PGID/TZ) + # environmentFiles — list of paths to env-files (e.g. sops template paths) + # extraOptions — list of extra --opt strings passed to the container runtime + # devices — list of device mappings + # extraConfig — extra NixOS config merged into moduleConfig + mkContainerService = + { + config, + name, + image, + internalPort, + description ? name, + options ? { }, + volumes ? [ ], + environment ? { }, + environmentFiles ? [ ], + extraOptions ? [ ], + devices ? [ ], + extraConfig ? { }, + }: + let + cfg = config.${namespace}.services.${name}; + in + mkModule { + inherit + config + name + description + options + ; + serviceName = "podman-${name}"; + moduleConfig = lib.recursiveUpdate { + virtualisation.oci-containers.containers.${name} = { + autoStart = true; + inherit + image + volumes + environmentFiles + extraOptions + devices + ; + ports = [ "${toString cfg.port}:${toString internalPort}" ]; + environment = { + PUID = cfg.puid; + PGID = cfg.pgid; + TZ = cfg.timeZone; + } + // environment; + }; + } extraConfig; + }; + + # Generates a sops secrets block + a sops template env-file in a single call. + # + # secrets — attrset of sops secret keys → extra attrs (e.g. owner/group). + # The sopsFile is set automatically to nas-secrets.yaml unless + # overridden per-secret via { sopsFile = ...; }. + # name — template file name, e.g. "glance.env" + # content — the template body string (use config.sops.placeholder."key") + # restartUnit — systemd unit to restart when the secret changes + # owner, group, mode — file ownership/permissions (defaults match NAS convention) + # sopsFile — default sops file for all secrets (can be overridden per-secret) + mkSopsEnvFile = + { + secrets, + name, + content, + restartUnit, + owner ? "nix-apps", + group ? "jallen-nas", + mode ? "660", + sopsFile ? (lib.snowfall.fs.get-file "secrets/nas-secrets.yaml"), + }: + { + sops.secrets = mapAttrs (_key: extra: { inherit sopsFile; } // extra) secrets; + + sops.templates.${name} = { + inherit + mode + owner + group + content + ; + restartUnits = [ restartUnit ]; + }; + }; + + # --------------------------------------------------------------------------- + # Home Manager module helper + # --------------------------------------------------------------------------- + + # Create a Home Manager module with a standard enable option and optional + # extra options, gating all config behind `cfg.enable`. + # + # domain — option namespace domain, e.g. "programs" or "desktop" + # name — module name, e.g. "btop" + # description — text for mkEnableOption (defaults to name) + # options — attrset of extra options merged into the submodule + # config — the NixOS/HM config attrset passed through from module args + # moduleConfig — the Home Manager config body (already gated behind cfg.enable) + mkHomeModule = + { + config, + domain, + name, + description ? name, + options ? { }, + moduleConfig, + }: + let + cfg = config.${namespace}.${domain}.${name}; + in + { lib, ... }: + { + options.${namespace}.${domain}.${name} = lib.mkOption { + type = lib.types.submodule { + options = { + enable = lib.mkEnableOption description; + } + // options; + }; + default = { }; + }; + + config = lib.mkIf cfg.enable moduleConfig; + }; + # --------------------------------------------------------------------------- # Option creation helpers # --------------------------------------------------------------------------- diff --git a/modules/home/home/default.nix b/modules/home/home/default.nix index a5358c5..a78e2db 100644 --- a/modules/home/home/default.nix +++ b/modules/home/home/default.nix @@ -70,7 +70,9 @@ in }; programs = { - nix-index-database.comma = enabled; + # nix-index-database is not available in all home configs (e.g. iso-minimal + # standalone homes don't load the nix-index-database HM module). + # Set it per-host in homes that explicitly load the module. btop = { enable = lib.mkDefault true; package = pkgs.btop; diff --git a/modules/home/programs/btop/default.nix b/modules/home/programs/btop/default.nix index 0266e34..852ffe4 100755 --- a/modules/home/programs/btop/default.nix +++ b/modules/home/programs/btop/default.nix @@ -4,79 +4,81 @@ namespace, ... }: -with lib; -let - cfg = config.${namespace}.programs.btop; -in { - imports = [ ./options.nix ]; - config = mkIf cfg.enable { - programs.btop = { - enable = true; - settings = { - truecolor = true; - force_tty = false; - presets = "cpu:1:default,proc:0:default cpu:0:default,mem:0:default,net:0:default cpu:0:block,net:0:tty"; - vim_keys = true; - rounded_corners = true; - graph_symbol = "braille"; - graph_symbol_cpu = "default"; - graph_symbol_mem = "default"; - graph_symbol_net = "default"; - graph_symbol_proc = "default"; - shown_boxes = "cpu mem net proc"; - update_ms = 2000; - proc_sorting = "cpu lazy"; - proc_reversed = false; - proc_tree = false; - proc_colors = true; - proc_gradient = true; - proc_per_core = false; - proc_mem_bytes = true; - proc_cpu_graphs = true; - proc_info_smaps = false; - proc_left = false; - proc_filter_kernel = false; - cpu_graph_upper = "total"; - cpu_graph_lower = "total"; - cpu_invert_lower = true; - cpu_single_graph = false; - cpu_bottom = false; - show_uptime = true; - check_temp = true; - cpu_sensor = "Auto"; - show_coretemp = true; - cpu_core_map = ""; - temp_scale = "celsius"; - base_10_sizes = false; - show_cpu_freq = true; - clock_format = "%X"; - background_update = true; - custom_cpu_name = ""; - disks_filter = ""; - mem_graphs = true; - mem_below_net = false; - zfs_arc_cached = true; - show_swap = true; - swap_disk = true; - show_disks = true; - only_physical = true; - use_fstab = true; - zfs_hide_datasets = false; - disk_free_priv = false; - show_io_stat = true; - io_mode = false; - io_graph_combined = false; - io_graph_speeds = ""; - net_download = 100; - net_upload = 100; - net_auto = true; - net_sync = true; - net_iface = ""; - show_battery = true; - selected_battery = "Auto"; - log_level = "WARNING"; + imports = [ + (lib.${namespace}.mkHomeModule { + inherit config; + domain = "programs"; + name = "btop"; + moduleConfig = { + programs.btop = { + enable = true; + settings = { + truecolor = true; + force_tty = false; + presets = "cpu:1:default,proc:0:default cpu:0:default,mem:0:default,net:0:default cpu:0:block,net:0:tty"; + vim_keys = true; + rounded_corners = true; + graph_symbol = "braille"; + graph_symbol_cpu = "default"; + graph_symbol_mem = "default"; + graph_symbol_net = "default"; + graph_symbol_proc = "default"; + shown_boxes = "cpu mem net proc"; + update_ms = 2000; + proc_sorting = "cpu lazy"; + proc_reversed = false; + proc_tree = false; + proc_colors = true; + proc_gradient = true; + proc_per_core = false; + proc_mem_bytes = true; + proc_cpu_graphs = true; + proc_info_smaps = false; + proc_left = false; + proc_filter_kernel = false; + cpu_graph_upper = "total"; + cpu_graph_lower = "total"; + cpu_invert_lower = true; + cpu_single_graph = false; + cpu_bottom = false; + show_uptime = true; + check_temp = true; + cpu_sensor = "Auto"; + show_coretemp = true; + cpu_core_map = ""; + temp_scale = "celsius"; + base_10_sizes = false; + show_cpu_freq = true; + clock_format = "%X"; + background_update = true; + custom_cpu_name = ""; + disks_filter = ""; + mem_graphs = true; + mem_below_net = false; + zfs_arc_cached = true; + show_swap = true; + swap_disk = true; + show_disks = true; + only_physical = true; + use_fstab = true; + zfs_hide_datasets = false; + disk_free_priv = false; + show_io_stat = true; + io_mode = false; + io_graph_combined = false; + io_graph_speeds = ""; + net_download = 100; + net_upload = 100; + net_auto = true; + net_sync = true; + net_iface = ""; + show_battery = true; + selected_battery = "Auto"; + log_level = "WARNING"; + }; + }; }; - }; - }; + }) + ]; } diff --git a/modules/home/programs/btop/options.nix b/modules/home/programs/btop/options.nix deleted file mode 100644 index 3cf098d..0000000 --- a/modules/home/programs/btop/options.nix +++ /dev/null @@ -1,7 +0,0 @@ -{ lib, namespace, ... }: -with lib; -{ - options.${namespace}.programs.btop = { - enable = mkEnableOption "enable btop"; - }; -} diff --git a/modules/home/programs/kitty/default.nix b/modules/home/programs/kitty/default.nix index 46916a6..5f61179 100755 --- a/modules/home/programs/kitty/default.nix +++ b/modules/home/programs/kitty/default.nix @@ -1,30 +1,30 @@ { - lib, config, + lib, namespace, ... }: -with lib; -let - cfg = config.${namespace}.programs.kitty; -in { - imports = [ ./options.nix ]; - - config = mkIf cfg.enable { - programs.kitty = { - enable = true; - shellIntegration.enableZshIntegration = true; - - settings = { - bold_font = "auto"; - italic_font = "auto"; - bold_italic_font = "auto"; - mouse_hide_wait = "2.0"; - cursor_shape = "block"; - url_style = "dotted"; - confirm_os_window_close = "0"; + imports = [ + (lib.${namespace}.mkHomeModule { + inherit config; + domain = "programs"; + name = "kitty"; + moduleConfig = { + programs.kitty = { + enable = true; + shellIntegration.enableZshIntegration = true; + settings = { + bold_font = "auto"; + italic_font = "auto"; + bold_italic_font = "auto"; + mouse_hide_wait = "2.0"; + cursor_shape = "block"; + url_style = "dotted"; + confirm_os_window_close = "0"; + }; + }; }; - }; - }; + }) + ]; } diff --git a/modules/home/programs/kitty/options.nix b/modules/home/programs/kitty/options.nix deleted file mode 100644 index 49130c9..0000000 --- a/modules/home/programs/kitty/options.nix +++ /dev/null @@ -1,7 +0,0 @@ -{ lib, namespace, ... }: -with lib; -{ - options.${namespace}.programs.kitty = { - enable = mkEnableOption "enable kitty terminal"; - }; -} diff --git a/modules/home/programs/mako/default.nix b/modules/home/programs/mako/default.nix index 3e3d80e..6102ffb 100755 --- a/modules/home/programs/mako/default.nix +++ b/modules/home/programs/mako/default.nix @@ -4,33 +4,37 @@ namespace, ... }: -with lib; -let - cfg = config.${namespace}.programs.mako; -in { - imports = [ ./options.nix ]; - config = mkIf cfg.enable { - services.mako = { - enable = true; - settings = { - font = mkDefault cfg.fontName; - icons = true; - ignore-timeout = true; - sort = "-time"; - width = 500; - height = 110; - layer = "overlay"; - border-radius = 15; - border-size = 1; - max-icon-size = 64; - default-timeout = 5000; - - # background-color = mkDefault config.lib.stylix.colors.base00; - # text-color = mkDefault config.lib.stylix.colors.base06; - # border-color = mkDefault config.lib.stylix.colors.base0F; - # progress-color = mkDefault "over ${config.lib.stylix.colors.base0C}"; + imports = [ + (lib.${namespace}.mkHomeModule { + inherit config; + domain = "programs"; + name = "mako"; + options = { + fontName = lib.mkOption { + type = lib.types.str; + default = "DejaVu Sans"; + description = "Font name for mako notifications."; + }; }; - }; - }; + moduleConfig = { + services.mako = { + enable = true; + settings = { + font = lib.mkDefault config.${namespace}.programs.mako.fontName; + icons = true; + ignore-timeout = true; + sort = "-time"; + width = 500; + height = 110; + layer = "overlay"; + border-radius = 15; + border-size = 1; + max-icon-size = 64; + default-timeout = 5000; + }; + }; + }; + }) + ]; } diff --git a/modules/home/programs/mako/options.nix b/modules/home/programs/mako/options.nix deleted file mode 100644 index 6bb8dfe..0000000 --- a/modules/home/programs/mako/options.nix +++ /dev/null @@ -1,12 +0,0 @@ -{ lib, namespace, ... }: -with lib; -{ - options.${namespace}.programs.mako = { - enable = mkEnableOption "enable mako"; - - fontName = mkOption { - type = types.str; - default = "DejaVu Sans"; - }; - }; -} diff --git a/modules/home/programs/nwg-dock/default.nix b/modules/home/programs/nwg-dock/default.nix index 9855671..8deda16 100644 --- a/modules/home/programs/nwg-dock/default.nix +++ b/modules/home/programs/nwg-dock/default.nix @@ -5,134 +5,131 @@ namespace, ... }: -with lib; -let - cfg = config.${namespace}.programs.nwg-dock; -in { - imports = [ ./options.nix ]; + imports = [ + (lib.${namespace}.mkHomeModule { + inherit config; + domain = "programs"; + name = "nwg-dock"; + moduleConfig = { + home.packages = with pkgs; [ nwg-dock-hyprland ]; - config = mkIf cfg.enable { - home.packages = with pkgs; [ nwg-dock-hyprland ]; + home.file = { + ".config/nwg-dock-hyprland/config.json".text = '' + { + "position": "bottom", + "anchor": "center", + "margin": 12, + "icon_size": 48, + "icon_size_hover": 64, + "spacing": 6, + "padding": 8, + "autohide": false, + "autohide_timeout": 0.3, + "exclusive": true, + "layer": "top", + "height": 72, + "background_alpha": 0.55, + "rounded_corners": 16, + "show_labels": false, + "show_running": true, + "show_pinned": true, + "pinned": [ + "firefox.desktop", + "org.wezfurlong.wezterm.desktop", + "codium.desktop", + "org.gnome.Nautilus.desktop" + ] + } + ''; - home.file = { - ".config/nwg-dock-hyprland/config.json".text = '' - { - "position": "bottom", - "anchor": "center", - "margin": 12, - "icon_size": 48, - "icon_size_hover": 64, - "spacing": 6, - "padding": 8, - "autohide": false, - "autohide_timeout": 0.3, - "exclusive": true, - "layer": "top", - "height": 72, - "background_alpha": 0.55, - "rounded_corners": 16, - "show_labels": false, - "show_running": true, - "show_pinned": true, - "pinned": [ - "firefox.desktop", - "org.wezfurlong.wezterm.desktop", - "codium.desktop", - "org.gnome.Nautilus.desktop" - ] - } - ''; + ".config/nwg-dock-hyprland/style.css".text = '' + window { + background: #36364f; + border-radius: 10px; + border-style: none; + border-width: 1px; + border-color: rgba(156, 142, 122, 0.7) + } - ".config/nwg-dock-hyprland/style.css".text = '' - window { - background: #36364f; - border-radius: 10px; - border-style: none; - border-width: 1px; - border-color: rgba(156, 142, 122, 0.7) - } + #box { + padding: 10px + } - #box { - /* Define attributes of the box surrounding icons here */ - padding: 10px - } + #active { + border-bottom: solid 1px; + border-color: rgba(255, 255, 255, 0.3) + } - #active { - /* This is to underline the button representing the currently active window */ - border-bottom: solid 1px; - border-color: rgba(255, 255, 255, 0.3) - } + button, image { + background: none; + border-style: none; + box-shadow: none; + color: #999 + } - button, image { - background: none; - border-style: none; - box-shadow: none; - color: #999 - } + button { + padding: 4px; + margin-left: 4px; + margin-right: 4px; + color: #eee; + font-size: 12px + } - button { - padding: 4px; - margin-left: 4px; - margin-right: 4px; - color: #eee; - font-size: 12px - } + button:hover { + background-color: rgba(255, 255, 255, 0.15); + border-radius: 2px; + } - button:hover { - background-color: rgba(255, 255, 255, 0.15); - border-radius: 2px; - } + button:focus { + box-shadow: none + } + ''; - button:focus { - box-shadow: none - } - ''; + ".config/nwg-dock-hyprland/drawer.css".text = '' + window { + background: ${config.lib.stylix.colors.base00}; + border-radius: 10px; + border-style: none; + border-width: 1px; + border-color: ${config.lib.stylix.colors.base0E}b0 + } - ".config/nwg-dock-hyprland/drawer.css".text = '' - window { - background: ${config.lib.stylix.colors.base00}; - border-radius: 10px; - border-style: none; - border-width: 1px; - border-color: ${config.lib.stylix.colors.base0E}b0 - } + #box { + padding: 10px + } - #box { - /* Define attributes of the box surrounding icons here */ - padding: 10px - } + active { + border-bottom: solid 1px; + border-color: ${config.lib.stylix.colors.base0B}1a + } - active { - /* This is to underline the button representing the currently active window */ - border-bottom: solid 1px; - border-color: ${config.lib.stylix.colors.base0B}1a - } + button, image { + background: none; + border-style: none; + box-shadow: none; + color: ${config.lib.stylix.colors.base0F} + } - button, image { - background: none; - border-style: none; - box-shadow: none; - color: ${config.lib.stylix.colors.base0F} - } + button { + padding: 4px; + margin-left: 4px; + margin-right: 4px; + color: #eee; + font-size: 12px + } - button { - padding: 4px; - margin-left: 4px; - margin-right: 4px; - color: #eee; - font-size: 12px - } + button:hover { + background-color: ${config.lib.stylix.colors.base00}1a; + border-radius: 2px; + } - button:hover { - background-color: ${config.lib.stylix.colors.base00}1a; - border-radius: 2px; - } - - button:focus { - box-shadow: none - } - ''; - }; - }; + button:focus { + box-shadow: none + } + ''; + }; + }; + }) + ]; } diff --git a/modules/home/programs/nwg-dock/options.nix b/modules/home/programs/nwg-dock/options.nix deleted file mode 100644 index e931798..0000000 --- a/modules/home/programs/nwg-dock/options.nix +++ /dev/null @@ -1,7 +0,0 @@ -{ lib, namespace, ... }: -with lib; -{ - options.${namespace}.programs.nwg-dock = { - enable = mkEnableOption "enable nwg-dock"; - }; -} diff --git a/modules/home/programs/nwg-drawer/default.nix b/modules/home/programs/nwg-drawer/default.nix index 5f9212e..cd8e6ae 100644 --- a/modules/home/programs/nwg-drawer/default.nix +++ b/modules/home/programs/nwg-drawer/default.nix @@ -5,53 +5,50 @@ namespace, ... }: -with lib; -let - cfg = config.${namespace}.programs.nwg-drawer; -in { - imports = [ ./options.nix ]; + imports = [ + (lib.${namespace}.mkHomeModule { + inherit config; + domain = "programs"; + name = "nwg-drawer"; + moduleConfig = { + home.packages = with pkgs; [ nwg-drawer ]; - config = mkIf cfg.enable { - home.packages = with pkgs; [ nwg-drawer ]; + home.file.".config/nwg-drawer/drawer.css".text = '' + window { + background-color: ${config.lib.stylix.colors.base00}bf; + color: ${config.lib.stylix.colors.base05}00 + } - home.file = { - ".config/nwg-drawer/drawer.css".text = '' - window { - background-color: ${config.lib.stylix.colors.base00}bf; - color: ${config.lib.stylix.colors.base05}00 - } + entry { + background-color: ${config.lib.stylix.colors.base01}0f + } - /* search entry */ - entry { - background-color: ${config.lib.stylix.colors.base01}0f - } + button, image { + background: none; + border: none + } - button, image { - background: none; - border: none - } + button:hover { + background-color: ${config.lib.stylix.colors.base0F}1a + } - button:hover { - background-color: ${config.lib.stylix.colors.base0F}1a - } + #category-button { + margin: 0 10px 0 10px + } - /* in case you wanted to give category buttons a different look */ - #category-button { - margin: 0 10px 0 10px - } + #pinned-box { + padding-bottom: 5px; + border-bottom: 1px dotted ${config.lib.stylix.colors.base03} + } - #pinned-box { - padding-bottom: 5px; - border-bottom: 1px dotted ${config.lib.stylix.colors.base03} - } - - #files-box { - padding: 5px; - border: 1px dotted ${config.lib.stylix.colors.base03}; - border-radius: 15px - } - ''; - }; - }; + #files-box { + padding: 5px; + border: 1px dotted ${config.lib.stylix.colors.base03}; + border-radius: 15px + } + ''; + }; + }) + ]; } diff --git a/modules/home/programs/nwg-drawer/options.nix b/modules/home/programs/nwg-drawer/options.nix deleted file mode 100644 index 6371fd4..0000000 --- a/modules/home/programs/nwg-drawer/options.nix +++ /dev/null @@ -1,7 +0,0 @@ -{ lib, namespace, ... }: -with lib; -{ - options.${namespace}.programs.nwg-drawer = { - enable = mkEnableOption "enable nwg-drawer"; - }; -} diff --git a/modules/home/programs/wlogout/default.nix b/modules/home/programs/wlogout/default.nix index c937cb0..beb64c1 100644 --- a/modules/home/programs/wlogout/default.nix +++ b/modules/home/programs/wlogout/default.nix @@ -4,105 +4,60 @@ namespace, ... }: -with lib; -let - cfg = config.${namespace}.programs.wlogout; -in { - imports = [ ./options.nix ]; - config = mkIf cfg.enable { - programs.wlogout = { - enable = false; - layout = { - lock = { - label = "lock"; - action = "hyprlock --immediate"; - text = "Lock"; - keybind = "l"; - }; - hibernate = { - label = "hibernate"; - action = "systemctl hibernate"; - text = "Hibernate"; - keybind = "h"; - }; - logout = { - label = "logout"; - action = "sleep 1; hyprctl dispatch exit"; - text = "Logout"; - keybind = "e"; - }; - shutdown = { - label = "shutdown"; - action = "systemctl poweroff"; - text = "Shutdown"; - keybind = "s"; - }; - suspend = { - label = "suspend"; - action = "systemctl suspend"; - text = "Suspend"; - keybind = "u"; - }; - reboot = { - label = "reboot"; - action = "reboot"; - text = "Reboot"; - keybind = "r"; + imports = [ + (lib.${namespace}.mkHomeModule { + inherit config; + domain = "programs"; + name = "wlogout"; + moduleConfig = { + programs.wlogout = { + enable = false; + layout = { + lock = { label = "lock"; action = "hyprlock --immediate"; text = "Lock"; keybind = "l"; }; + hibernate = { label = "hibernate"; action = "systemctl hibernate"; text = "Hibernate"; keybind = "h"; }; + logout = { label = "logout"; action = "sleep 1; hyprctl dispatch exit"; text = "Logout"; keybind = "e"; }; + shutdown = { label = "shutdown"; action = "systemctl poweroff"; text = "Shutdown"; keybind = "s"; }; + suspend = { label = "suspend"; action = "systemctl suspend"; text = "Suspend"; keybind = "u"; }; + reboot = { label = "reboot"; action = "reboot"; text = "Reboot"; keybind = "r"; }; + }; + style = '' + * { + background-image: none; + } + + window { + background-color: ${config.lib.stylix.colors.base00}f0 + } + + button { + margin: 8px; + color: ${config.lib.stylix.colors.base0C}; + background-color: ${config.lib.stylix.colors.base01}; + border-style: solid; + border-width: 2px; + background-repeat: no-repeat; + background-position: center; + background-size: 25%; + } + + button:active, + button:focus, + button:hover { + color: ${config.lib.stylix.colors.base0C}; + background-color: ${config.lib.stylix.colors.base02Alt}; + outline-style: none; + } + + #lock { background-image: image(url("icons/lock.png")); } + #logout { background-image: image(url("icons/logout.png")); } + #suspend { background-image: image(url("icons/suspend.png")); } + #hibernate { background-image: image(url("icons/hibernate.png")); } + #shutdown { background-image: image(url("icons/shutdown.png")); } + #reboot { background-image: image(url("icons/reboot.png")); } + ''; }; }; - style = '' - * { - background-image: none; - } - - window { - background-color: ${config.lib.stylix.colors.base00}f0 - } - - button { - margin: 8px; - color: ${config.lib.stylix.colors.base0C}; - background-color: ${config.lib.stylix.colors.base01}; - border-style: solid; - border-width: 2px; - background-repeat: no-repeat; - background-position: center; - background-size: 25%; - } - - button:active, - button:focus, - button:hover { - color: ${config.lib.stylix.colors.base0C}; - background-color: ${config.lib.stylix.colors.base02Alt}; - outline-style: none; - } - - #lock { - background-image: image(url("icons/lock.png")); - } - - #logout { - background-image: image(url("icons/logout.png")); - } - - #suspend { - background-image: image(url("icons/suspend.png")); - } - - #hibernate { - background-image: image(url("icons/hibernate.png")); - } - - #shutdown { - background-image: image(url("icons/shutdown.png")); - } - - #reboot { - background-image: image(url("icons/reboot.png")); - } - ''; - }; - }; + }) + ]; } diff --git a/modules/home/programs/wlogout/options.nix b/modules/home/programs/wlogout/options.nix deleted file mode 100644 index 3646ebb..0000000 --- a/modules/home/programs/wlogout/options.nix +++ /dev/null @@ -1,7 +0,0 @@ -{ lib, namespace, ... }: -with lib; -{ - options.${namespace}.programs.wlogout = { - enable = mkEnableOption "enable wlogout"; - }; -} diff --git a/modules/home/programs/wofi/default.nix b/modules/home/programs/wofi/default.nix index adf2e57..39eaa9f 100755 --- a/modules/home/programs/wofi/default.nix +++ b/modules/home/programs/wofi/default.nix @@ -4,103 +4,104 @@ namespace, ... }: -with lib; -let - cfg = config.${namespace}.programs.wofi; -in { - imports = [ ./options.nix ]; + imports = [ + (lib.${namespace}.mkHomeModule { + inherit config; + domain = "programs"; + name = "wofi"; + options = { + fontName = lib.mkOption { + type = lib.types.str; + default = "DejaVu Sans"; + description = "Font name for wofi."; + }; + }; + moduleConfig = { + programs.wofi = { + enable = true; + style = '' + * { + font-family: "${config.${namespace}.programs.wofi.fontName}", monospace; + font-size: 14px; + } - config = mkIf cfg.enable { - programs.wofi = { - enable = true; - style = '' - * { - font-family: "${cfg.fontName}", monospace; - font-size: 14px; - } + window { + margin: 0px; + padding: 10px; + border: 0.16em solid ${config.lib.stylix.colors.base0E}; + border-radius: 0.1em; + background-color: ${config.lib.stylix.colors.base00}; + } - /* Window */ - window { - margin: 0px; - padding: 10px; - border: 0.16em solid ${config.lib.stylix.colors.base0E}; - border-radius: 0.1em; - background-color: ${config.lib.stylix.colors.base00}; - } + #inner-box { + margin: 5px; + padding: 10px; + border: none; + background-color: ${config.lib.stylix.colors.base00}; + } - /* Inner Box */ - #inner-box { - margin: 5px; - padding: 10px; - border: none; - background-color: ${config.lib.stylix.colors.base00}; - } + #outer-box { + margin: 5px; + padding: 10px; + border: none; + background-color: ${config.lib.stylix.colors.base00}; + } - /* Outer Box */ - #outer-box { - margin: 5px; - padding: 10px; - border: none; - background-color: ${config.lib.stylix.colors.base00}; - } + #scroll { + margin: 0px; + padding: 10px; + border: none; + background-color: ${config.lib.stylix.colors.base00}; + } - /* Scroll */ - #scroll { - margin: 0px; - padding: 10px; - border: none; - background-color: ${config.lib.stylix.colors.base00}; - } + #input { + margin: 5px 20px; + padding: 10px; + border: none; + border-radius: 0.1em; + color: ${config.lib.stylix.colors.base06}; + background-color: ${config.lib.stylix.colors.base00}; + } - /* Input */ - #input { - margin: 5px 20px; - padding: 10px; - border: none; - border-radius: 0.1em; - color: ${config.lib.stylix.colors.base06}; - background-color: ${config.lib.stylix.colors.base00}; - } + #input image { + border: none; + color: ${config.lib.stylix.colors.base08}; + } - #input image { - border: none; - color: ${config.lib.stylix.colors.base08}; - } + #input * { + outline: 4px solid ${config.lib.stylix.colors.base08}!important; + } - #input * { - outline: 4px solid ${config.lib.stylix.colors.base08}!important; - } + #text { + margin: 5px; + border: none; + color: ${config.lib.stylix.colors.base06}; + } - /* Text */ - #text { - margin: 5px; - border: none; - color: ${config.lib.stylix.colors.base06}; - } + #entry { + background-color: ${config.lib.stylix.colors.base00}; + } - #entry { - background-color: ${config.lib.stylix.colors.base00}; - } + #entry arrow { + border: none; + color: ${config.lib.stylix.colors.base0E}; + } - #entry arrow { - border: none; - color: ${config.lib.stylix.colors.base0E}; - } + #entry:selected { + border: 0.11em solid ${config.lib.stylix.colors.base0E}; + } - /* Selected Entry */ - #entry:selected { - border: 0.11em solid ${config.lib.stylix.colors.base0E}; - } + #entry:selected #text { + color: ${config.lib.stylix.colors.base0C}; + } - #entry:selected #text { - color: ${config.lib.stylix.colors.base0C}; - } - - #entry:drop(active) { - background-color: ${config.lib.stylix.colors.base0E}!important; - } - ''; - }; - }; + #entry:drop(active) { + background-color: ${config.lib.stylix.colors.base0E}!important; + } + ''; + }; + }; + }) + ]; } diff --git a/modules/home/programs/wofi/options.nix b/modules/home/programs/wofi/options.nix deleted file mode 100644 index deba779..0000000 --- a/modules/home/programs/wofi/options.nix +++ /dev/null @@ -1,12 +0,0 @@ -{ lib, namespace, ... }: -with lib; -{ - options.${namespace}.programs.wofi = { - enable = mkEnableOption "enable wofi"; - - fontName = mkOption { - type = types.str; - default = "Deja Vu Sans"; - }; - }; -} diff --git a/modules/nixos/desktop/gnome/default.nix b/modules/nixos/desktop/gnome/default.nix index 85804ec..e4d6cee 100644 --- a/modules/nixos/desktop/gnome/default.nix +++ b/modules/nixos/desktop/gnome/default.nix @@ -22,7 +22,7 @@ in wayland = lib.mkDefault true; }; - gnome = { + gnome = lib.mkOverride 90 { at-spi2-core = disabled; core-apps = enabled; core-developer-tools = disabled; diff --git a/modules/nixos/network/default.nix b/modules/nixos/network/default.nix index ebb128c..1428bc3 100644 --- a/modules/nixos/network/default.nix +++ b/modules/nixos/network/default.nix @@ -144,10 +144,7 @@ in # Configure WiFi profiles if any are defined ensureProfiles = mkIf (cfg.networkmanager.profiles != { }) { - environmentFiles = [ - config.sops.secrets.wifi.path - ]; - + environmentFiles = lib.optional (config.sops.secrets ? wifi) config.sops.secrets.wifi.path; profiles = profiles; }; }) diff --git a/modules/nixos/services/authentik/default.nix b/modules/nixos/services/authentik/default.nix index 368338c..e7879c5 100644 --- a/modules/nixos/services/authentik/default.nix +++ b/modules/nixos/services/authentik/default.nix @@ -4,7 +4,6 @@ namespace, ... }: -with lib; # NOTE: AUTHENTIK_TOKEN for the RAC outpost is stored in sops. # Add jallen-nas/authentik-rac/token to secrets/nas-secrets.yaml and ensure # jallen-nas/sops.nix declares the "authentik-rac.env" template before deploying. @@ -15,37 +14,31 @@ let authentikConfig = lib.${namespace}.mkModule { inherit config name; - description = "authentik Service"; + description = "authentik identity provider"; options = { }; moduleConfig = { - services = { - authentik = { - enable = true; - environmentFile = cfg.environmentFile; - settings = { - port = cfg.port; - }; - }; + services.authentik = { + enable = true; + environmentFile = cfg.environmentFile; + settings.port = cfg.port; }; }; }; + # RAC outpost: uses podman but has a legacy container name "authenticRac" + # (different from the option name "authentikRac"), so we use mkModule directly. authentikRacConfig = lib.${namespace}.mkModule { inherit config; name = "authentikRac"; serviceName = "podman-authenticRac"; - description = "authentik_rac Service"; + description = "authentik RAC outpost"; options = { }; moduleConfig = { virtualisation.oci-containers.containers."authenticRac" = { autoStart = true; image = "ghcr.io/goauthentik/rac"; ports = [ "${toString cfgRac.port}:4822" ]; - volumes = [ - "${cfg.configDir}/authentik-rac:/media" - ]; - # AUTHENTIK_TOKEN is injected via the sops template "authentik-rac.env" - # defined in systems/x86_64-linux/jallen-nas/sops.nix + volumes = [ "${cfg.configDir}/authentik-rac:/media" ]; environmentFiles = [ config.sops.templates."authentik-rac.env".path ]; environment = { AUTHENTIK_HOST = "https://${name}.mjallen.dev"; diff --git a/modules/nixos/services/booklore/default.nix b/modules/nixos/services/booklore/default.nix index 81c4a61..c764e6a 100644 --- a/modules/nixos/services/booklore/default.nix +++ b/modules/nixos/services/booklore/default.nix @@ -4,40 +4,27 @@ namespace, ... }: -with lib; let - name = "booklore"; - cfg = config.${namespace}.services.${name}; - - bookloreConfig = lib.${namespace}.mkModule { - inherit config name; - serviceName = "podman-${name}"; - description = "booklore"; - options = { }; - moduleConfig = { - virtualisation.oci-containers.containers.${name} = { - autoStart = true; - image = "booklore/booklore"; - volumes = [ - "${cfg.configDir}/booklore:/app/data" - "${cfg.configDir}/bookdrop:/bookdrop" - "${cfg.dataDir}/books:/books" - ]; - ports = [ - "${toString cfg.port}:6060" - ]; - environment = { - DATABASE_URL = "jdbc:mariadb://10.0.1.3:3306/booklore"; - DATABASE_USERNAME = "booklore"; - DATABASE_PASSWORD = "Lucifer008!"; - PUID = cfg.puid; - PGID = cfg.pgid; - TZ = cfg.timeZone; - }; - }; - }; - }; + cfg = config.${namespace}.services.booklore; in { - imports = [ bookloreConfig ]; + imports = [ + (lib.${namespace}.mkContainerService { + inherit config; + name = "booklore"; + image = "booklore/booklore"; + internalPort = 6060; + volumes = [ + "${cfg.configDir}/booklore:/app/data" + "${cfg.configDir}/bookdrop:/bookdrop" + "${cfg.dataDir}/books:/books" + ]; + environment = { + DATABASE_URL = "jdbc:mariadb://10.0.1.3:3306/booklore"; + DATABASE_USERNAME = "booklore"; + # TODO: move DATABASE_PASSWORD to a sops secret + DATABASE_PASSWORD = "Lucifer008!"; + }; + }) + ]; } diff --git a/modules/nixos/services/dispatcharr/default.nix b/modules/nixos/services/dispatcharr/default.nix index ed9fa53..6d7fd6c 100644 --- a/modules/nixos/services/dispatcharr/default.nix +++ b/modules/nixos/services/dispatcharr/default.nix @@ -4,41 +4,25 @@ namespace, ... }: -with lib; let - name = "dispatcharr"; - cfg = config.${namespace}.services.${name}; - - dispatcharrConfig = lib.${namespace}.mkModule { - inherit config name; - serviceName = "podman-${name}"; - description = "dispatcharr podman container"; - options = { }; - moduleConfig = { - virtualisation.oci-containers.containers.${name} = { - autoStart = true; - image = "ghcr.io/dispatcharr/dispatcharr"; - extraOptions = [ "--device=/dev/dri" ]; - volumes = [ - "${cfg.configDir}/dispatcharr:/data" - "${cfg.dataDir}/movies:/movies" - "${cfg.dataDir}/tv:/tv" - ]; - ports = [ - "${toString cfg.port}:9191" - ]; - environment = { - # DISPATCHARR_LOG_LEVEL = "DEBUG"; - DISPATCHARR_ENV = "aio"; - # DJANGO_SECRET_KEY = "123456"; - # PUID = cfg.puid; - # PGID = cfg.pgid; - # TZ = cfg.timeZone; - }; - }; - }; - }; + cfg = config.${namespace}.services.dispatcharr; in { - imports = [ dispatcharrConfig ]; + imports = [ + (lib.${namespace}.mkContainerService { + inherit config; + name = "dispatcharr"; + image = "ghcr.io/dispatcharr/dispatcharr"; + internalPort = 9191; + extraOptions = [ "--device=/dev/dri" ]; + volumes = [ + "${cfg.configDir}/dispatcharr:/data" + "${cfg.dataDir}/movies:/movies" + "${cfg.dataDir}/tv:/tv" + ]; + environment = { + DISPATCHARR_ENV = "aio"; + }; + }) + ]; } diff --git a/modules/nixos/services/free-games-claimer/default.nix b/modules/nixos/services/free-games-claimer/default.nix index 6dca3eb..e0352af 100755 --- a/modules/nixos/services/free-games-claimer/default.nix +++ b/modules/nixos/services/free-games-claimer/default.nix @@ -4,32 +4,18 @@ namespace, ... }: -with lib; let - name = "free-games-claimer"; - cfg = config.${namespace}.services.${name}; - - fgcConfig = lib.${namespace}.mkModule { - inherit config name; - serviceName = "podman-${name}"; - description = "free-games-claimer"; - options = { }; - moduleConfig = { - virtualisation.oci-containers.containers."${name}" = { - autoStart = true; - image = "ghcr.io/vogler/free-games-claimer"; - ports = [ "${toString cfg.port}:6080" ]; - volumes = [ "${cfg.configDir}/free-games-claimer:/fgc/data" ]; - environmentFiles = [ config.sops.templates."fgc.env".path ]; - environment = { - PUID = cfg.puid; - PGID = cfg.pgid; - TZ = cfg.timeZone; - }; - }; - }; - }; + cfg = config.${namespace}.services."free-games-claimer"; in { - imports = [ fgcConfig ]; + imports = [ + (lib.${namespace}.mkContainerService { + inherit config; + name = "free-games-claimer"; + image = "ghcr.io/vogler/free-games-claimer"; + internalPort = 6080; + volumes = [ "${cfg.configDir}/free-games-claimer:/fgc/data" ]; + environmentFiles = [ config.sops.templates."fgc.env".path ]; + }) + ]; } diff --git a/modules/nixos/services/glance/default.nix b/modules/nixos/services/glance/default.nix index 50493af..bcfbdec 100644 --- a/modules/nixos/services/glance/default.nix +++ b/modules/nixos/services/glance/default.nix @@ -19,27 +19,6 @@ let }; }; moduleConfig = { - sops = { - secrets = { - "jallen-nas/glance/arr-username" = { - sopsFile = (lib.snowfall.fs.get-file "secrets/nas-secrets.yaml"); - }; - "jallen-nas/glance/arr-password" = { - sopsFile = (lib.snowfall.fs.get-file "secrets/nas-secrets.yaml"); - }; - }; - templates = { - "glance.env" = { - mode = "660"; - restartUnits = [ "glance.service" ]; - content = '' - ARR_USER=${config.sops.placeholder."jallen-nas/glance/arr-username"} - ARR_PASS=${config.sops.placeholder."jallen-nas/glance/arr-password"} - ''; - }; - }; - }; - services.glance = { enable = true; openFirewall = true; @@ -301,5 +280,25 @@ let }; in { - imports = [ glanceConfig ]; + imports = [ + glanceConfig + + # Sops env-file for arr credentials (gated behind glance.enable) + { + config = lib.mkIf cfg.enable ( + lib.${namespace}.mkSopsEnvFile { + name = "glance.env"; + restartUnit = "glance.service"; + secrets = { + "jallen-nas/glance/arr-username" = { }; + "jallen-nas/glance/arr-password" = { }; + }; + content = '' + ARR_USER=${config.sops.placeholder."jallen-nas/glance/arr-username"} + ARR_PASS=${config.sops.placeholder."jallen-nas/glance/arr-password"} + ''; + } + ); + } + ]; } diff --git a/modules/nixos/services/lubelogger/default.nix b/modules/nixos/services/lubelogger/default.nix index e59fe3f..395b762 100644 --- a/modules/nixos/services/lubelogger/default.nix +++ b/modules/nixos/services/lubelogger/default.nix @@ -1,40 +1,23 @@ { - config, lib, + config, namespace, ... }: -with lib; let - name = "lubelogger"; - cfg = config.${namespace}.services.${name}; - - lubeloggerConfig = lib.${namespace}.mkModule { - inherit config name; - serviceName = "podman-${name}"; - description = "lubelogger"; - options = { }; - moduleConfig = { - virtualisation.oci-containers.containers.lubelogger = { - autoStart = true; - image = "ghcr.io/hargata/lubelogger"; - ports = [ "${toString cfg.port}:8080" ]; - volumes = [ - "${cfg.configDir}/lubelogger:/App/data" - "${cfg.configDir}/lubelogger/keys:/root/.aspnet/DataProtection-Keys" - ]; - # environmentFiles = [ - # "${cfg.configDir}/lubelogger/lubelogger.env" - # ]; - environment = { - PUID = toString config.users.users.nix-apps.uid; - PGID = toString config.users.groups.jallen-nas.gid; - TZ = "America/Chicago"; - }; - }; - }; - }; + cfg = config.${namespace}.services.lubelogger; in { - imports = [ lubeloggerConfig ]; + imports = [ + (lib.${namespace}.mkContainerService { + inherit config; + name = "lubelogger"; + image = "ghcr.io/hargata/lubelogger"; + internalPort = 8080; + volumes = [ + "${cfg.configDir}/lubelogger:/App/data" + "${cfg.configDir}/lubelogger/keys:/root/.aspnet/DataProtection-Keys" + ]; + }) + ]; } diff --git a/modules/nixos/services/manyfold/default.nix b/modules/nixos/services/manyfold/default.nix index f0eef1e..96f3da1 100755 --- a/modules/nixos/services/manyfold/default.nix +++ b/modules/nixos/services/manyfold/default.nix @@ -4,43 +4,29 @@ namespace, ... }: -with lib; let - name = "manyfold"; - cfg = config.${namespace}.services.${name}; - - manyfoldConfig = lib.${namespace}.mkModule { - inherit config name; - serviceName = "podman-${name}"; - description = "manyfold"; - options = { }; - moduleConfig = { - virtualisation.oci-containers.containers."${name}" = { - autoStart = true; - image = "ghcr.io/manyfold3d/manyfold-solo"; - ports = [ "${toString cfg.port}:3214" ]; - extraOptions = [ - "--cap-drop=ALL" - "--cap-add=CHOWN" - "--cap-add=DAC_OVERRIDE" - "--cap-add=SETUID" - "--cap-add=SETGID" - "--security-opt=no-new-privileges:true" - ]; - volumes = [ - "${cfg.configDir}/manyfold:/config" - "${cfg.dataDir}/documents/3d-models:/libraries" - ]; - environment = { - PUID = cfg.puid; - PGID = cfg.pgid; - TZ = cfg.timeZone; - }; - environmentFiles = [ config.sops.secrets."jallen-nas/manyfold/secretkeybase".path ]; - }; - }; - }; + cfg = config.${namespace}.services.manyfold; in { - imports = [ manyfoldConfig ]; + imports = [ + (lib.${namespace}.mkContainerService { + inherit config; + name = "manyfold"; + image = "ghcr.io/manyfold3d/manyfold-solo"; + internalPort = 3214; + extraOptions = [ + "--cap-drop=ALL" + "--cap-add=CHOWN" + "--cap-add=DAC_OVERRIDE" + "--cap-add=SETUID" + "--cap-add=SETGID" + "--security-opt=no-new-privileges:true" + ]; + volumes = [ + "${cfg.configDir}/manyfold:/config" + "${cfg.dataDir}/documents/3d-models:/libraries" + ]; + environmentFiles = [ config.sops.secrets."jallen-nas/manyfold/secretkeybase".path ]; + }) + ]; } diff --git a/modules/nixos/services/netbootxyz/default.nix b/modules/nixos/services/netbootxyz/default.nix index 19b5fa3..22a5270 100644 --- a/modules/nixos/services/netbootxyz/default.nix +++ b/modules/nixos/services/netbootxyz/default.nix @@ -1,54 +1,39 @@ { - config, lib, + config, namespace, ... }: -with lib; let - inherit (lib.${namespace}) mkOpt; - name = "netbootxyz"; - cfg = config.${namespace}.services.${name}; - - netbootxyzConfig = lib.${namespace}.mkModule { - inherit config name; - description = "netbootxyz"; - options = { - assetPort = mkOpt types.port 4001 "NGINX server for hosting assets."; - - tftpPort = mkOpt types.port 69 "HTTPS port for netbootxyz"; - }; - moduleConfig = { - # Open firewall for netbootxyz if enabled - networking.firewall = mkIf cfg.openFirewall { - allowedTCPPorts = [ - cfg.assetPort - cfg.tftpPort - ]; - allowedUDPPorts = [ - cfg.assetPort - cfg.tftpPort - ]; - }; - - virtualisation.oci-containers = { - containers.netbootxyz = { - autoStart = true; - image = "ghcr.io/netbootxyz/netbootxyz:latest"; - ports = [ - "${toString cfg.port}:3000" - "${toString cfg.assetPort}:80" - "${toString cfg.tftpPort}:69" - ]; - volumes = [ - "${cfg.configDir}/netbootxyz:/config" - "${cfg.dataDir}/isos:/assets" - ]; - }; - }; - }; - }; + inherit (lib.${namespace}) mkOpt mkContainerService; + cfg = config.${namespace}.services.netbootxyz; in { - imports = [ netbootxyzConfig ]; + imports = [ + (mkContainerService { + inherit config; + name = "netbootxyz"; + image = "ghcr.io/netbootxyz/netbootxyz:latest"; + internalPort = 3000; + options = { + assetPort = mkOpt lib.types.port 4001 "NGINX port for hosting assets"; + tftpPort = mkOpt lib.types.port 69 "TFTP port"; + }; + volumes = [ + "${cfg.configDir}/netbootxyz:/config" + "${cfg.dataDir}/isos:/assets" + ]; + extraConfig = { + networking.firewall = lib.mkIf cfg.openFirewall { + allowedTCPPorts = [ cfg.assetPort cfg.tftpPort ]; + allowedUDPPorts = [ cfg.assetPort cfg.tftpPort ]; + }; + virtualisation.oci-containers.containers.netbootxyz.ports = lib.mkForce [ + "${toString cfg.port}:3000" + "${toString cfg.assetPort}:80" + "${toString cfg.tftpPort}:69" + ]; + }; + }) + ]; } diff --git a/modules/nixos/services/orca/default.nix b/modules/nixos/services/orca/default.nix index e99ede1..b329756 100644 --- a/modules/nixos/services/orca/default.nix +++ b/modules/nixos/services/orca/default.nix @@ -4,37 +4,27 @@ namespace, ... }: -with lib; let - inherit (lib.${namespace}) mkOpt; - name = "orca-slicer"; - cfg = config.${namespace}.services.${name}; - - orcaConfig = lib.${namespace}.mkModule { - inherit config name; - serviceName = "podman-${name}"; - description = "orca slicer web ui"; - options = { - httpsPort = mkOpt types.int 443 "HTTPS port"; - }; - moduleConfig = { - virtualisation.oci-containers.containers."${name}" = { - autoStart = true; - image = "linuxserver/orcaslicer"; - ports = [ + inherit (lib.${namespace}) mkOpt mkContainerService; + cfg = config.${namespace}.services."orca-slicer"; +in +{ + imports = [ + (mkContainerService { + inherit config; + name = "orca-slicer"; + image = "linuxserver/orcaslicer"; + internalPort = 3000; + options = { + httpsPort = mkOpt lib.types.int 443 "HTTPS port"; + }; + extraConfig = { + virtualisation.oci-containers.containers."orca-slicer".ports = lib.mkForce [ "${toString cfg.port}:3000" "${toString cfg.httpsPort}:3001" ]; - volumes = [ "${cfg.configDir}/orca-slicer:/config" ]; - environment = { - PUID = cfg.puid; - PGID = cfg.pgid; - TZ = cfg.timeZone; - }; }; - }; - }; -in -{ - imports = [ orcaConfig ]; + volumes = [ "${cfg.configDir}/orca-slicer:/config" ]; + }) + ]; } diff --git a/modules/nixos/services/sparky-fitness/default.nix b/modules/nixos/services/sparky-fitness/default.nix index a4ed2ea..4120a9d 100644 --- a/modules/nixos/services/sparky-fitness/default.nix +++ b/modules/nixos/services/sparky-fitness/default.nix @@ -4,118 +4,74 @@ namespace, ... }: -with lib; let - name = "sparky-fitness-server"; - cfg = config.${namespace}.services.${name}; - - sparky-fitness-server = lib.${namespace}.mkModule { - inherit config name; - serviceName = "podman-${name}"; - description = "sparky-fitness-server"; - options = { }; - moduleConfig = { - virtualisation.oci-containers.containers.${name} = { - autoStart = true; - image = "codewithcj/sparkyfitness_server"; - ports = [ "${toString cfg.port}:3010" ]; - volumes = [ - "${cfg.configDir}/sparky-fitness/server/backup:/app/SparkyFitnessServer/backup" - "${cfg.configDir}/sparky-fitness/server/uploads:/app/SparkyFitnessServer/uploads" - ]; - # environmentFiles = [ - # "${cfg.configDir}/lubelogger/lubelogger.env" - # ]; - environment = { - SPARKY_FITNESS_LOG_LEVEL = "0"; - ALLOW_PRIVATE_NETWORK_CORS = "false"; - SPARKY_FITNESS_EXTRA_TRUSTED_ORIGINS = ""; - SPARKY_FITNESS_DB_USER = "sparkyfitness"; - SPARKY_FITNESS_DB_HOST = "10.0.1.3"; # Use the service name 'sparkyfitness-db' for inter-container communication - SPARKY_FITNESS_DB_NAME = "sparkyfitness"; - SPARKY_FITNESS_DB_PASSWORD = "sparkyfitness"; - SPARKY_FITNESS_APP_DB_USER = "sparkyfitness"; - SPARKY_FITNESS_APP_DB_PASSWORD = "sparkyfitness"; - SPARKY_FITNESS_DB_PORT = "${toString dbCfg.port}"; - SPARKY_FITNESS_API_ENCRYPTION_KEY = "088ab2c6487ca1048c1fe74a4d8bd906e88db56953406769426b615d6df2407b"; - # Uncomment the line below and comment the line above to use a file-based secret - # SPARKY_FITNESS_API_ENCRYPTION_KEY_FILE: /run/secrets/sparkyfitness_api_key - - BETTER_AUTH_SECRET = "a0304bda5a9efd0d92595c8d46526e33d58f436408f6b70ea37c2b84308d9abe"; - # Uncomment the line below and comment the line above to use a file-based secret - # BETTER_AUTH_SECRET_FILE: /run/secrets/sparkyfitness_better_auth_secret - SPARKY_FITNESS_FRONTEND_URL = "http://10.0.1.3:${toString frontendCfg.port}"; - SPARKY_FITNESS_DISABLE_SIGNUP = "false"; - SPARKY_FITNESS_ADMIN_EMAIL = "jalle008@proton.me"; #User with this email can access the admin panel - # SPARKY_FITNESS_EMAIL_HOST = "${SPARKY_FITNESS_EMAIL_HOST}"; - # SPARKY_FITNESS_EMAIL_PORT = "${SPARKY_FITNESS_EMAIL_PORT}"; - # SPARKY_FITNESS_EMAIL_SECURE = "${SPARKY_FITNESS_EMAIL_SECURE}"; - # SPARKY_FITNESS_EMAIL_USER = "${SPARKY_FITNESS_EMAIL_USER}"; - # SPARKY_FITNESS_EMAIL_PASS = "${SPARKY_FITNESS_EMAIL_PASS}"; - # SPARKY_FITNESS_EMAIL_FROM = "${SPARKY_FITNESS_EMAIL_FROM}"; - PUID = toString config.users.users.nix-apps.uid; - PGID = toString config.users.groups.jallen-nas.gid; - TZ = "America/Chicago"; - }; - }; - }; - }; - - fontendName = "sparky-fitness"; - frontendCfg = config.${namespace}.services.${fontendName}; - - sparky-fitness-frontend = lib.${namespace}.mkModule { - inherit config; - name = fontendName; - serviceName = "podman-${fontendName}"; - description = "sparky-fitness"; - options = { }; - moduleConfig = { - virtualisation.oci-containers.containers.${fontendName} = { - autoStart = true; - image = "codewithcj/sparkyfitness"; - ports = [ "${toString frontendCfg.port}:80" ]; - environment = { - SPARKY_FITNESS_FRONTEND_URL = "http://10.0.1.3:${toString frontendCfg.port}"; - SPARKY_FITNESS_SERVER_HOST = "10.0.1.3"; - SPARKY_FITNESS_SERVER_PORT = "${toString cfg.port}"; - PUID = toString config.users.users.nix-apps.uid; - PGID = toString config.users.groups.jallen-nas.gid; - TZ = "America/Chicago"; - }; - }; - }; - }; + inherit (lib.${namespace}) mkContainerService; + serverName = "sparky-fitness-server"; + frontendName = "sparky-fitness"; dbName = "sparky-fitness-db"; + + serverCfg = config.${namespace}.services.${serverName}; + frontendCfg = config.${namespace}.services.${frontendName}; dbCfg = config.${namespace}.services.${dbName}; - - sparky-fitness-db = lib.${namespace}.mkModule { - inherit config; - name = dbName; - serviceName = "podman-${dbName}"; - description = "sparky-fitness-db"; - options = { }; - moduleConfig = { - virtualisation.oci-containers.containers.${dbName} = { - autoStart = true; - image = "postgres:15-alpine"; - ports = [ "${toString dbCfg.port}:5432" ]; - volumes = [ - "${dbCfg.configDir}/sparky-fitness/db:/var/lib/postgresql/data" - ]; - environment = { - POSTGRES_DB = "sparkyfitness-db"; - POSTGRES_USER = "sparkyfitness"; - POSTGRES_PASSWORD = "sparkyfitness"; - PUID = toString config.users.users.nix-apps.uid; - PGID = toString config.users.groups.jallen-nas.gid; - TZ = "America/Chicago"; - }; - }; - }; - }; in { - imports = [ sparky-fitness-server sparky-fitness-frontend sparky-fitness-db ]; + imports = [ + (mkContainerService { + inherit config; + name = serverName; + image = "codewithcj/sparkyfitness_server"; + internalPort = 3010; + volumes = [ + "${serverCfg.configDir}/sparky-fitness/server/backup:/app/SparkyFitnessServer/backup" + "${serverCfg.configDir}/sparky-fitness/server/uploads:/app/SparkyFitnessServer/uploads" + ]; + environment = { + SPARKY_FITNESS_LOG_LEVEL = "0"; + ALLOW_PRIVATE_NETWORK_CORS = "false"; + SPARKY_FITNESS_EXTRA_TRUSTED_ORIGINS = ""; + SPARKY_FITNESS_DB_USER = "sparkyfitness"; + SPARKY_FITNESS_DB_HOST = "10.0.1.3"; + SPARKY_FITNESS_DB_NAME = "sparkyfitness"; + # TODO: move DB password and secrets to sops + SPARKY_FITNESS_DB_PASSWORD = "sparkyfitness"; + SPARKY_FITNESS_APP_DB_USER = "sparkyfitness"; + SPARKY_FITNESS_APP_DB_PASSWORD = "sparkyfitness"; + SPARKY_FITNESS_DB_PORT = "${toString dbCfg.port}"; + SPARKY_FITNESS_API_ENCRYPTION_KEY = "088ab2c6487ca1048c1fe74a4d8bd906e88db56953406769426b615d6df2407b"; + BETTER_AUTH_SECRET = "a0304bda5a9efd0d92595c8d46526e33d58f436408f6b70ea37c2b84308d9abe"; + SPARKY_FITNESS_FRONTEND_URL = "http://10.0.1.3:${toString frontendCfg.port}"; + SPARKY_FITNESS_DISABLE_SIGNUP = "false"; + SPARKY_FITNESS_ADMIN_EMAIL = "jalle008@proton.me"; + }; + }) + + (mkContainerService { + inherit config; + name = frontendName; + image = "codewithcj/sparkyfitness"; + internalPort = 80; + environment = { + SPARKY_FITNESS_FRONTEND_URL = "http://10.0.1.3:${toString frontendCfg.port}"; + SPARKY_FITNESS_SERVER_HOST = "10.0.1.3"; + SPARKY_FITNESS_SERVER_PORT = "${toString serverCfg.port}"; + }; + }) + + (mkContainerService { + inherit config; + name = dbName; + image = "postgres:15-alpine"; + internalPort = 5432; + volumes = [ + "${dbCfg.configDir}/sparky-fitness/db:/var/lib/postgresql/data" + ]; + environment = { + POSTGRES_DB = "sparkyfitness-db"; + POSTGRES_USER = "sparkyfitness"; + # TODO: move POSTGRES_PASSWORD to sops + POSTGRES_PASSWORD = "sparkyfitness"; + }; + }) + ]; } diff --git a/modules/nixos/services/tdarr/default.nix b/modules/nixos/services/tdarr/default.nix index 92806cc..ce62279 100755 --- a/modules/nixos/services/tdarr/default.nix +++ b/modules/nixos/services/tdarr/default.nix @@ -4,52 +4,45 @@ namespace, ... }: -with lib; let - inherit (lib.${namespace}) mkOpt; - name = "tdarr"; - cfg = config.${namespace}.services.${name}; - - tdarrConfig = lib.${namespace}.mkModule { - inherit config name; - description = "tdarr"; - options = { - serverPort = mkOpt types.str "8266" "node port"; - }; - moduleConfig = { - virtualisation.oci-containers.containers.${name} = { - autoStart = true; - image = "ghcr.io/haveagitgat/tdarr"; - extraOptions = [ "--device=nvidia.com/gpu=0" ]; - volumes = [ - "${cfg.configDir}/tdarr/config:/app/configs" - "${cfg.configDir}/tdarr/server:/app/server" - "${cfg.configDir}/tdarr/logs:/app/logs" - "${cfg.configDir}/tdarr/transcode:/temp" - "${cfg.dataDir}/movies:/data/movies" - "${cfg.dataDir}/tv:/data/tv" - ]; - ports = [ - "${cfg.serverPort}:8266" - "${cfg.port}:8265" - ]; - environment = { - serverPort = "8266"; - webUIPort = "8265"; - internalNode = "true"; - inContainer = "true"; - ffmpegVersion = "6"; - nodeName = "tdarr node"; - NVIDIA_VISIBLE_DEVICES = "all"; - NVIDIA_DRIVER_CAPABILITIES = "all"; - PUID = cfg.puid; - PGID = cfg.pgid; - TZ = cfg.timeZone; - }; - }; - }; - }; + inherit (lib.${namespace}) mkOpt mkContainerService; + cfg = config.${namespace}.services.tdarr; in { - imports = [ tdarrConfig ]; + imports = [ + (mkContainerService { + inherit config; + name = "tdarr"; + image = "ghcr.io/haveagitgat/tdarr"; + internalPort = 8265; + options = { + serverPort = mkOpt lib.types.str "8266" "Tdarr node server port"; + }; + extraOptions = [ "--device=nvidia.com/gpu=0" ]; + volumes = [ + "${cfg.configDir}/tdarr/config:/app/configs" + "${cfg.configDir}/tdarr/server:/app/server" + "${cfg.configDir}/tdarr/logs:/app/logs" + "${cfg.configDir}/tdarr/transcode:/temp" + "${cfg.dataDir}/movies:/data/movies" + "${cfg.dataDir}/tv:/data/tv" + ]; + environment = { + serverPort = "8266"; + webUIPort = "8265"; + internalNode = "true"; + inContainer = "true"; + ffmpegVersion = "6"; + nodeName = "tdarr node"; + NVIDIA_VISIBLE_DEVICES = "all"; + NVIDIA_DRIVER_CAPABILITIES = "all"; + }; + extraConfig = { + virtualisation.oci-containers.containers.tdarr.ports = lib.mkForce [ + "${cfg.serverPort}:8266" + "${toString cfg.port}:8265" + ]; + }; + }) + ]; } diff --git a/modules/nixos/services/termix/default.nix b/modules/nixos/services/termix/default.nix index a463aaa..456f4f0 100644 --- a/modules/nixos/services/termix/default.nix +++ b/modules/nixos/services/termix/default.nix @@ -4,66 +4,44 @@ namespace, ... }: -with lib; let - name = "termix"; - cfg = config.${namespace}.services.${name}; - - termixConfig = lib.${namespace}.mkModule { - inherit config name; - serviceName = "podman-${name}"; - description = "termix"; - options = { }; - moduleConfig = { - sops = { - secrets = { - "jallen-nas/termix/client-id" = { - sopsFile = (lib.snowfall.fs.get-file "secrets/nas-secrets.yaml"); - }; - "jallen-nas/termix/client-secret" = { - sopsFile = (lib.snowfall.fs.get-file "secrets/nas-secrets.yaml"); - }; - }; - templates = { - "termix.env" = { - mode = "660"; - owner = "nix-apps"; - group = "jallen-nas"; - restartUnits = [ "podman-termix.service" ]; - content = '' - OIDC_CLIENT_ID=${config.sops.placeholder."jallen-nas/termix/client-id"} - OIDC_CLIENT_SECRET=${config.sops.placeholder."jallen-nas/termix/client-secret"} - ''; - }; - }; - }; - - virtualisation.oci-containers.containers.${name} = { - autoStart = true; - image = "ghcr.io/lukegus/termix"; - volumes = [ - "${cfg.configDir}/termix:/app/data" - ]; - ports = [ - "${toString cfg.port}:8080" - ]; - environment = { - OIDC_ISSUER_URL = "https://authentik.mjallen.dev/application/o/termix/"; - OIDC_AUTHORIZATION_URL = "https://authentik.mjallen.dev/application/o/authorize/"; - OIDC_TOKEN_URL = "https://authentik.mjallen.dev/application/o/token/"; - OIDC_FORCE_HTTPS = "true"; - GUACD_HOST = "10.0.1.3"; - PUID = cfg.puid; - PGID = cfg.pgid; - TZ = cfg.timeZone; - }; - }; - }; - }; + cfg = config.${namespace}.services.termix; + inherit (lib.${namespace}) mkSopsEnvFile mkContainerService; in { imports = [ ./guacd.nix - termixConfig + + # Sops env-file for OIDC credentials + { + config = lib.mkIf cfg.enable (mkSopsEnvFile { + name = "termix.env"; + restartUnit = "podman-termix.service"; + secrets = { + "jallen-nas/termix/client-id" = { }; + "jallen-nas/termix/client-secret" = { }; + }; + content = '' + OIDC_CLIENT_ID=${config.sops.placeholder."jallen-nas/termix/client-id"} + OIDC_CLIENT_SECRET=${config.sops.placeholder."jallen-nas/termix/client-secret"} + ''; + }); + } + + (mkContainerService { + inherit config; + name = "termix"; + image = "ghcr.io/lukegus/termix"; + internalPort = 8080; + volumes = [ "${cfg.configDir}/termix:/app/data" ]; + environmentFiles = [ config.sops.templates."termix.env".path ]; + environment = { + OIDC_ISSUER_URL = "https://authentik.mjallen.dev/application/o/termix/"; + OIDC_AUTHORIZATION_URL = "https://authentik.mjallen.dev/application/o/authorize/"; + OIDC_TOKEN_URL = "https://authentik.mjallen.dev/application/o/token/"; + OIDC_FORCE_HTTPS = "true"; + GUACD_HOST = "10.0.1.3"; + }; + }) ]; } diff --git a/modules/nixos/services/termix/guacd.nix b/modules/nixos/services/termix/guacd.nix index 86b0712..bdb2b9b 100644 --- a/modules/nixos/services/termix/guacd.nix +++ b/modules/nixos/services/termix/guacd.nix @@ -4,32 +4,13 @@ namespace, ... }: -with lib; -let - name = "guacd"; - cfg = config.${namespace}.services.${name}; - - guacdConfig = lib.${namespace}.mkModule { - inherit config name; - serviceName = "podman-${name}"; - description = "guacd"; - options = { }; - moduleConfig = { - virtualisation.oci-containers.containers.${name} = { - autoStart = true; - image = "guacamole/guacd"; - ports = [ - "${toString cfg.port}:4822" - ]; - environment = { - PUID = cfg.puid; - PGID = cfg.pgid; - TZ = cfg.timeZone; - }; - }; - }; - }; -in { - imports = [ guacdConfig ]; + imports = [ + (lib.${namespace}.mkContainerService { + inherit config; + name = "guacd"; + image = "guacamole/guacd"; + internalPort = 4822; + }) + ]; } diff --git a/modules/nixos/services/tunarr/default.nix b/modules/nixos/services/tunarr/default.nix index af0c4b9..eedaac9 100644 --- a/modules/nixos/services/tunarr/default.nix +++ b/modules/nixos/services/tunarr/default.nix @@ -4,40 +4,24 @@ namespace, ... }: -with lib; let - name = "tunarr"; - cfg = config.${namespace}.services.${name}; - - tunarrConfig = lib.${namespace}.mkModule { - inherit config name; - serviceName = "podman-${name}"; - description = "tunarr"; - options = { }; - moduleConfig = { - virtualisation.oci-containers.containers.${name} = { - autoStart = true; - image = "ghcr.io/chrisbenincasa/tunarr"; - extraOptions = [ "--device=/dev/dri" ]; - volumes = [ - "${cfg.configDir}/tunarr:/config/tunarr" - "${cfg.configDir}/tunarr:/root/.local/share/tunarr" - "${cfg.dataDir}/movies:/libraries/movies" - "${cfg.dataDir}/tv:/libraries/tv" - "${cfg.configDir}/transcode:/transcode" - ]; - ports = [ - "${toString cfg.port}:8000" - ]; - environment = { - PUID = cfg.puid; - PGID = cfg.pgid; - TZ = cfg.timeZone; - }; - }; - }; - }; + cfg = config.${namespace}.services.tunarr; in { - imports = [ tunarrConfig ]; + imports = [ + (lib.${namespace}.mkContainerService { + inherit config; + name = "tunarr"; + image = "ghcr.io/chrisbenincasa/tunarr"; + internalPort = 8000; + extraOptions = [ "--device=/dev/dri" ]; + volumes = [ + "${cfg.configDir}/tunarr:/config/tunarr" + "${cfg.configDir}/tunarr:/root/.local/share/tunarr" + "${cfg.dataDir}/movies:/libraries/movies" + "${cfg.dataDir}/tv:/libraries/tv" + "${cfg.configDir}/transcode:/transcode" + ]; + }) + ]; } diff --git a/modules/nixos/services/unmanic/default.nix b/modules/nixos/services/unmanic/default.nix index 86a37dc..27f5260 100644 --- a/modules/nixos/services/unmanic/default.nix +++ b/modules/nixos/services/unmanic/default.nix @@ -4,41 +4,23 @@ namespace, ... }: -with lib; let - name = "unmanic"; - cfg = config.${namespace}.services.${name}; - - unmanicConfig = lib.${namespace}.mkModule { - inherit config name; - serviceName = "podman-${name}"; - description = "unmanic"; - options = { }; - moduleConfig = { - virtualisation.oci-containers.containers.${name} = { - autoStart = true; - image = "josh5/unmanic"; - devices = [ - "/dev/dri:/dev/dri" - ]; - volumes = [ - "${cfg.configDir}/unmanic:/config" - "${cfg.dataDir}/movies:/library/movies" - "${cfg.dataDir}/tv:/library/tv" - "${cfg.configDir}/unmanic/transcode:/tmp/unmanic" - ]; - ports = [ - "${toString cfg.port}:8888" - ]; - environment = { - PUID = cfg.puid; - PGID = cfg.pgid; - TZ = cfg.timeZone; - }; - }; - }; - }; + cfg = config.${namespace}.services.unmanic; in { - imports = [ unmanicConfig ]; + imports = [ + (lib.${namespace}.mkContainerService { + inherit config; + name = "unmanic"; + image = "josh5/unmanic"; + internalPort = 8888; + devices = [ "/dev/dri:/dev/dri" ]; + volumes = [ + "${cfg.configDir}/unmanic:/config" + "${cfg.dataDir}/movies:/library/movies" + "${cfg.dataDir}/tv:/library/tv" + "${cfg.configDir}/unmanic/transcode:/tmp/unmanic" + ]; + }) + ]; } diff --git a/modules/nixos/services/your-spotify/default.nix b/modules/nixos/services/your-spotify/default.nix index 84d6964..679f00d 100755 --- a/modules/nixos/services/your-spotify/default.nix +++ b/modules/nixos/services/your-spotify/default.nix @@ -4,43 +4,54 @@ namespace, ... }: -with lib; let - cfg = config.${namespace}.services.your_spotify; + inherit (lib.${namespace}) mkOpt mkModule; + name = "your-spotify"; + cfg = config.${namespace}.services.${name}; in { - imports = [ ./options.nix ]; - - config = mkIf cfg.enable { - - virtualisation.oci-containers.containers."${cfg.name}-server" = { - autoStart = true; - image = cfg.imageServer; - volumes = [ "${cfg.configPath}:/root/.your-spotify" ]; - ports = [ "${cfg.portServer}:8080" ]; - dependsOn = [ "mongo" ]; - environment = { - PUID = cfg.puid; - PGID = cfg.pgid; - TZ = cfg.timeZone; - API_ENDPOINT = "https://your-spotify-server.mjallen.dev"; - CLIENT_ENDPOINT = "https://your-spotify.mjallen.dev"; - SPOTIFY_PUBLIC = "e270589d72a6494680a17d325af8670d"; - SPOTIFY_SECRET = "423cb7b69fe8486e89eccd01e0c22924"; - MONGO_ENDPOINT = "mongodb://10.0.1.3:27017"; + imports = [ + (mkModule { + inherit config name; + description = "Your Spotify — self-hosted Spotify stats"; + options = { + serverPort = mkOpt lib.types.int 7777 "Port for the API server container"; + webPort = mkOpt lib.types.int 7778 "Port for the web client container"; + imageServer = mkOpt lib.types.str "yooooomi/your_spotify_server" "Server OCI image"; + imageWeb = mkOpt lib.types.str "yooooomi/your_spotify_client" "Web client OCI image"; }; - }; + moduleConfig = { + virtualisation.oci-containers.containers."${name}-server" = { + autoStart = true; + image = cfg.imageServer; + volumes = [ "${cfg.configDir}:/root/.your-spotify" ]; + ports = [ "${toString cfg.serverPort}:8080" ]; + dependsOn = [ "mongo" ]; + environment = { + PUID = cfg.puid; + PGID = cfg.pgid; + TZ = cfg.timeZone; + API_ENDPOINT = "https://your-spotify-server.mjallen.dev"; + CLIENT_ENDPOINT = "https://your-spotify.mjallen.dev"; + # TODO: move Spotify API keys to sops secrets + SPOTIFY_PUBLIC = "e270589d72a6494680a17d325af8670d"; + SPOTIFY_SECRET = "423cb7b69fe8486e89eccd01e0c22924"; + MONGO_ENDPOINT = "mongodb://10.0.1.3:27017"; + }; + }; - virtualisation.oci-containers.containers."${cfg.name}-web" = { - autoStart = true; - image = cfg.imageWeb; - ports = [ "${cfg.portWeb}:3000" ]; - environment = { - PUID = cfg.puid; - PGID = cfg.pgid; - TZ = cfg.timeZone; - API_ENDPOINT = "https://your-spotify-server.mjallen.dev"; + virtualisation.oci-containers.containers."${name}-web" = { + autoStart = true; + image = cfg.imageWeb; + ports = [ "${toString cfg.webPort}:3000" ]; + environment = { + PUID = cfg.puid; + PGID = cfg.pgid; + TZ = cfg.timeZone; + API_ENDPOINT = "https://your-spotify-server.mjallen.dev"; + }; + }; }; - }; - }; + }) + ]; } diff --git a/modules/nixos/services/your-spotify/options.nix b/modules/nixos/services/your-spotify/options.nix deleted file mode 100755 index 88f86b4..0000000 --- a/modules/nixos/services/your-spotify/options.nix +++ /dev/null @@ -1,57 +0,0 @@ -{ lib, namespace, ... }: -with lib; -{ - options.${namespace}.services.your_spotify = { - enable = mkEnableOption "your_spotify docker service"; - - autoStart = mkOption { - type = types.bool; - default = true; - }; - - portServer = mkOption { - type = types.str; - default = "7777"; - }; - - portWeb = mkOption { - type = types.str; - default = "7778"; - }; - - name = mkOption { - type = types.str; - default = "your_spotify"; - }; - - imageServer = mkOption { - type = types.str; - default = "yooooomi/your_spotify_server"; - }; - - imageWeb = mkOption { - type = types.str; - default = "yooooomi/your_spotify_client"; - }; - - configPath = mkOption { - type = types.str; - default = "/var/lib/your-spotify"; - }; - - puid = mkOption { - type = types.str; - default = "911"; - }; - - pgid = mkOption { - type = types.str; - default = "100"; - }; - - timeZone = mkOption { - type = types.str; - default = "UTC"; - }; - }; -} diff --git a/modules/nixos/sops/default.nix b/modules/nixos/sops/default.nix index d271a75..0a7e75b 100644 --- a/modules/nixos/sops/default.nix +++ b/modules/nixos/sops/default.nix @@ -9,9 +9,10 @@ let cfg = config.${namespace}.sops; defaultSops = lib.snowfall.fs.get-file "secrets/secrets.yaml"; isx86 = system == "x86_64-linux"; - user = config.${namespace}.user.name; in { + imports = [ ./options.nix ]; + config = lib.mkIf cfg.enable { sops = { defaultSopsFile = if cfg.defaultSopsFile != null then cfg.defaultSopsFile else defaultSops; @@ -19,16 +20,13 @@ in secrets = { "wifi" = { }; + "disk-key".mode = "0600"; "matt_password" = { neededForUsers = true; mode = "0600"; - owner = config.users.users."${user}".name; - group = config.users.users."${user}".group; }; - "disk-key".mode = "0600"; - "secureboot/GUID" = lib.mkIf isx86 { mode = "0600"; }; "secureboot/keys/db-key" = lib.mkIf isx86 { mode = "0600"; }; "secureboot/keys/db-pem" = lib.mkIf isx86 { mode = "0600"; }; @@ -37,8 +35,6 @@ in "secureboot/keys/PK-key" = lib.mkIf isx86 { mode = "0600"; }; "secureboot/keys/PK-pem" = lib.mkIf isx86 { mode = "0600"; }; }; - - templates = { }; }; }; } diff --git a/modules/nixos/sops/options.nix b/modules/nixos/sops/options.nix index 96a73c2..2626b22 100644 --- a/modules/nixos/sops/options.nix +++ b/modules/nixos/sops/options.nix @@ -5,7 +5,7 @@ with lib; enable = mkEnableOption "enable sops"; defaultSopsFile = mkOption { - type = types.nullOr types.str; + type = types.nullOr types.path; default = null; description = "Default sops file to use for secrets. If null, will use the system-wide default."; example = "/etc/nixos/secrets/secrets.yaml"; diff --git a/modules/nixos/user/default.nix b/modules/nixos/user/default.nix index f1dabed..6864537 100644 --- a/modules/nixos/user/default.nix +++ b/modules/nixos/user/default.nix @@ -8,20 +8,27 @@ with lib; let inherit (lib.${namespace}) mkOpt mkBoolOpt; - cfg = config.${namespace}.user // { - hashedPasswordFile = ( - if - ( - config.${namespace}.user.hashedPassword == null - && config.${namespace}.user.hashedPasswordFile == null - && config.${namespace}.user.password == null - ) - then - defaultPasswordFile - else - config.${namespace}.user.hashedPasswordFile - ); - }; + cfg = config.${namespace}.user; + + # Reference the sops-managed password file only when the secret has been + # declared somewhere in the configuration. Checking the attrset with ? + # avoids forcing evaluation of the secret path on hosts that don't use sops. + sopsMattPassword = + let + secretName = cfg.sopsPasswordSecret; + in + if secretName != null && builtins.hasAttr secretName config.sops.secrets then + config.sops.secrets.${secretName}.path + else + null; + + # Fall back to the sops-managed password file only when no explicit password + # method has been set by the caller. + resolvedPasswordFile = + if cfg.hashedPassword == null && cfg.hashedPasswordFile == null && cfg.password == null then + sopsMattPassword + else + cfg.hashedPasswordFile; # Common SSH keys used across systems commonSshKeys = [ @@ -39,7 +46,6 @@ let "ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBGdwsYDOkjd17rKdpjKN+3Yx1rRHT/Fiv2erc2JdE6ibHKBxLSEZ4kCOFCyGyc5ZO6Cmb09GfAe9FugkD4titns= cardno:33_720_987" ]; - defaultPasswordFile = config.sops.secrets."matt_password".path; in { options.${namespace}.user = with types; { @@ -73,7 +79,11 @@ in hashedPasswordFile = mkOpt (nullOr path) null "Path to the password file for this user account"; - mutableUsers = mkBoolOpt false "Whether users are mutable (can be modified after creation)."; + sopsPasswordSecret = + mkOpt (nullOr str) "matt_password" + "Name of the sops secret to use as the hashed password file when no explicit password method is set. Set to null to disable the sops fallback."; + + mutableUsers = mkBoolOpt false "Whether users are mutable (can be modified after modification)."; }; config = { @@ -94,8 +104,8 @@ in packages password hashedPassword - hashedPasswordFile ; + hashedPasswordFile = resolvedPasswordFile; extraGroups = [ "wheel" @@ -137,8 +147,8 @@ in assertions = [ { assertion = - (cfg.password != null) || (cfg.hashedPassword != null) || (cfg.hashedPasswordFile != null); - message = "User '${cfg.name}' requires at least one password method (password, hashedPassword, or hashedPasswordFile)."; + (cfg.password != null) || (cfg.hashedPassword != null) || (resolvedPasswordFile != null); + message = "User '${cfg.name}' requires at least one password method (password, hashedPassword, hashedPasswordFile, or a sops 'matt_password' secret)."; } { assertion = @@ -146,19 +156,11 @@ in passwordMethods = lib.count (x: x != null) [ cfg.password cfg.hashedPassword - cfg.hashedPasswordFile + resolvedPasswordFile ]; in passwordMethods <= 1; - message = "User '${cfg.name}' can only use one password method at a time. Found multiple: ${ - lib.concatStringsSep ", " ( - lib.filter (x: x != null) [ - (if cfg.password != null then "password" else null) - (if cfg.hashedPassword != null then "hashedPassword" else null) - (if cfg.hashedPasswordFile != null then "hashedPasswordFile" else null) - ] - ) - }"; + message = "User '${cfg.name}' can only use one password method at a time."; } ]; }; diff --git a/systems/aarch64-linux/macbook-pro-nixos/default.nix b/systems/aarch64-linux/macbook-pro-nixos/default.nix index a32080d..abd69c6 100755 --- a/systems/aarch64-linux/macbook-pro-nixos/default.nix +++ b/systems/aarch64-linux/macbook-pro-nixos/default.nix @@ -23,6 +23,8 @@ ${namespace} = { headless.enable = false; + sops.enable = true; + impermanence = { enable = true; # extraDirectories = [ diff --git a/systems/aarch64-linux/pi5/default.nix b/systems/aarch64-linux/pi5/default.nix index 6c1ff86..f32a83e 100644 --- a/systems/aarch64-linux/pi5/default.nix +++ b/systems/aarch64-linux/pi5/default.nix @@ -17,6 +17,8 @@ ${namespace} = { + sops.enable = true; + # ################################################### # # Impermanence # # # ################################################### diff --git a/systems/x86_64-linux/allyx/default.nix b/systems/x86_64-linux/allyx/default.nix index 5c828ae..f04cbf9 100644 --- a/systems/x86_64-linux/allyx/default.nix +++ b/systems/x86_64-linux/allyx/default.nix @@ -27,6 +27,8 @@ ${namespace} = { headless.enable = false; + sops.enable = true; + bootloader.lanzaboote.enable = true; desktop.gnome.enable = true; diff --git a/systems/x86_64-linux/jallen-nas/apps.nix b/systems/x86_64-linux/jallen-nas/apps.nix index aea135b..d4749db 100755 --- a/systems/x86_64-linux/jallen-nas/apps.nix +++ b/systems/x86_64-linux/jallen-nas/apps.nix @@ -19,10 +19,7 @@ in ai = { enable = true; }; - arrs = { - enable = true; - enableVpn = true; - }; + arrs.enable = true; attic = { enable = true; port = 9012; diff --git a/systems/x86_64-linux/jallen-nas/default.nix b/systems/x86_64-linux/jallen-nas/default.nix index c015414..2a5100b 100755 --- a/systems/x86_64-linux/jallen-nas/default.nix +++ b/systems/x86_64-linux/jallen-nas/default.nix @@ -26,6 +26,7 @@ in powerManagement.cpuFreqGovernor = "powersave"; ${namespace} = { + sops.enable = true; # ################################################### # # Boot # # # ################################################### diff --git a/systems/x86_64-linux/jallen-nas/disabled.nix b/systems/x86_64-linux/jallen-nas/disabled.nix index f9abfbe..88bc3ca 100644 --- a/systems/x86_64-linux/jallen-nas/disabled.nix +++ b/systems/x86_64-linux/jallen-nas/disabled.nix @@ -17,6 +17,7 @@ in consoleLogLevel = 3; }; ${namespace} = { + sops.enable = true; services = { actual = mkForce disabled; ai = mkForce disabled; diff --git a/systems/x86_64-linux/jallen-nas/nas-defaults.nix b/systems/x86_64-linux/jallen-nas/nas-defaults.nix index 6341c76..ffd0021 100644 --- a/systems/x86_64-linux/jallen-nas/nas-defaults.nix +++ b/systems/x86_64-linux/jallen-nas/nas-defaults.nix @@ -21,66 +21,69 @@ let }; in { - # Bespoke services that define their own path options (not via mkModule). - # Set NAS-specific paths here so the module defaults stay generic. - ${namespace}.services.your_spotify.configPath = lib.mkDefault "${appdata}/your_spotify"; - ${namespace}.services.ocis = { - dataPath = lib.mkDefault "${data}/ocis"; - configPath = lib.mkDefault "${appdata}/ocis"; - }; - - imports = map svcDefault [ - "actual" - "ai" - "arrs" - "attic" - "authentik" - "authentikRac" - "booklore" - "caddy" - "calibre" - "calibre-web" - "code-server" - "collabora" - "coturn" - "crowdsec" - "dispatcharr" - "free-games-claimer" - "gitea" - "glance" - "glances" - "grafana" - "guacd" - "headscale" - "immich" - "jellyfin" - "jellyseerr" - "lubelogger" - "manyfold" - "matrix" - "minecraft" - "mongodb" - "nebula" - "nebula-lighthouse" - "netbootxyz" - "nextcloud" - "ntfy" - "onlyoffice" - "opencloud" - "orca-slicer" - "paperless" - "paperless-ai" - "protonmail-bridge" - "restic" - "sparky-fitness" - "sparky-fitness-server" - "sparky-fitness-db" - "sunshine" - "tdarr" - "termix" - "tunarr" - "unmanic" - "uptime-kuma" - "wyoming" - ]; + imports = + # Bespoke services with their own path option names (not configDir/dataDir). + [ + { + ${namespace}.services.ocis = { + dataPath = lib.mkDefault "${data}/ocis"; + configPath = lib.mkDefault "${appdata}/ocis"; + }; + } + ] + ++ map svcDefault [ + "actual" + "ai" + "arrs" + "attic" + "authentik" + "authentikRac" + "booklore" + "caddy" + "calibre" + "calibre-web" + "code-server" + "collabora" + "coturn" + "crowdsec" + "dispatcharr" + "free-games-claimer" + "gitea" + "glance" + "glances" + "grafana" + "guacd" + "headscale" + "immich" + "jellyfin" + "jellyseerr" + "lubelogger" + "manyfold" + "matrix" + "minecraft" + "mongodb" + "nebula" + "nebula-lighthouse" + "netbootxyz" + "nextcloud" + "ntfy" + "onlyoffice" + "opencloud" + "orca-slicer" + "paperless" + "paperless-ai" + "protonmail-bridge" + "restic" + "sparky-fitness" + "sparky-fitness-server" + "sparky-fitness-db" + "sunshine" + "tdarr" + "termix" + "tunarr" + "unmanic" + "uptime-kuma" + "wyoming" + "your-spotify" + ]; } diff --git a/systems/x86_64-linux/matt-nixos/default.nix b/systems/x86_64-linux/matt-nixos/default.nix index 81188b9..2fdd1b9 100644 --- a/systems/x86_64-linux/matt-nixos/default.nix +++ b/systems/x86_64-linux/matt-nixos/default.nix @@ -31,6 +31,8 @@ ${namespace} = { headless.enable = false; + sops.enable = true; + bootloader.lanzaboote.enable = true; desktop = { @@ -100,6 +102,7 @@ "cosmic" = { configuration = { ${namespace} = { + sops.enable = true; desktop = { cosmic.enable = lib.mkForce true; hyprland = { diff --git a/systems/x86_64-linux/matt-nixos/sops.nix b/systems/x86_64-linux/matt-nixos/sops.nix index f1c9699..b070ba4 100755 --- a/systems/x86_64-linux/matt-nixos/sops.nix +++ b/systems/x86_64-linux/matt-nixos/sops.nix @@ -28,6 +28,13 @@ in # Secrets # ------------------------------ secrets = { + "matt_password" = { + neededForUsers = true; + mode = "0600"; + owner = config.users.users."${user}".name; + group = config.users.users."${user}".group; + }; + "desktop/hass_token" = { sopsFile = desktopSopsFile; mode = "0777"; diff --git a/systems/x86_64-linux/nuc-nixos/default.nix b/systems/x86_64-linux/nuc-nixos/default.nix index c8182f1..d2c7e2d 100644 --- a/systems/x86_64-linux/nuc-nixos/default.nix +++ b/systems/x86_64-linux/nuc-nixos/default.nix @@ -5,6 +5,7 @@ }: { ${namespace} = { + sops.enable = true; # ################################################### # # Boot # # # ###################################################