diff options
| author | Collin Williams <96917990+bluedragon1221@users.noreply.github.com> | 2026-01-29 20:15:19 -0600 |
|---|---|---|
| committer | Collin Williams <96917990+bluedragon1221@users.noreply.github.com> | 2026-01-30 08:38:21 -0600 |
| commit | c9a1d2da80bca0a85e8c18f6d2db71c4d1127eda (patch) | |
| tree | 9da79e318ff0533a3708aee85a0b6a6d7f1d1036 | |
| parent | c81952cbcb6c6f1b41c2b6e2a366891991cceaee (diff) | |
Spring Cleaning
- create new module, `system`, that consumes the `boot` module and takes
in the more system-interested services from the `services` module
- touch up left over services (which are more self-hosting interested)
- touch up yo and yoshi configs
41 files changed, 532 insertions, 439 deletions
diff --git a/hosts/ganymede/config.nix b/hosts/ganymede/config.nix index e44e4a8..ba7c854 100644 --- a/hosts/ganymede/config.nix +++ b/hosts/ganymede/config.nix @@ -1,6 +1,6 @@ {config, ...}: { collinux = { - user.name = "collin"; + theme = "terminal"; secrets = { "williams-psk" = { @@ -18,40 +18,41 @@ userName = "Collin Williams"; userEmail = "96917990+bluedragon1221@users.noreply.github.com"; }; + helix.enable = true; }; }; - boot.systemd-boot.enable = true; - - services = { - networking = { + system.network = { + networkd = { enable = true; - networkd = { - enable = true; - ssid = "williams"; - pskFile = config.collinux.secrets."williams-psk".path; - static = { - ip = "192.168.50.2/24"; - gateway = "192.168.50.1"; - }; - }; - sshd = { - enable = true; - bind_host = "0.0.0.0"; + static = { + ip = "192.168.50.2/24"; + gateway = "192.168.50.1"; }; + + ssid = "williams"; + pskFile = config.collinux.secrets."williams-psk".path; }; + }; - selfhost = { - caddy = { - enable = true; - envFile = config.collinux.secrets."caddy-env".path; - }; + services = { + sshd = { + enable = true; + portConfig = [ + { + port = 2222; + rootLogin = true; + } + { + port = 22; + otp = true; + } + ]; + }; - forgejo = { - enable = true; - bind_host = "127.0.0.1"; - root_url = "ganymede.collinux.tailnet:8010"; - }; + caddy = { + enable = true; + envFile = config.collinux.secrets."caddy-env".path; }; }; }; diff --git a/hosts/mercury/config.nix b/hosts/mercury/config.nix index b122e5e..abf38fb 100644 --- a/hosts/mercury/config.nix +++ b/hosts/mercury/config.nix @@ -2,10 +2,7 @@ collinux = { theme = "catppuccin"; - user = { - name = "collin"; - useRun0 = true; - }; + user.useRun0 = true; desktop = { wallpaper = ./wallpapers/abstract-swirls.jpg; @@ -32,16 +29,17 @@ }; }; - services = { - audio.enable = true; - networking = { - enable = true; + system = { + boot = { + systemd-boot.enable = true; + secureBoot.enable = true; + }; + network = { iwd.enable = true; - networkd = { - enable = true; - }; + networkd.enable = true; }; + audio.enable = true; bluetooth.enable = true; }; @@ -62,7 +60,6 @@ tmux.enable = true; lazygit.enable = true; - # nh.enable = true; git = { enable = true; userName = "Collin Williams"; @@ -71,10 +68,5 @@ }; }; }; - - boot = { - systemd-boot.enable = true; - secureBoot.enable = true; - }; }; } diff --git a/hosts/mercury/hjem.nix b/hosts/mercury/hjem.nix index a9d6d08..35f21b8 100644 --- a/hosts/mercury/hjem.nix +++ b/hosts/mercury/hjem.nix @@ -2,7 +2,16 @@ pkgs, inputs, ... -}: { +}: let + captiveBrowserDesktop = pkgs.makeDesktopItem { + name = "captive-browser"; + desktopName = "Captive Browser"; + exec = "${pkgs.captive-browser}/bin/captive-browser"; + icon = "web-browser"; + terminal = false; + categories = ["Application"]; + }; +in { packages = with pkgs; [ tor-browser # don't ask @@ -21,6 +30,7 @@ vital captive-browser # https://words.filippo.io/captive-browser + captiveBrowserDesktop inputs.glide-browser.packages."x86_64-linux".default (pkgs.callPackage ../../pkgs/yoshi.nix {inherit inputs;}) diff --git a/lib/lib.nix b/lib/lib.nix index 56f0dfd..9dd60d4 100644 --- a/lib/lib.nix +++ b/lib/lib.nix @@ -27,6 +27,11 @@ let (builtins.readDir dir))); }; + netTypes = {lib, ...}: { + ipAddr = lib.types.strMatching "^((25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])\\.){3}(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])$"; + ipAddrCidr = lib.types.strMatching "^((25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])\\.){3}(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])/(3[0-2]|[12]?[0-9])$"; + }; + options = { lib, config, @@ -36,7 +41,7 @@ let mkThemeOption = name: mkOption { description = "Pre-made theme for ${name}"; - type = lib.types.enum ["catppuccin" "adwaita" "kanagawa"]; + type = lib.types.enum ["catppuccin" "adwaita" "kanagawa" "terminal"]; default = config.collinux.theme; defaultText = "config.collinux.theme"; }; @@ -51,6 +56,7 @@ let in { inherit globimport; inherit options; + inherit netTypes; flatten = builtins.foldl' (a: b: a ++ b) []; } diff --git a/modules/boot/nixos/plymouth.nix b/modules/boot/nixos/plymouth.nix deleted file mode 100644 index 5f7952b..0000000 --- a/modules/boot/nixos/plymouth.nix +++ /dev/null @@ -1,21 +0,0 @@ -{ - pkgs, - config, - lib, - ... -}: let - cfg = config.collinux.boot.plymouth; -in - lib.mkIf cfg.enable { - boot.plymouth = { - enable = true; - theme = - if (cfg.theme == "catppuccin") - then "catppuccin-macchiato" # for whatever reason catppuccin-mocha has errors - else "nixos-bgrt"; - themePackages = - if (cfg.theme == "catppuccin") - then [pkgs.catppuccin-plymouth] - else [pkgs.nixos-bgrt-plymouth]; - }; - } diff --git a/modules/boot/options.nix b/modules/boot/options.nix deleted file mode 100644 index 9e85570..0000000 --- a/modules/boot/options.nix +++ /dev/null @@ -1,25 +0,0 @@ -{ - my-lib, - config, - lib, - ... -}: let - inherit (lib) mkOption mkEnableOption; - inherit (my-lib.options {inherit lib config;}) mkThemeOption; -in { - options = { - collinux.boot = { - systemd-boot.enable = mkEnableOption "systemd-boot"; - timeout = mkOption { - description = "bootloader timeout"; - type = lib.types.int; - default = 0; - }; - plymouth = { - enable = mkEnableOption "plymouth bootsplash"; - theme = mkThemeOption "plymouth"; - }; - secureBoot.enable = mkEnableOption "lanzaboote"; - }; - }; -} diff --git a/modules/desktop/hjem/wm/dunst.nix b/modules/desktop/hjem/wm/dunst.nix index 9366975..7528dd0 100644 --- a/modules/desktop/hjem/wm/dunst.nix +++ b/modules/desktop/hjem/wm/dunst.nix @@ -18,17 +18,16 @@ origin = "top-right" [urgency_low] - background = "#${base00}99" foreground = "#${base05}ff" + background = "#ffffff00" [urgency_normal] - background = "#${base00}99" foreground = "#${base05}ff" + background = "#ffffff00" [urgency_critical] - background = "#${base00}99" - foreground = "#${base05}ff" - frame_color = "#${base08}" + foreground = "#${base08}ff" + background = "#ffffff00" ''; in lib.mkIf cfg.enable { diff --git a/modules/desktop/hjem/wm/sway.nix b/modules/desktop/hjem/wm/sway.nix index 4cecdea..7051402 100644 --- a/modules/desktop/hjem/wm/sway.nix +++ b/modules/desktop/hjem/wm/sway.nix @@ -38,11 +38,12 @@ settings = '' exec ${config.collinux.desktop.wallpaper_cmd} exec ${pkgs.dunst}/bin/dunst + exec ${pkgs.soteria}/bin/soteria include catppuccin-mocha # target title bg text indicator border - client.focused $lavender $base $text $rosewater $lavender + client.focused $lavender $base $text $rosewater $blue client.focused_inactive $overlay0 $base $text $rosewater $overlay0 client.unfocused $overlay0 $base $text $rosewater $overlay0 client.urgent $peach $base $peach $overlay0 $peach @@ -93,8 +94,11 @@ bindsym Insert exec 'util.lua music next' default_border pixel 2 + default_floating_border pixel 2 smart_borders on smart_gaps on + + floating_modifier Mod4 normal ''; in lib.mkIf cfg.enable { diff --git a/modules/desktop/nixos/greeters/greetd.nix b/modules/desktop/nixos/greeters/greetd.nix index 02af31f..8e0a3ba 100644 --- a/modules/desktop/nixos/greeters/greetd.nix +++ b/modules/desktop/nixos/greeters/greetd.nix @@ -14,13 +14,8 @@ } else if cfg.autologin.enable then { + command = cfg.autologin.command; user = config.collinux.user.name; - command = with config.collinux.desktop; - if (wm.sway.enable && !gnome.enable && !wm.niri.enable) - then lib.getExe pkgs.sway - else if (wm.niri.enable && !gnome.enable && !wm.sway.enable) - then "${pkgs.niri}/bin/niri-session" - else null; } else {}; in diff --git a/modules/desktop/options.nix b/modules/desktop/options.nix index 5ba4423..1bd03fe 100644 --- a/modules/desktop/options.nix +++ b/modules/desktop/options.nix @@ -22,7 +22,18 @@ in { greetd = { enable = mkEnableOption "greetd greeter"; - autologin.enable = mkEnableOption "autologin"; + autologin = { + enable = mkEnableOption "autologin"; + command = mkOption { + type = lib.types.str; + default = with config.collinux.desktop; + if (wm.sway.enable && !gnome.enable && !wm.niri.enable) + then "${pkgs.sway}/bin/sway" + else if (wm.niri.enable && !gnome.enable && !wm.sway.enable) + then "${pkgs.niri}/bin/niri-session" + else null; + }; + }; cosmic-greeter.enable = mkEnableOption "cosmic-greeter"; }; gdm.enable = mkEnableOption "gdm display manager"; diff --git a/modules/options.nix b/modules/options.nix index 8ecf1d7..3e3065d 100644 --- a/modules/options.nix +++ b/modules/options.nix @@ -1,15 +1,14 @@ { lib, config, + my-lib, ... }: let - inherit (lib) mkOption types; + inherit (lib) mkOption; + inherit (my-lib.options {inherit lib config;}) mkThemeOption; in { options = { - collinux.theme = mkOption { - description = "System-wide theme"; - type = types.enum ["catppuccin" "adwaita" "kanagawa"]; - }; + collinux.theme = mkThemeOption "The entire system"; collinux.palette = let colorOption = lib.mkOption { @@ -17,7 +16,7 @@ in { internal = true; }; in - lib.mkOption { + mkOption { internal = true; type = lib.types.submodule { options = { diff --git a/modules/services/nixos/selfhost/adguard.nix b/modules/services/nixos/adguard.nix index 69fb8a4..f59934e 100644 --- a/modules/services/nixos/selfhost/adguard.nix +++ b/modules/services/nixos/adguard.nix @@ -3,9 +3,13 @@ lib, ... }: let - cfg = config.collinux.services.selfhost.adguard; -in - lib.mkIf cfg.enable { + cfg = config.collinux.services.adguard; +in { + imports = [ + (import ./mkCaddyCfg.nix cfg) + ]; + + config = lib.mkIf cfg.enable { services.adguardhome = { enable = true; port = cfg.port; @@ -31,17 +35,6 @@ in DNS=127.0.0.1 DNSStubListener=no ''; - services.tailscale.extraSetFlags = lib.optional config.collinux.services.networking.tailscale.enable "--accept-dns=false"; # would create an infinite loop of dns lookups - - services.caddy = lib.mkIf cfg.caddy.enable { - virtualHosts.${cfg.root_url}.extraConfig = '' - ${ - if cfg.caddy.bind_tailscale - then "bind tailscale/${cfg.service_name}" - else "" - } - reverse_proxy ${cfg.bind_host}:${toString cfg.port} - ''; - }; - } + }; +} diff --git a/modules/services/nixos/caddy.nix b/modules/services/nixos/caddy.nix new file mode 100644 index 0000000..06f040c --- /dev/null +++ b/modules/services/nixos/caddy.nix @@ -0,0 +1,23 @@ +{ + pkgs, + lib, + config, + ... +}: let + cfg = config.collinux.services.caddy; +in + lib.mkIf cfg.enable { + services.caddy = { + # just always install this. No harm in installing an extra plugin + package = pkgs.caddy.withPlugins { + plugins = [ + "github.com/tailscale/caddy-tailscale@v0.0.0-20251204171825-f070d146dd61" + ]; + hash = "sha256-cK7C5ISsTwX0FMf891s/Vr22JvRqYEC8GkLfP1L1Mus="; + }; + enable = true; + environmentFile = cfg.envFile; + }; + networking.firewall.allowedTCPPorts = [80 443]; + environment.systemPackages = with pkgs; [nss]; # required for caddy https stuff + } diff --git a/modules/services/nixos/default.nix b/modules/services/nixos/default.nix index 9c95180..234a712 100644 --- a/modules/services/nixos/default.nix +++ b/modules/services/nixos/default.nix @@ -1,10 +1,11 @@ { imports = [ - ./networking - ./audio.nix - ./bluetooth.nix - ./tailscale.nix - ./selfhost - ./ssh.nix + # ./navidrome.nix + ./headscale.nix + ./forgejo.nix + ./openssh.nix + # ./jellyfin.nix + ./caddy.nix + ./adguard.nix ]; } diff --git a/modules/services/nixos/selfhost/forgejo.nix b/modules/services/nixos/forgejo.nix index 1b02628..5c98633 100644 --- a/modules/services/nixos/selfhost/forgejo.nix +++ b/modules/services/nixos/forgejo.nix @@ -3,9 +3,13 @@ config, ... }: let - cfg = config.collinux.services.selfhost.forgejo; -in - lib.mkIf cfg.enable { + cfg = config.collinux.services.forgejo; +in { + imports = [ + (import ./mkCaddyCfg.nix cfg) + ]; + + config = lib.mkIf cfg.enable { services.forgejo = { enable = true; database.type = "sqlite3"; @@ -18,10 +22,10 @@ in # ssh START_SSH_SERVER = true; # use builtin ssh server BUILTIN_SSH_SERVER_USER = "git"; - SSH_DOMAIN = "ganymede"; - SSH_PORT = 2225; # don't conflict with system ssh + SSH_DOMAIN = cfg.root_url or "ganymede"; + SSH_PORT = cfg.git_ssh_port; # don't conflict with system ssh SSH_LISTEN_HOST = cfg.bind_host; - SSH_LISTEN_PORT = 2225; + SSH_LISTEN_PORT = cfg.git_ssh_port; }; service = { DISABLE_REGISTRATION = false; @@ -40,15 +44,5 @@ in after = lib.mkAfter ["network-online.target"]; wants = lib.mkAfter ["network-online.target"]; }; - - services.caddy = lib.mkIf cfg.caddy.enable { - virtualHosts.${cfg.root_url}.extraConfig = '' - ${ - if cfg.caddy.bind_tailscale - then "bind tailscale/${cfg.service_name}" - else "" - } - reverse_proxy ${cfg.bind_host}:${toString cfg.port} - ''; - }; - } + }; +} diff --git a/modules/services/nixos/selfhost/headscale.nix b/modules/services/nixos/headscale.nix index 2bdcca1..51d3da5 100644 --- a/modules/services/nixos/selfhost/headscale.nix +++ b/modules/services/nixos/headscale.nix @@ -4,7 +4,7 @@ lib, ... }: let - cfg = config.collinux.services.selfhost.headscale; + cfg = config.collinux.services.headscale; acl_file = (pkgs.formats.json {}).generate "acl.json" { ssh = [ @@ -16,8 +16,12 @@ } ]; }; -in - lib.mkIf cfg.enable { +in { + imports = [ + (import ./mkCaddyCfg.nix cfg) + ]; + + config = lib.mkIf cfg.enable { services.headscale = { enable = true; address = cfg.bind_host; @@ -34,7 +38,7 @@ in nameservers.global = ["9.9.9.9" "149.112.112.112" "2620:fe::fe" "2620:fe::9"]; }; - policy.path = "${acl_file}"; + policy.path = acl_file; prefixes = { "v4" = "100.100.0.0/16"; @@ -50,7 +54,7 @@ in }; # make sure headscale can start before tailscale - systemd.services."headscale" = lib.mkIf config.collinux.services.networking.tailscale.enable { + systemd.services."headscale" = lib.mkIf config.collinux.system.networking.tailscale.enable { after = lib.mkForce ["network.target"]; before = lib.mkForce ["headscale.target"]; wants = lib.mkForce ["network.target" "headscale.target"]; @@ -61,15 +65,5 @@ in }; environment.systemPackages = [pkgs.headscale]; - - services.caddy = lib.mkIf cfg.caddy.enable { - virtualHosts.${cfg.root_url}.extraConfig = '' - ${ - if cfg.caddy.bind_tailscale - then "bind tailscale/${cfg.service_name}" - else "" - } - reverse_proxy ${cfg.bind_host}:${toString cfg.port} - ''; - }; - } + }; +} diff --git a/modules/services/nixos/jellyfin.nix b/modules/services/nixos/jellyfin.nix new file mode 100644 index 0000000..65193f2 --- /dev/null +++ b/modules/services/nixos/jellyfin.nix @@ -0,0 +1,10 @@ +{ + config, + lib, + ... +}: let + cfg = config.collinux.services.selfhost.jellyfin; +in + lib.mkIf cfg.enable { + services.jellyfin.enable = true; + } diff --git a/modules/services/nixos/mkCaddyCfg.nix b/modules/services/nixos/mkCaddyCfg.nix new file mode 100644 index 0000000..bb2e06d --- /dev/null +++ b/modules/services/nixos/mkCaddyCfg.nix @@ -0,0 +1,15 @@ +cfg: { + services.caddy = + if cfg.caddy.enable + then { + virtualHosts.${cfg.root_url}.extraConfig = '' + ${ + if cfg.caddy.bind_tailscale + then "bind tailscale/${cfg.service_name}" + else "" + } + reverse_proxy ${cfg.bind_host}:${toString cfg.port} + ''; + } + else {}; +} diff --git a/modules/services/nixos/selfhost/navidrome.nix b/modules/services/nixos/navidrome.nix index 5250b85..5250b85 100644 --- a/modules/services/nixos/selfhost/navidrome.nix +++ b/modules/services/nixos/navidrome.nix diff --git a/modules/services/nixos/openssh.nix b/modules/services/nixos/openssh.nix new file mode 100644 index 0000000..c0c8c30 --- /dev/null +++ b/modules/services/nixos/openssh.nix @@ -0,0 +1,96 @@ +{ + config, + lib, + pkgs, + hosts, + ... +}: let + cfg = config.collinux.services.sshd; + + anyAttr = attr: cfg.portConfig |> builtins.map (x: x.${attr} != null) |> builtins.any (x: x); + anyOTP = cfg.portConfig |> builtins.map (x: x.otp == true) |> builtins.any (x: x); + + authorizedKeys = + hosts + |> builtins.mapAttrs (_: data: data.user_pubkey or null) + |> builtins.attrValues + |> builtins.filter (x: x != null); +in { + config = lib.mkIf cfg.enable { + networking.firewall.allowedTCPPorts = cfg.portConfig |> builtins.map (x: x.port); + + services.openssh = { + enable = true; + allowSFTP = false; + + hostKeys = [ + { + path = "/etc/ssh/ssh_host_ed25519_key"; + type = "ed25519"; + } + ]; + + listenAddresses = + cfg.portConfig + |> builtins.map (x: { + addr = "0.0.0.0"; + port = x.port; + }); + + # Lock down everything by default + settings = { + PermitRootLogin = "no"; + PasswordAuthentication = false; + PubkeyAuthentication = false; + KbdInteractiveAuthentication = false; + AllowAgentForwarding = false; + }; + + extraConfig = + cfg.portConfig + |> builtins.map (x: + lib.concatStringsSep "\n" [ + "Match LocalPort ${toString x.port}" + ( + if x.otp + then '' + ChallengeResponseAuthentication yes + PubkeyAuthentication yes + KbdInteractiveAuthentication yes + AuthenticationMethods publickey,keyboard-interactive:pam + '' + else '' + PubkeyAuthentication yes + AuthenticationMethods publickey + '' + ) + (lib.optionalString x.rootLogin "PermitRootLogin yes") + ]) + |> lib.concatStringsSep "\n\n"; + }; + + security.pam.services = lib.optionalAttrs anyOTP { + login.googleAuthenticator.enable = true; + + sshd.text = '' + account required pam_unix.so + + auth required ${pkgs.google-authenticator}/lib/security/pam_google_authenticator.so nullok no_increment_hotp + auth sufficient pam_permit.so + + session required pam_env.so conffile=/etc/pam/environment readenv=0 + session required pam_unix.so + session required pam_loginuid.so + session optional ${pkgs.systemd}/lib/security/pam_systemd.so + ''; + }; + + users.users.${config.collinux.user.name}.openssh.authorizedKeys.keys = authorizedKeys; + users.users."root".openssh.authorizedKeys.keys = lib.mkIf (anyAttr "rootLogin") authorizedKeys; + + systemd.services."openssh" = { + after = lib.mkAfter ["network-online.target"]; + wants = lib.mkAfter ["network-online.target"]; + }; + }; +} diff --git a/modules/services/nixos/selfhost/caddy.nix b/modules/services/nixos/selfhost/caddy.nix deleted file mode 100644 index f625f62..0000000 --- a/modules/services/nixos/selfhost/caddy.nix +++ /dev/null @@ -1,28 +0,0 @@ -{ - pkgs, - lib, - config, - ... -}: let - cfg = config.collinux.services.selfhost.caddy; -in - lib.mkIf cfg.enable (lib.mkMerge [ - { - services.caddy = { - enable = true; - environmentFile = cfg.envFile; - }; - networking.firewall.allowedTCPPorts = [80 443]; - environment.systemPackages = with pkgs; [nss]; # required for caddy https stuff - } - (lib.mkIf config.collinux.services.networking.tailscale.enable { - services.caddy = { - package = pkgs.caddy.withPlugins { - plugins = [ - "github.com/tailscale/caddy-tailscale@v0.0.0-20251204171825-f070d146dd61" - ]; - hash = "sha256-cK7C5ISsTwX0FMf891s/Vr22JvRqYEC8GkLfP1L1Mus="; - }; - }; - }) - ]) diff --git a/modules/services/nixos/selfhost/default.nix b/modules/services/nixos/selfhost/default.nix deleted file mode 100644 index de1078b..0000000 --- a/modules/services/nixos/selfhost/default.nix +++ /dev/null @@ -1,8 +0,0 @@ -{ - imports = [ - ./adguard.nix - ./forgejo.nix - ./headscale.nix - ./caddy.nix - ]; -} diff --git a/modules/services/nixos/selfhost/jellyfin.nix b/modules/services/nixos/selfhost/jellyfin.nix deleted file mode 100644 index 59ea473..0000000 --- a/modules/services/nixos/selfhost/jellyfin.nix +++ /dev/null @@ -1,20 +0,0 @@ -{ - config, - lib, - ... -}: let - cfg = config.collinux.services.selfhost.jellyfin; -in - lib.mkIf cfg.enable (lib.mkMerge [ - { - services.jellyfin = { - enable = true; - }; - } - # (lib.mkIf (with config.collinux.services; networking.tailscale.enable && selfhost.caddy.enable) { - # services.caddy.virtualHosts."https://jellyfin.tail7cca06.ts.net".extraConfig = '' - # bind tailscale/jellyfin - # reverse_proxy localhost:${config.services.jellyfin.port} - # ''; - # }) - ]) diff --git a/modules/services/nixos/ssh.nix b/modules/services/nixos/ssh.nix deleted file mode 100644 index fa8b2ef..0000000 --- a/modules/services/nixos/ssh.nix +++ /dev/null @@ -1,86 +0,0 @@ -{ - config, - lib, - pkgs, - hosts, - ... -}: let - cfg = config.collinux.services.networking.sshd; -in { - config = lib.mkIf cfg.enable { - networking.firewall.allowedTCPPorts = [2222]; # only on local network - - services.openssh = { - enable = true; - - allowSFTP = false; - - hostKeys = [ - { - path = "/etc/ssh/ssh_host_ed25519_key"; - type = "ed25519"; - } - ]; - - listenAddresses = [ - { - addr = cfg.bind_host; - port = 22; - } - { - addr = cfg.bind_host; - port = 2222; - } - ]; - - settings = { - PermitRootLogin = "no"; - PasswordAuthentication = false; - PubkeyAuthentication = true; - KbdInteractiveAuthentication = true; # for google authenticator totp codes - AuthenticationMethods = "publickey,keyboard-interactive:pam"; - }; - - extraConfig = '' - Match LocalPort 2222 - AuthenticationMethods publickey - PermitRootLogin prohibit-password - ''; - }; - - security.pam.services = { - login.googleAuthenticator.enable = true; - - sshd.text = '' - account required pam_unix.so # unix (order 10900) - - auth required ${pkgs.google-authenticator}/lib/security/pam_google_authenticator.so nullok no_increment_hotp # google_authenticator (order 12500) - auth sufficient pam_permit.so - - session required pam_env.so conffile=/etc/pam/environment readenv=0 # env (order 10100) - session required pam_unix.so # unix (order 10200) - session required pam_loginuid.so # loginuid (order 10300) - session optional ${pkgs.systemd}/lib/security/pam_systemd.so # systemd (order 12000) - ''; - }; - - users.users.${config.collinux.user.name}.openssh.authorizedKeys.keys = - hosts - |> (builtins.mapAttrs (_: data: data.user_pubkey or null)) - |> builtins.attrValues - |> (builtins.filter (x: x != null)); - - users.users."root".openssh.authorizedKeys.keys = - hosts - |> (builtins.mapAttrs (_: data: data.user_pubkey or null)) - |> builtins.attrValues - |> (builtins.filter (x: x != null)); # only possible over home network (:2222) - - systemd.services."openssh" = lib.mkIf config.collinux.services.networking.networkd.enable { - after = lib.mkAfter ["network-online.target"]; - wants = lib.mkAfter ["network-online.target"]; - }; - - services.tailscale.extraSetFlags = lib.optional config.services.tailscale.enable "--ssh=true"; - }; -} diff --git a/modules/services/options.nix b/modules/services/options.nix index 9a1f662..880206f 100644 --- a/modules/services/options.nix +++ b/modules/services/options.nix @@ -1,122 +1,93 @@ { lib, - config, + my-lib, ... }: let inherit (lib) mkOption mkEnableOption; + inherit ((my-lib {inherit lib;}).netTypes) ipAddr; - ip_addr = lib.types.strMatching "^((25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])\\.){3}(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])$"; - ip_addr_cidr = lib.types.strMatching "^((25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])\\.){3}(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])/(3[0-2]|[12]?[0-9])$"; + selfhostOptions = { + service_name, + default_port ? null, + }: { + enable = mkEnableOption "${service_name} selfhosted service"; + + service_name = mkOption { + type = lib.types.str; + internal = true; + }; + + bind_host = mkOption { + description = "The IP address on which ${service_name} will listen for incoming connections. The default, `0.0.0.0`, means 'all interfaces'"; + type = ipAddr; + default = "0.0.0.0"; + }; + port = mkOption { + description = "The port on which ${service_name} will listen for incomming connections"; + type = lib.types.port; + default = default_port; + }; + + root_url = mkOption { + description = "The final url that this service will be hosted on. Required for caddy, otherwise optional"; + type = lib.types.nullOr lib.types.str; + }; + + caddy = { + enable = mkEnableOption "Automatically create caddy configurations for this service"; + bind_tailscale = mkEnableOption "Bind the service to ${service_name}.{tailnet}"; + }; + }; in { options = { collinux.services = { - networking = { - enable = mkEnableOption "wifi"; + sshd = { + enable = mkEnableOption "OpenSSH server"; - iwd.enable = mkEnableOption "lightweight wifi daemon"; - networkmanager.enable = mkEnableOption "heavier wifi daemon"; - - networkd = { - enable = mkEnableOption "use systemd-networkd"; - ssid = mkOption { - description = "SSID for this network"; - type = lib.types.str; - }; - pskFile = mkOption { - description = "Absolute path to a file containing the pre-shared key for this network"; - type = lib.types.str; - example = "/run/secrets.d/wifi-psk"; - }; - - static = lib.mkOption { - description = "Set a static IP address for this device on this network. Set to null to use DHCP"; - type = lib.types.nullOr (lib.types.submodule { - options = { - ip = mkOption { - description = "IP address"; - type = ip_addr_cidr; - }; - gateway = mkOption { - description = "default gateway"; - type = ip_addr; - }; + portConfig = mkOption { + description = "List of ssh bind hosts. see submodule options for details"; + type = lib.types.listOf (lib.types.submodule { + options = { + port = mkOption { + description = "Port to run on"; + type = lib.types.port; }; - }); - default = null; - }; - }; - tailscale.enable = mkEnableOption "tailscale"; - sshd = { - enable = mkEnableOption "OpenSSH server"; - bind_host = mkOption { - description = "The IP address on which OpenSSH will listen for incomming connections. The default, `0.0.0.0`, means 'all interfaces'"; - type = ip_addr; - default = "0.0.0.0"; - }; + otp = mkEnableOption "Whether to require TOTP (Google Authenticator) 2fa codes for this port"; + rootLogin = mkEnableOption "Whether to allow root login for this port"; + }; + }); }; }; - audio.enable = mkEnableOption "pipewire and wireplumber"; - - bluetooth.enable = mkEnableOption "bluetooth"; - - selfhost = let - selfhostOptions = { - service_name, - default_port ? null, - }: { - enable = mkEnableOption "${service_name} selfhosted service"; - - service_name = mkOption { - type = lib.types.str; - internal = true; - }; - - bind_host = mkOption { - description = "The IP address on which ${service_name} will listen for incoming connections. The default, `0.0.0.0`, means 'all interfaces'"; - type = ip_addr; - default = "0.0.0.0"; - }; - port = mkOption { - description = "The port on which ${service_name} will listen for incomming connections"; - type = lib.types.port; - default = default_port; - }; - - root_url = mkOption { - description = "The final url that this service will be hosted on. Required for caddy, otherwise optional"; - type = lib.types.nullOr lib.types.str; - }; - - caddy = { - enable = mkEnableOption "Automatically create caddy configurations for this service"; - bind_tailscale = mkEnableOption "Bind the service to ${service_name}.{tailnet}"; - }; - }; - in { - adguard = selfhostOptions { - service_name = "adguard"; - default_port = 8001; - }; + adguard = selfhostOptions { + service_name = "adguard"; + default_port = 8001; + }; - forgejo = selfhostOptions { + forgejo = + (selfhostOptions { service_name = "forgejo"; default_port = 8010; + }) + // { + git_ssh_port = mkOption { + type = lib.types.port; + default = 2225; + }; }; - headscale = selfhostOptions { - service_name = "headscale"; - default_port = 8080; - }; + headscale = selfhostOptions { + service_name = "headscale"; + default_port = 8080; + }; - caddy = { - enable = mkEnableOption "caddy https server"; - envFile = mkOption { - description = "Absolute path to file that contains environment variables for caddy operations"; - type = lib.types.str; - example = "/run/secrets.d/caddy-env"; - }; + caddy = { + enable = mkEnableOption "caddy https server"; + envFile = mkOption { + description = "Absolute path to file that contains environment variables for caddy operations"; + type = lib.types.str; + example = "/run/secrets.d/caddy-env"; }; }; }; diff --git a/modules/services/nixos/audio.nix b/modules/system/nixos/audio.nix index 9de6787..85232f6 100644 --- a/modules/services/nixos/audio.nix +++ b/modules/system/nixos/audio.nix @@ -4,7 +4,7 @@ lib, ... }: let - cfg = config.collinux.services.audio; + cfg = config.collinux.system.audio; in lib.mkIf cfg.enable { security.rtkit.enable = true; @@ -18,4 +18,6 @@ in boot.blacklistedKernelModules = ["snd_seq_dummy"]; # remove extraneous alsa midi devices environment.systemPackages = with pkgs; [pwvucontrol qpwgraph]; + + users.users.${config.collinux.user.name}.extraGroups = ["audio" "pipewire"]; } diff --git a/modules/services/nixos/bluetooth.nix b/modules/system/nixos/bluetooth.nix index acf628c..1795547 100644 --- a/modules/services/nixos/bluetooth.nix +++ b/modules/system/nixos/bluetooth.nix @@ -3,7 +3,7 @@ config, ... }: let - cfg = config.collinux.services.bluetooth; + cfg = config.collinux.system.bluetooth; in lib.mkIf cfg.enable { hardware.bluetooth = { @@ -11,8 +11,8 @@ in powerOnBoot = true; settings.General = { - FastConnectable = true; ControllerMode = "bredr"; + FastConnectable = true; JustWorksRepairing = "always"; }; }; diff --git a/modules/boot/nixos/default.nix b/modules/system/nixos/boot.nix index 49cca5e..b7f5266 100644 --- a/modules/boot/nixos/default.nix +++ b/modules/system/nixos/boot.nix @@ -4,15 +4,11 @@ lib, ... }: let - cfg = config.collinux.boot; + cfg = config.collinux.system.boot; in { - imports = [ - ./plymouth.nix - ]; - boot = { - bcache.enable = false; # why is this default on? I DON'T CARE ABOUT bcache + bcache.enable = false; # why is this default on? I DON'T CARE ABOUT bcachefs initrd = { verbose = false; systemd.enable = true; @@ -24,7 +20,19 @@ in { configurationLimit = 3; }; efi.canTouchEfiVariables = true; - timeout = cfg.timeout; # hold space to show boot menu + timeout = cfg.timeout; # hold space to show boot menu if timeout == 0 + }; + + plymouth = lib.mkIf cfg.plymouth.enable { + enable = true; + theme = + if (cfg.plymouth.theme == "catppuccin") + then "catppuccin-macchiato" # for whatever reason catppuccin-mocha has errors + else "nixos-bgrt"; + themePackages = + if (cfg.plymouth.theme == "catppuccin") + then [pkgs.catppuccin-plymouth] + else [pkgs.nixos-bgrt-plymouth]; }; # from hardened.nix diff --git a/modules/system/nixos/default.nix b/modules/system/nixos/default.nix new file mode 100644 index 0000000..132d99c --- /dev/null +++ b/modules/system/nixos/default.nix @@ -0,0 +1,9 @@ +{ + imports = [ + ./networking + ./boot.nix + ./audio.nix + ./bluetooth.nix + ./polkit.nix + ]; +} diff --git a/modules/services/nixos/networking/default.nix b/modules/system/nixos/networking/default.nix index a042411..a042411 100644 --- a/modules/services/nixos/networking/default.nix +++ b/modules/system/nixos/networking/default.nix diff --git a/modules/services/nixos/networking/iwd.nix b/modules/system/nixos/networking/iwd.nix index db5cc2e..eea35d8 100644 --- a/modules/services/nixos/networking/iwd.nix +++ b/modules/system/nixos/networking/iwd.nix @@ -3,7 +3,7 @@ config, ... }: let - cfg = config.collinux.services.networking.iwd; + cfg = config.collinux.system.network.iwd; in lib.mkIf cfg.enable { networking = { @@ -11,7 +11,7 @@ in enable = true; settings = { General = { - EnableNetworkConfiguration = !config.collinux.services.networking.networkd.enable; + EnableNetworkConfiguration = !config.collinux.system.network.networkd.enable; AddressRandomization = "once"; AddressRandomizationRange = "full"; }; diff --git a/modules/services/nixos/networking/networkd.nix b/modules/system/nixos/networking/networkd.nix index e84fd2f..37b0908 100644 --- a/modules/services/nixos/networking/networkd.nix +++ b/modules/system/nixos/networking/networkd.nix @@ -3,14 +3,14 @@ config, ... }: let - cfg = config.collinux.services.networking.networkd; + cfg = config.collinux.system.network.networkd; dhcp_enabled = cfg.static == null; in lib.mkIf cfg.enable { networking = { wireless = - if !config.collinux.services.networking.iwd.enable + if !config.collinux.system.network.iwd.enable then { enable = true; networks.${cfg.ssid}.pskRaw = "ext:psk"; diff --git a/modules/services/nixos/networking/networkmanager.nix b/modules/system/nixos/networking/networkmanager.nix index e032bd0..c2d6dd1 100644 --- a/modules/services/nixos/networking/networkmanager.nix +++ b/modules/system/nixos/networking/networkmanager.nix @@ -3,7 +3,7 @@ config, ... }: let - cfg = config.collinux.services.networking.networkmanager; + cfg = config.collinux.system.network.networkmanager; in lib.mkIf cfg.enable { networking = { @@ -15,6 +15,4 @@ in dhcpcd.enable = false; }; - - services.tailscale.extraSetFlags = lib.optional config.collinux.services.networking.tailscale.enable "--accept-dns=true"; } diff --git a/modules/services/nixos/networking/resolved.nix b/modules/system/nixos/networking/resolved.nix index 03333b1..03333b1 100644 --- a/modules/services/nixos/networking/resolved.nix +++ b/modules/system/nixos/networking/resolved.nix diff --git a/modules/services/nixos/tailscale.nix b/modules/system/nixos/networking/tailscale.nix index 50e35d3..552ec8b 100644 --- a/modules/services/nixos/tailscale.nix +++ b/modules/system/nixos/networking/tailscale.nix @@ -4,7 +4,7 @@ lib, ... }: let - cfg = config.collinux.services.networking.tailscale; + cfg = config.collinux.system.network.tailscale; in lib.mkIf cfg.enable { services.tailscale = { @@ -13,15 +13,14 @@ in }; networking.firewall = { - checkReversePath = "loose"; trustedInterfaces = ["tailscale0"]; allowedUDPPorts = [config.services.tailscale.port]; }; - # don't start tailscale until after headscale starts systemd.services."tailscaled" = if config.collinux.services.selfhost.headscale.enable then { + # don't start tailscale until after headscale starts wants = lib.mkForce ["network.target" "headscale.target"]; after = lib.mkForce ["network.target" "headscale.target"]; } diff --git a/modules/system/nixos/polkit.nix b/modules/system/nixos/polkit.nix new file mode 100644 index 0000000..29a06f4 --- /dev/null +++ b/modules/system/nixos/polkit.nix @@ -0,0 +1,75 @@ +{lib, ...}: let + defaultDenyRule = '' + polkit.addRule(function(action, subject) { + // Log denied actions for debugging + polkit.log("DENY: action=" + action.id + " user=" + subject.user); + return polkit.Result.NO; + }); + ''; + + run0Rules = '' + polkit.addRule(function(action, subject) { + if (subject.isInGroup("wheel") && action.id === "org.freedesktop.systemd1.manage-units") { + return polkit.Result.AUTH_ADMIN_KEEP; + } + }); + ''; + + networkRules = '' + polkit.addRule(function(action, subject) { + // Only allow network modifications for wheel group (admins) + if (action.id.startsWith("org.freedesktop.NetworkManager.") && + subject.isInGroup("wheel")) { + return polkit.Result.YES; + } + + // Allow reading network status for all users + if (action.id == "org.freedesktop.NetworkManager.network-control" || + action.id == "org.freedesktop.NetworkManager.settings.modify.system") { + if (subject.isInGroup("wheel")) { + return polkit.Result.YES; + } + return polkit.Result.NO; + } + + return polkit.Result.NOT_HANDLED; + }); + ''; + + powerRules = '' + polkit.addRule(function(action, subject) { + if (action.id.match("org.freedesktop.login1.")) { + return polkit.Result.YES; + } + }); + ''; + + bluetoothRules = '' + polkit.addRule(function(action, subject) { + // Allow users to manage bluetooth devices + if (action.id.startsWith("org.bluez.") && + subject.local && subject.active) { + return polkit.Result.YES; + } + + return polkit.Result.NOT_HANDLED; + }); + ''; +in { + security = { + polkit = { + enable = true; + adminIdentities = ["unix-group:wheel"]; + + extraConfig = lib.concatStringsSep "\n\n" [ + run0Rules + networkRules + powerRules + bluetoothRules + defaultDenyRule + ]; + }; + + soteria.enable = true; + }; +} diff --git a/modules/system/options.nix b/modules/system/options.nix new file mode 100644 index 0000000..72d0392 --- /dev/null +++ b/modules/system/options.nix @@ -0,0 +1,68 @@ +{ + lib, + my-lib, + config, + ... +}: let + inherit (lib) mkOption mkEnableOption; + inherit (my-lib.netTypes {inherit lib;}) ipAddr ipAddrCidr; + inherit (my-lib.options {inherit lib config;}) mkThemeOption; +in { + options.collinux.system = { + boot = { + systemd-boot.enable = mkOption { + description = "Whether to use systemd-boot on this system"; + default = true; + }; + timeout = mkOption { + description = "bootloader timeout"; + type = lib.types.int; + default = 0; + }; + plymouth = { + enable = mkEnableOption "plymouth bootsplash"; + theme = mkThemeOption "plymouth"; + }; + secureBoot.enable = mkEnableOption "lanzaboote"; + }; + + network = { + iwd.enable = mkEnableOption "lightweight wifi daemon"; + networkmanager.enable = mkEnableOption "heavier wifi daemon"; + networkd = { + enable = mkEnableOption "use systemd-networkd"; + ssid = mkOption { + description = "SSID for this network"; + type = lib.types.str; + }; + pskFile = mkOption { + description = "Absolute path to a file containing the pre-shared key for this network in the form `psk:<wifi psk>`"; + type = lib.types.str; + example = "/run/secrets.d/wifi-psk"; + }; + + static = lib.mkOption { + description = "Set a static IP address for this device on this network. Leave unset to use DHCP"; + type = lib.types.nullOr (lib.types.submodule { + options = { + ip = mkOption { + description = "IP address"; + type = ipAddrCidr; + }; + gateway = mkOption { + description = "default gateway"; + type = ipAddr; + }; + }; + }); + default = null; + }; + }; + + tailscale.enable = mkEnableOption "tailscale"; + }; + + audio.enable = mkEnableOption "pipewire and wireplumber"; + bluetooth.enable = mkEnableOption "bluetooth"; + }; +} diff --git a/modules/user/nixos/default.nix b/modules/user/nixos/default.nix index 5a871af..71f6c14 100644 --- a/modules/user/nixos/default.nix +++ b/modules/user/nixos/default.nix @@ -12,7 +12,7 @@ in { users.${cfg.name} = { isNormalUser = true; description = cfg.name; - extraGroups = ["networkmanager" "pipewire" "disks" "input" "video" "dialout" "kvm"] ++ (lib.optional cfg.isAdmin "wheel"); + extraGroups = ["networkmanager" "disks" "input" "video" "dialout" "kvm"] ++ (lib.optional cfg.isAdmin "wheel"); }; }; services.userborn.enable = true; @@ -20,7 +20,12 @@ in { # sudo security = { sudo.enable = false; - sudo-rs.enable = !cfg.useRun0; + sudo-rs = lib.mkIf (!cfg.useRun0) { + enable = true; + extraConfig = '' + Defaults pwfeedback + ''; + }; run0.enableSudoAlias = cfg.useRun0; }; diff --git a/modules/user/options.nix b/modules/user/options.nix index 31f166d..6ea2793 100644 --- a/modules/user/options.nix +++ b/modules/user/options.nix @@ -6,6 +6,7 @@ in { name = mkOption { description = "Name for the sole user of this system"; type = types.str; + default = "collin"; }; isAdmin = mkOption { description = "Whether this user is an admin"; diff --git a/pkgs/yo.nix b/pkgs/yo.nix index b98926a..91f30f7 100644 --- a/pkgs/yo.nix +++ b/pkgs/yo.nix @@ -4,25 +4,29 @@ local flags = {} if arg[2] ~= nil then - for a = 2, #arg do - table.insert(flags, a) + for i = 2, #arg do + table.insert(flags, arg[i]) end end if arg[1] == "deploy" or arg[1] == "dep" or arg[1] == "d" then - cmd = ("${pkgs.deploy-rs}/bin/deploy-rs --skip-checks %s -- --log-format internal-json |& ${pkgs.nix-output-monitor}/bin/nom --json"):format(table.concat(flags, " ")) + cmd = ("nix run github:serokell/deploy-rs -- --skip-checks %s -- --log-format internal-json |& ${pkgs.nix-output-monitor}/bin/nom --json"):format(table.concat(flags, " ")) print("+ "..cmd) os.execute(cmd) elseif arg[1] == "switch" or arg[1] == "sw" or arg[1] == "s" then verb = "switch" - elseif arg[1] == "boot" or arg[1] == "b" then + elseif arg[1] == "boot" or arg[1] == "bo" then verb = "boot" elseif arg[1] == "test" or arg[1] == "t" then verb = "test" + elseif arg[1] == "build" or arg[1] == "bu" then + cmd = ("nixos-rebuild build --flake /home/collin/nixos %s --log-format internal-json |& ${pkgs.nix-output-monitor}/bin/nom --json"):format(table.concat(flags, " ")) + print("+ "..cmd) + os.execute(cmd) end if verb then - cmd = ("run0 sh -c 'nixos-rebuild %s --flake /home/collin/nixos %s --log-format internal-json |& ${pkgs.nix-output-monitor}/bin/nom --json'"):format(verb, table.concat(flags, " ")) + cmd = ("run0 --background= sh -c 'nixos-rebuild %s --flake /home/collin/nixos %s --log-format internal-json |& ${pkgs.nix-output-monitor}/bin/nom --json'"):format(verb, table.concat(flags, " ")) print("+ "..cmd) os.execute(cmd) end diff --git a/pkgs/yoshi.nix b/pkgs/yoshi.nix index 14341a0..3679ecf 100644 --- a/pkgs/yoshi.nix +++ b/pkgs/yoshi.nix @@ -18,14 +18,12 @@ if isHome() then return yoshi.ssh{ HostName = "192.168.50.2", - Port = 2222, - LocalForward = 8010 + Port = 2222 } else return yoshi.ssh{ HostName = "williamsfam.us.com", - LocalForward = 8010, - DynamicFoward = 9090 + DynamicForward = 9090 } end end |
