diff --git a/aspects/ai.nix b/aspects/ai.nix new file mode 100644 index 0000000..f3eb6dd --- /dev/null +++ b/aspects/ai.nix @@ -0,0 +1,19 @@ +{ ... }: +{ + flake.modules.nixos.ai = + { inputs, pkgs, ... }: + { + environment.systemPackages = + (with pkgs; [ ]) + ++ (with inputs.nix-ai-tools.packages.${pkgs.stdenv.hostPlatform.system}; [ + opencode + ]); + + nix.settings = { + extra-substituters = [ "https://cache.numtide.com" ]; + extra-trusted-public-keys = [ + "niks3.numtide.com-1:DTx8wZduET09hRmMtKdQDxNNthLQETkc/yaX7M4qK0g=" + ]; + }; + }; +} diff --git a/aspects/base/bash.nix b/aspects/base/bash.nix new file mode 100644 index 0000000..6ba97ef --- /dev/null +++ b/aspects/base/bash.nix @@ -0,0 +1,16 @@ +{ ... }: +{ + flake.modules.homeManager.bash = + { + config, + lib, + pkgs, + ... + }: + { + programs.bash = { + enable = true; + historyFile = "~/.cache/bash_history"; + }; + }; +} diff --git a/aspects/base/boot.nix b/aspects/base/boot.nix new file mode 100644 index 0000000..ec8593d --- /dev/null +++ b/aspects/base/boot.nix @@ -0,0 +1,23 @@ +{ ... }: +{ + flake.modules.nixos.boot = + { pkgs, ... }: + { + boot = { + loader = { + timeout = 1; + efi.canTouchEfiVariables = true; + systemd-boot = { + enable = true; + editor = false; + consoleMode = "max"; + sortKey = "aa"; + netbootxyz = { + enable = true; + sortKey = "zz"; + }; + }; + }; + }; + }; +} diff --git a/aspects/base/console.nix b/aspects/base/console.nix new file mode 100644 index 0000000..6bb7be4 --- /dev/null +++ b/aspects/base/console.nix @@ -0,0 +1,11 @@ +{ ... }: +{ + flake.modules.nixos.console = + { ... }: + { + console = { + useXkbConfig = true; + earlySetup = true; + }; + }; +} diff --git a/aspects/base/firewall.nix b/aspects/base/firewall.nix new file mode 100644 index 0000000..68ffa6e --- /dev/null +++ b/aspects/base/firewall.nix @@ -0,0 +1,11 @@ +{ ... }: +{ + flake.modules.nixos.firewall = + { ... }: + { + networking = { + firewall.enable = true; + nftables.enable = true; + }; + }; +} diff --git a/aspects/base/fish.nix b/aspects/base/fish.nix new file mode 100644 index 0000000..8ed326a --- /dev/null +++ b/aspects/base/fish.nix @@ -0,0 +1,47 @@ +{ ... }: +{ + flake.modules = { + nixos.fish = + { ... }: + { + programs.fish.enable = true; + }; + homeManager.fish = + { + config, + lib, + pkgs, + ... + }: + { + programs.fish = { + enable = true; + interactiveShellInit = '' + set fish_greeting + ${lib.getExe pkgs.nix-your-shell} fish | source + ''; + loginShellInit = "${lib.getExe pkgs.nix-your-shell} fish | source"; + plugins = [ + { + name = "bang-bang"; + src = pkgs.fetchFromGitHub { + owner = "oh-my-fish"; + repo = "plugin-bang-bang"; + rev = "f969c618301163273d0a03d002614d9a81952c1e"; + sha256 = "sha256-A8ydBX4LORk+nutjHurqNNWFmW6LIiBPQcxS3x4nbeQ="; + }; + } + { + name = "z"; + src = pkgs.fetchFromGitHub { + owner = "jethrokuan"; + repo = "z"; + rev = "067e867debee59aee231e789fc4631f80fa5788e"; + sha256 = "sha256-emmjTsqt8bdI5qpx1bAzhVACkg0MNB/uffaRjjeuFxU="; + }; + } + ]; + }; + }; + }; +} diff --git a/aspects/base/locale.nix b/aspects/base/locale.nix new file mode 100644 index 0000000..4d0c716 --- /dev/null +++ b/aspects/base/locale.nix @@ -0,0 +1,24 @@ +{ ... }: +{ + flake.modules.nixos.locale = + { ... }: + { + time.timeZone = "America/Bahia"; + + i18n = { + defaultLocale = "en_US.UTF-8"; + extraLocaleSettings = { + LC_ADDRESS = "pt_BR.utf8"; + LC_COLLATE = "pt_BR.utf8"; + LC_IDENTIFICATION = "pt_BR.utf8"; + LC_MEASUREMENT = "pt_BR.utf8"; + LC_MONETARY = "pt_BR.utf8"; + LC_NAME = "pt_BR.utf8"; + LC_NUMERIC = "pt_BR.utf8"; + LC_PAPER = "pt_BR.utf8"; + LC_TELEPHONE = "pt_BR.utf8"; + LC_TIME = "en_IE.utf8"; + }; + }; + }; +} diff --git a/aspects/base/nix.nix b/aspects/base/nix.nix new file mode 100644 index 0000000..2442024 --- /dev/null +++ b/aspects/base/nix.nix @@ -0,0 +1,51 @@ +{ ... }: +{ + flake.modules.nixos.nix = + { inputs, pkgs, ... }: + { + imports = [ inputs.nixos-cli.nixosModules.nixos-cli ]; + + nix = { + settings = { + auto-optimise-store = true; + connect-timeout = 10; + log-lines = 25; + min-free = 128000000; + max-free = 1000000000; + trusted-users = [ "@wheel" ]; + }; + extraOptions = "experimental-features = nix-command flakes"; + gc = { + automatic = true; + options = "--delete-older-than 8d"; + }; + }; + + nixpkgs.config = { + allowUnfree = true; + enableParallelBuilding = true; + buildManPages = false; + buildDocs = false; + }; + + services.nixos-cli = { + enable = true; + config = { + use_nvd = true; + ignore_dirty_tree = true; + apply = { + reexec_as_root = true; + use_nom = true; + }; + confirmation.empty = "default-yes"; + }; + }; + + environment.systemPackages = with pkgs; [ + nix-output-monitor + nvd + ]; + + system.stateVersion = "22.11"; + }; +} diff --git a/aspects/base/security.nix b/aspects/base/security.nix new file mode 100644 index 0000000..310e345 --- /dev/null +++ b/aspects/base/security.nix @@ -0,0 +1,13 @@ +{ ... }: +{ + flake.modules.nixos.security = + { ... }: + { + security.sudo = { + wheelNeedsPassword = false; + extraConfig = '' + Defaults lecture = never + ''; + }; + }; +} diff --git a/aspects/base/ssh.nix b/aspects/base/ssh.nix new file mode 100644 index 0000000..6569bf0 --- /dev/null +++ b/aspects/base/ssh.nix @@ -0,0 +1,32 @@ +{ ... }: + +{ + flake.modules.nixos.ssh = + { ... }: + { + services.openssh = { + enable = true; + settings.PermitRootLogin = "no"; + extraConfig = '' + PrintLastLog no + ''; + }; + programs = { + bash.interactiveShellInit = '' + if [ -n "$SSH_CONNECTION" ] && [ -z "$IN_NIX_SHELL" ] && [ -z "$TMUX" ]; then + export TERM=xterm-256color + clear + fastfetch + fi + ''; + fish.interactiveShellInit = '' + set fish_greeting + if set -q SSH_CONNECTION; and not set -q IN_NIX_SHELL; and not set -q TMUX + export TERM=xterm-256color + clear + fastfetch + end + ''; + }; + }; +} diff --git a/aspects/bluetooth.nix b/aspects/bluetooth.nix new file mode 100644 index 0000000..6c7b2d8 --- /dev/null +++ b/aspects/bluetooth.nix @@ -0,0 +1,16 @@ +{ ... }: +{ + flake.modules.nixos.bluetooth = + { + config, + lib, + pkgs, + ... + }: + { + hardware.bluetooth = { + enable = true; + powerOnBoot = false; + }; + }; +} diff --git a/aspects/cli/btop.nix b/aspects/cli/btop.nix new file mode 100644 index 0000000..220a462 --- /dev/null +++ b/aspects/cli/btop.nix @@ -0,0 +1,28 @@ +{ ... }: +{ + flake.modules = { + nixos.btop = + { pkgs, ... }: + { + environment.systemPackages = with pkgs; [ btop ]; + }; + + homeManager.btop = + { + config, + lib, + pkgs, + ... + }: + { + programs.btop = { + enable = true; + settings = { + theme_background = false; + proc_sorting = "cpu direct"; + update_ms = 500; + }; + }; + }; + }; +} diff --git a/aspects/cli/comma.nix b/aspects/cli/comma.nix new file mode 100644 index 0000000..169144f --- /dev/null +++ b/aspects/cli/comma.nix @@ -0,0 +1,16 @@ +{ ... }: +{ + flake.modules.homeManager.comma = + { + config, + lib, + pkgs, + inputs, + ... + }: + { + imports = [ inputs.nix-index-database.homeModules.nix-index ]; + + programs.nix-index-database.comma.enable = true; + }; +} diff --git a/aspects/cli/direnv.nix b/aspects/cli/direnv.nix new file mode 100644 index 0000000..2cfb2ef --- /dev/null +++ b/aspects/cli/direnv.nix @@ -0,0 +1,16 @@ +{ ... }: +{ + flake.modules.homeManager.direnv = + { + config, + lib, + pkgs, + ... + }: + { + programs.direnv = { + enable = true; + nix-direnv.enable = true; + }; + }; +} diff --git a/aspects/cli/helix.nix b/aspects/cli/helix.nix new file mode 100644 index 0000000..a21641a --- /dev/null +++ b/aspects/cli/helix.nix @@ -0,0 +1,67 @@ +{ ... }: +{ + flake.modules = { + nixos.helix = + { pkgs, ... }: + { + environment.systemPackages = with pkgs; [ + helix + ]; + }; + + homeManager.helix = + { + config, + lib, + pkgs, + ... + }: + { + home.sessionVariables = { + EDITOR = "hx"; + }; + + programs.helix = { + enable = true; + settings = { + editor = { + file-picker.hidden = false; + idle-timeout = 0; + line-number = "relative"; + cursor-shape = { + normal = "underline"; + insert = "bar"; + select = "underline"; + }; + soft-wrap.enable = true; + auto-format = true; + indent-guides.render = true; + }; + keys.normal = { + space = { + o = "file_picker_in_current_buffer_directory"; + esc = [ + "collapse_selection" + "keep_primary_selection" + ]; + }; + }; + }; + languages = { + language = [ + { + name = "nix"; + auto-format = true; + formatter.command = "nixfmt"; + } + { + name = "typst"; + auto-format = true; + formatter.command = "typstyle -c 1000 -i"; + } + ]; + }; + }; + }; + }; +} diff --git a/aspects/cli/hm-cli.nix b/aspects/cli/hm-cli.nix new file mode 100644 index 0000000..97d79e4 --- /dev/null +++ b/aspects/cli/hm-cli.nix @@ -0,0 +1,18 @@ +{ ... }: +{ + flake.modules.homeManager.hm-cli = + { + config, + lib, + pkgs, + ... + }: + { + home = { + packages = with pkgs; [ hm-cli ]; + sessionVariables = { + HM_PATH = "/etc/nixos"; + }; + }; + }; +} diff --git a/aspects/cli/starship.nix b/aspects/cli/starship.nix new file mode 100644 index 0000000..3ac5e4f --- /dev/null +++ b/aspects/cli/starship.nix @@ -0,0 +1,48 @@ +{ ... }: +{ + flake.modules.homeManager.starship = + { + config, + lib, + pkgs, + ... + }: + { + programs.starship = { + enable = true; + enableBashIntegration = true; + enableFishIntegration = true; + settings = { + add_newline = false; + format = '' + $hostname$directory$git_branch$git_status$nix_shell + [ ❯ ](bold green) + ''; + right_format = "$cmd_duration$character"; + hostname = { + ssh_symbol = "󰖟 "; + }; + character = { + error_symbol = "[](red)"; + success_symbol = "[󱐋](green)"; + }; + cmd_duration = { + format = "[󰄉 $duration ]($style)"; + style = "yellow"; + min_time = 500; + }; + git_branch = { + symbol = " "; + style = "purple"; + }; + git_status.style = "red"; + nix_shell = { + format = "via [$symbol$state]($style)"; + heuristic = true; + style = "blue"; + symbol = "󱄅 "; + }; + }; + }; + }; +} diff --git a/aspects/cli/tmux.nix b/aspects/cli/tmux.nix new file mode 100644 index 0000000..4937574 --- /dev/null +++ b/aspects/cli/tmux.nix @@ -0,0 +1,29 @@ +{ ... }: +{ + flake.modules = { + nixos.tmux = + { pkgs, ... }: + { + environment.systemPackages = with pkgs; [ + tmux + ]; + }; + + homeManager.tmux = + { + config, + lib, + pkgs, + ... + }: + { + programs.tmux = { + enable = true; + clock24 = true; + terminal = "xterm-256color"; + mouse = true; + keyMode = "vi"; + }; + }; + }; +} diff --git a/aspects/constants.nix b/aspects/constants.nix new file mode 100644 index 0000000..5a82660 --- /dev/null +++ b/aspects/constants.nix @@ -0,0 +1,217 @@ +{ + inputs, + lib, + config, + ... +}: + +let + # Host submodule type + hostType = lib.types.submodule { + options = { + lanIP = lib.mkOption { + type = lib.types.nullOr lib.types.str; + default = null; + description = "LAN IP address for the host"; + }; + tailscaleIP = lib.mkOption { + type = lib.types.nullOr lib.types.str; + default = null; + description = "Tailscale IP address for the host"; + }; + }; + }; + + # Service submodule type + serviceType = lib.types.submodule { + options = { + name = lib.mkOption { + type = lib.types.str; + description = "Service name"; + }; + domain = lib.mkOption { + type = lib.types.str; + description = "Domain name for the service"; + }; + host = lib.mkOption { + type = lib.types.str; + description = "Host where the service runs"; + }; + public = lib.mkOption { + type = lib.types.bool; + default = false; + description = "Whether the service is publicly accessible"; + }; + lanIP = lib.mkOption { + type = lib.types.nullOr lib.types.str; + default = null; + description = "LAN IP address (inherited from host)"; + }; + tailscaleIP = lib.mkOption { + type = lib.types.nullOr lib.types.str; + default = null; + description = "Tailscale IP address (inherited from host)"; + }; + }; + }; + + # Import shared data (also used by terranix) + sharedData = import ../data/services.nix; + + # Enrich services with host IP information + enrichServices = + hosts: services: + map ( + svc: + let + hostInfo = hosts.${svc.host} or { }; + in + svc + // { + lanIP = hostInfo.lanIP or null; + tailscaleIP = hostInfo.tailscaleIP or null; + } + ) services; + +in +{ + options.flake = { + hosts = lib.mkOption { + type = lib.types.attrsOf hostType; + default = { }; + description = "Host definitions with IP addresses"; + }; + + services = lib.mkOption { + type = lib.types.listOf serviceType; + default = [ ]; + description = "Service definitions with enriched host information"; + }; + + lib = lib.mkOption { + type = lib.types.attrsOf lib.types.raw; + default = { }; + description = "Utility functions for flake configuration"; + }; + }; + + config.flake = { + hosts = sharedData.hosts; + + services = enrichServices config.flake.hosts sharedData.services; + + lib = { + # Nginx virtual host utilities + mkNginxVHosts = + { domains }: + let + mkVHostConfig = + domain: vhostConfig: + lib.recursiveUpdate { + useACMEHost = domain; + forceSSL = true; + kTLS = true; + } vhostConfig; + in + lib.mapAttrs mkVHostConfig domains; + + # Split DNS utilities for unbound + # Generates unbound view config from a list of DNS entries + mkSplitDNS = + entries: + let + tailscaleData = map (e: ''"${e.domain}. IN A ${e.tailscaleIP}"'') entries; + lanData = map (e: ''"${e.domain}. IN A ${e.lanIP}"'') entries; + in + [ + { + name = "tailscale"; + view-first = true; + local-zone = ''"baduhai.dev." transparent''; + local-data = tailscaleData; + } + { + name = "lan"; + view-first = true; + local-zone = ''"baduhai.dev." transparent''; + local-data = lanData; + } + ]; + # Generates flake.homeConfigurations + mkHomeConfiguration = + { + user, + hostname, + system ? "x86_64-linux", + stateVersion ? "22.05", + nixpkgs ? inputs.nixpkgs, # override with e.g. inputs.nixpkgs-stable + userModules ? [ ], + overlays ? [ inputs.self.overlays.default ], + homeManagerModules ? with inputs.self.modules.homeManager; [ + base + cli + ], + userDirectory ? "/home/${user}", + }: + inputs.home-manager.lib.homeManagerConfiguration { + pkgs = nixpkgs.legacyPackages.${system}; + + extraSpecialArgs = { + inherit inputs hostname; + }; + + modules = [ + { nixpkgs.overlays = overlays; } + { + home = { + username = user; + homeDirectory = userDirectory; + inherit stateVersion; + }; + } + ((inputs.import-tree.initFilter (p: lib.hasSuffix ".nix" p)) + "/${inputs.self}/aspects/users/_${user}" + ) + ] + ++ homeManagerModules + ++ userModules; + }; + # Generates flake.nixosConfigurations + mkHost = + { + hostname, + system ? "x86_64-linux", + nixpkgs ? inputs.nixpkgs, + overlays ? [ + inputs.agenix.overlays.default + inputs.self.overlays.default + ], + ephemeralRootDev ? null, # pass rootDevice string to enable, e.g. ephemeralephemeralRootDev = "/dev/mapper/cryptroot" + nixosModules ? with inputs.self.modules.nixos; [ + base + cli + user + root + ], + extraModules ? [ ], + }: + nixpkgs.lib.nixosSystem { + inherit system; + specialArgs = { inherit inputs; }; + modules = [ + inputs.agenix.nixosModules.default + { networking.hostName = hostname; } + { nixpkgs.overlays = overlays; } + ((inputs.import-tree.initFilter (p: lib.hasSuffix ".nix" p)) + "${inputs.self}/aspects/hosts/_${hostname}" + ) + ] + ++ (lib.optional (ephemeralRootDev != null) ( + inputs.self.factory.ephemeral { rootDevice = ephemeralRootDev; } + )) + ++ nixosModules + ++ extraModules; + }; + }; + }; +} diff --git a/aspects/desktop/graphics.nix b/aspects/desktop/graphics.nix new file mode 100644 index 0000000..7d1ed6d --- /dev/null +++ b/aspects/desktop/graphics.nix @@ -0,0 +1,25 @@ +{ ... }: + +{ + flake.modules.nixos.graphics = + { pkgs, ... }: + { + environment.systemPackages = with pkgs; [ + gimp + inkscape + plasticity + ]; + + services.flatpak.packages = [ + "com.boxy_svg.BoxySVG" + rec { + appId = "io.github.softfever.OrcaSlicer"; + sha256 = "0hdx5sg6fknj1pfnfxvlfwb5h6y1vjr6fyajbsnjph5gkp97c6p1"; + bundle = "${pkgs.fetchurl { + url = "https://github.com/SoftFever/OrcaSlicer/releases/download/v2.3.0/OrcaSlicer-Linux-flatpak_V2.3.0_x86_64.flatpak"; + inherit sha256; + }}"; + } + ]; + }; +} diff --git a/aspects/desktop/media.nix b/aspects/desktop/media.nix new file mode 100644 index 0000000..7543c0a --- /dev/null +++ b/aspects/desktop/media.nix @@ -0,0 +1,29 @@ +{ ... }: + +{ + flake.modules = { + nixos.media = + { pkgs, ... }: + { + environment.systemPackages = with pkgs; [ + decibels + loupe + obs-studio + showtime + ]; + }; + + homeManager.media = + { pkgs, ... }: + { + programs.obs-studio = { + enable = true; + plugins = with pkgs.obs-studio-plugins; [ + obs-vkcapture + obs-backgroundremoval + obs-pipewire-audio-capture + ]; + }; + }; + }; +} diff --git a/aspects/desktop/niri.nix b/aspects/desktop/niri.nix new file mode 100644 index 0000000..9408097 --- /dev/null +++ b/aspects/desktop/niri.nix @@ -0,0 +1,246 @@ +{ ... }: +{ + flake.modules = { + nixos.niri = + { + config, + lib, + pkgs, + ... + }: + { + services.greetd.settings = { + default_session.command = "${lib.getExe pkgs.tuigreet} --user-menu --time --remember --asterisks --cmd ${config.programs.niri.package}/bin/niri-session"; + }; + + programs.niri.enable = true; + }; + homeManager.niri = + { + config, + lib, + pkgs, + inputs, + hostname ? null, + ... + }: + let + isRotterdam = hostname == "rotterdam"; + in + { + imports = [ inputs.noctalia.homeModules.default ]; + + services.kanshi = { + enable = true; + settings = [ + { + profile.name = "default"; + profile.outputs = [ + { + criteria = "*"; + scale = 1.0; + } + ]; + } + ]; + }; + + home = { + packages = with pkgs; [ + xwayland-satellite + inputs.noctalia.packages.${pkgs.stdenv.hostPlatform.system}.default + ]; + sessionVariables.QT_QPA_PLATFORMTHEME = "gtk3"; + }; + + xdg.configFile."niri/config.kdl".text = '' + input { + keyboard { + xkb { + layout "us" + variant "altgr-intl" + } + } + touchpad { + tap + dwt + drag true + drag-lock + natural-scroll + accel-speed 0.2 + accel-profile "flat" + scroll-method "two-finger" + middle-emulation + } + mouse { + natural-scroll + accel-speed 0.2 + accel-profile "flat" + } + warp-mouse-to-focus mode="center-xy" + focus-follows-mouse + } + + output "LG Electronics LG ULTRAWIDE 206AZFM5E459" { + layout { + preset-column-widths { + proportion 0.33333 + proportion 0.5 + proportion 0.66667 + } + default-column-width { proportion 0.33333; } + } + } + + layout { + gaps 8 + center-focused-column "never" + always-center-single-column + empty-workspace-above-first + preset-column-widths { + proportion 0.5 + proportion 1.0 + } + default-column-width { proportion 0.5; } + focus-ring { + off + } + border { + width 4 + active-color "#ffc87f" + inactive-color "#505050" + urgent-color "#9b0000" + } + tab-indicator { + width 4 + gap 4 + place-within-column + } + } + + overview { + zoom 0.65 + } + + spawn-at-startup "noctalia-shell" "-d" + spawn-at-startup "${lib.getExe pkgs.niri-auto-centre}" + layer-rule { + match namespace="^noctalia-overview*" + place-within-backdrop true + } + + hotkey-overlay { + skip-at-startup + } + + prefer-no-csd + screenshot-path "~/Pictures/Screenshots/Screenshot from %Y-%m-%d %H-%M-%S.png" + + animations { + slowdown 0.3 + } + + window-rule { + match app-id="zen" + default-column-width { proportion ${if isRotterdam then "0.5" else "1.0"}; } + } + + window-rule { + geometry-corner-radius 12 + clip-to-geometry true + } + + config-notification { + disable-failed + } + + binds { + Alt+Space repeat=false { spawn "vicinae" "toggle"; } + XF86AudioRaiseVolume allow-when-locked=true { spawn "noctalia-shell" "ipc" "call" "volume" "increase"; } + XF86AudioLowerVolume allow-when-locked=true { spawn "noctalia-shell" "ipc" "call" "volume" "decrease"; } + XF86AudioMute allow-when-locked=true { spawn "noctalia-shell" "ipc" "call" "volume" "muteOutput"; } + XF86MonBrightnessUp allow-when-locked=true { spawn "noctalia-shell" "ipc" "call" "brightness" "increase"; } + XF86MonBrightnessDown allow-when-locked=true { spawn "noctalia-shell" "ipc" "call" "brightness" "decrease"; } + XF86AudioPlay allow-when-locked=true { spawn "${lib.getExe pkgs.playerctl}" "play-pause"; } + XF86AudioStop allow-when-locked=true { spawn "${lib.getExe pkgs.playerctl}" "stop"; } + XF86AudioPrev allow-when-locked=true { spawn "${lib.getExe pkgs.playerctl}" "previous"; } + XF86AudioNext allow-when-locked=true { spawn "${lib.getExe pkgs.playerctl}" "next"; } + Mod+V repeat=false { spawn "vicinae" "vicinae://extensions/vicinae/clipboard/history"; } + Mod+Shift+L repeat=false { spawn "noctalia-shell" "ipc" "call" "lockScreen" "lock"; } + Mod+Return { spawn "ghostty"; } + Ctrl+Alt+Shift+A allow-when-locked=true { spawn "toggleaudiosink"; } + Mod+W repeat=false { toggle-overview; } + Mod+Q { close-window; } + Alt+Shift+Q { close-window;} + Mod+Shift+Q { close-window; } + Alt+F4 { close-window; } + Mod+Left { focus-column-left; } + Mod+Down { focus-window-or-workspace-down; } + Mod+Up { focus-window-or-workspace-up; } + Mod+Right { focus-column-right; } + Mod+H { focus-column-left; } + Mod+L { focus-column-right; } + Mod+J { focus-window-or-workspace-down; } + Mod+K { focus-window-or-workspace-up; } + Mod+Ctrl+Left { move-column-left; } + Mod+Ctrl+Down { move-window-down-or-to-workspace-down; } + Mod+Ctrl+Up { move-window-up-or-to-workspace-up; } + Mod+Ctrl+Right { move-column-right; } + Mod+Ctrl+H { move-column-left; } + Mod+Ctrl+J { move-window-down-or-to-workspace-down; } + Mod+Ctrl+K { move-window-up-or-to-workspace-up; } + Mod+Ctrl+L { move-column-right; } + Mod+Home { focus-column-first; } + Mod+End { focus-column-last; } + Mod+Ctrl+Home { move-column-to-first; } + Mod+Ctrl+End { move-column-to-last; } + Mod+Alt+Left { focus-monitor-left; } + Mod+Alt+Down { focus-monitor-down; } + Mod+Alt+Up { focus-monitor-up; } + Mod+Alt+Right { focus-monitor-right; } + Mod+Alt+H { focus-monitor-left; } + Mod+Alt+J { focus-monitor-down; } + Mod+Alt+K { focus-monitor-up; } + Mod+Alt+L { focus-monitor-right; } + Mod+Alt+Ctrl+Left { move-column-to-monitor-left; } + Mod+Alt+Ctrl+Down { move-column-to-monitor-down; } + Mod+Alt+Ctrl+Up { move-column-to-monitor-up; } + Mod+Alt+Ctrl+Right { move-column-to-monitor-right; } + Mod+Alt+Ctrl+H { move-column-to-monitor-left; } + Mod+Alt+Ctrl+J { move-column-to-monitor-down; } + Mod+Alt+Ctrl+K { move-column-to-monitor-up; } + Mod+Alt+Ctrl+L { move-column-to-monitor-right; } + Mod+Ctrl+U { move-workspace-down; } + Mod+Ctrl+I { move-workspace-up; } + Mod+WheelScrollDown cooldown-ms=150 { focus-workspace-down; } + Mod+WheelScrollUp cooldown-ms=150 { focus-workspace-up; } + Mod+Ctrl+WheelScrollDown cooldown-ms=150 { move-column-to-workspace-down; } + Mod+Ctrl+WheelScrollUp cooldown-ms=150 { move-column-to-workspace-up; } + Mod+Shift+WheelScrollDown { focus-column-right; } + Mod+Shift+WheelScrollUp { focus-column-left; } + Mod+Ctrl+Shift+WheelScrollDown { move-column-right; } + Mod+Ctrl+Shift+WheelScrollUp { move-column-left; } + Mod+BracketLeft { consume-or-expel-window-left; } + Mod+BracketRight { consume-or-expel-window-right; } + Mod+Comma { consume-window-into-column; } + Mod+Period { expel-window-from-column; } + Mod+R { switch-preset-column-width; } + Mod+F { maximize-column; } + Mod+Ctrl+F { fullscreen-window; } + Mod+C { center-visible-columns; } + Mod+Ctrl+C { center-column; } + Mod+Space { toggle-window-floating; } + Mod+Ctrl+Space { switch-focus-between-floating-and-tiling; } + Mod+T { toggle-column-tabbed-display; } + Print { screenshot-screen; } + Mod+Print { screenshot; } + Ctrl+Print { screenshot-window; } + Mod+Backspace allow-inhibiting=false { toggle-keyboard-shortcuts-inhibit; } + Mod+Alt+E { spawn "noctalia-shell" "ipc" "call" "sessionMenu" "toggle"; } + Ctrl+Alt+Delete { spawn "noctalia-shell" "ipc" "call" "sessionMenu" "toggle"; } + Mod+Ctrl+P { power-off-monitors; } + } + ''; + }; + }; +} diff --git a/aspects/desktop/office.nix b/aspects/desktop/office.nix new file mode 100644 index 0000000..68d958a --- /dev/null +++ b/aspects/desktop/office.nix @@ -0,0 +1,23 @@ +{ ... }: + +{ + flake.modules.nixos.office = + { pkgs, ... }: + { + environment.systemPackages = with pkgs; [ + aspell + aspellDicts.de + aspellDicts.en + aspellDicts.en-computers + aspellDicts.pt_BR + glow + papers + presenterm + rnote + ]; + + services.flatpak.packages = [ + "com.collabora.Office" + ]; + }; +} diff --git a/aspects/desktop/web.nix b/aspects/desktop/web.nix new file mode 100644 index 0000000..9d6494f --- /dev/null +++ b/aspects/desktop/web.nix @@ -0,0 +1,22 @@ +{ ... }: + +{ + flake.modules.nixos.web = + { + inputs, + pkgs, + ... + }: + { + environment.systemPackages = with pkgs; [ + inputs.zen-browser.packages."${pkgs.stdenv.hostPlatform.system}".default + beeper + bitwarden-desktop + fragments + nextcloud-client + tor-browser + ungoogled-chromium + vesktop + ]; + }; +} diff --git a/aspects/dev.nix b/aspects/dev.nix new file mode 100644 index 0000000..afe9edc --- /dev/null +++ b/aspects/dev.nix @@ -0,0 +1,23 @@ +{ ... }: +{ + flake.modules.nixos.dev = + { + config, + lib, + pkgs, + ... + }: + { + environment.systemPackages = with pkgs; [ + android-tools + lazygit + fd + fzf + nixfmt + nix-init + ripgrep + ]; + + users.users.user.extraGroups = [ "adbusers" ]; + }; +} diff --git a/aspects/ephemeral.nix b/aspects/ephemeral.nix new file mode 100644 index 0000000..90c03c6 --- /dev/null +++ b/aspects/ephemeral.nix @@ -0,0 +1,139 @@ +# Ephemeral root aspect - provides automatic btrfs root subvolume rollover +# Exports both a base module with options and a factory function for easy configuration +{ inputs, ... }: +{ + # Base module with options (for external flakes or direct use) + flake.modules.nixos.ephemeral = + { lib, config, ... }: + let + cfg = config.ephemeral; + in + { + options.ephemeral = { + enable = lib.mkEnableOption "ephemeral root with automatic rollback"; + + rootDevice = lib.mkOption { + type = lib.types.str; + example = "/dev/mapper/cryptroot"; + description = "Device path for the root btrfs filesystem"; + }; + + rootSubvolume = lib.mkOption { + type = lib.types.str; + default = "@root"; + description = "Name of the root btrfs subvolume"; + }; + + oldRootRetentionDays = lib.mkOption { + type = lib.types.int; + default = 30; + description = "Number of days to keep old root snapshots before deletion"; + }; + }; + + config = lib.mkIf cfg.enable { + boot.initrd.systemd.services.recreate-root = { + description = "Rolling over and creating new filesystem root"; + requires = [ "initrd-root-device.target" ]; + after = [ + "local-fs-pre.target" + "initrd-root-device.target" + ]; + requiredBy = [ "initrd-root-fs.target" ]; + before = [ "sysroot.mount" ]; + unitConfig = { + AssertPathExists = "/etc/initrd-release"; + DefaultDependencies = false; + }; + serviceConfig = { + Type = "oneshot"; + RemainAfterExit = true; + }; + script = '' + set -euo pipefail + + mkdir /btrfs_tmp + if ! mount ${cfg.rootDevice} /btrfs_tmp; then + echo "ERROR: Failed to mount ${cfg.rootDevice}" + exit 1 + fi + + if [[ -e /btrfs_tmp/${cfg.rootSubvolume} ]]; then + mkdir -p /btrfs_tmp/old_roots + timestamp=$(date --date="@$(stat -c %Y /btrfs_tmp/${cfg.rootSubvolume})" "+%Y-%m-%-d_%H:%M:%S") + mv /btrfs_tmp/${cfg.rootSubvolume} "/btrfs_tmp/old_roots/$timestamp" + fi + + delete_subvolume_recursively() { + IFS=$'\n' + for i in $(btrfs subvolume list -o "$1" | cut -f 9- -d ' '); do + delete_subvolume_recursively "/btrfs_tmp/$i" + done + btrfs subvolume delete "$1" + } + + for i in $(find /btrfs_tmp/old_roots/ -maxdepth 1 -mtime +${toString cfg.oldRootRetentionDays}); do + delete_subvolume_recursively "$i" + done + + if ! btrfs subvolume create /btrfs_tmp/${cfg.rootSubvolume}; then + echo "ERROR: Failed to create subvolume ${cfg.rootSubvolume}" + umount /btrfs_tmp + exit 1 + fi + + umount /btrfs_tmp + ''; + }; + }; + }; + + # Factory function that generates configured modules + flake.factory.ephemeral = + { + rootDevice, + rootSubvolume ? "@root", + retentionDays ? 30, + persistentStoragePath ? "/persistent", + persistentFiles ? [ + "/etc/machine-id" + "/etc/ssh/ssh_host_ed25519_key" + "/etc/ssh/ssh_host_ed25519_key.pub" + "/etc/ssh/ssh_host_rsa_key" + "/etc/ssh/ssh_host_rsa_key.pub" + ], + persistentDirectories ? [ + "/etc/NetworkManager/system-connections" + "/etc/nixos" + "/var/lib/bluetooth" + "/var/lib/flatpak" + "/var/lib/lxd" + "/var/lib/nixos" + "/var/lib/systemd/coredump" + "/var/lib/systemd/timers" + "/var/lib/tailscale" + "/var/log" + ], + }: + { ... }: + { + imports = [ + inputs.impermanence.nixosModules.impermanence + inputs.self.modules.nixos.ephemeral + ]; + + ephemeral = { + enable = true; + inherit rootDevice rootSubvolume; + oldRootRetentionDays = retentionDays; + }; + + fileSystems."/persistent".neededForBoot = true; + + environment.persistence.main = { + inherit persistentStoragePath; + files = persistentFiles; + directories = persistentDirectories; + }; + }; +} diff --git a/aspects/fwupd.nix b/aspects/fwupd.nix new file mode 100644 index 0000000..217f1eb --- /dev/null +++ b/aspects/fwupd.nix @@ -0,0 +1,13 @@ +{ ... }: +{ + flake.modules.nixos.fwupd = + { + config, + lib, + pkgs, + ... + }: + { + services.fwupd.enable = true; + }; +} diff --git a/aspects/gaming/mangohud.nix b/aspects/gaming/mangohud.nix new file mode 100644 index 0000000..14a3df6 --- /dev/null +++ b/aspects/gaming/mangohud.nix @@ -0,0 +1,47 @@ +{ ... }: + +{ + flake.modules = { + nixos.mangohud = + { pkgs, ... }: + { + environment.systemPackages = with pkgs; [ + mangohud + ]; + }; + + homeManager.mangohud = + { config, ... }: + { + programs.mangohud = { + enable = true; + enableSessionWide = true; + settings = { + position = "top-left"; + fps = true; + frametime = false; + frame_timing = false; + gpu_stats = true; + gpu_temp = true; + gpu_power = true; + cpu_stats = true; + cpu_temp = true; + cpu_power = true; + ram = true; + vram = true; + gamemode = false; + vkbasalt = false; + version = false; + engine_version = false; + vulkan_driver = false; + wine = false; + time = false; + fps_sampling_period = 500; + toggle_hud = "Shift_L+F12"; + toggle_logging = "Ctrl_L+F2"; + output_folder = "${config.home.homeDirectory}/.local/share/mangohud"; + }; + }; + }; + }; +} diff --git a/aspects/gaming/steam.nix b/aspects/gaming/steam.nix new file mode 100644 index 0000000..a10d0e4 --- /dev/null +++ b/aspects/gaming/steam.nix @@ -0,0 +1,24 @@ +{ ... }: + +{ + flake.modules.nixos.steam = + { pkgs, ... }: + { + environment.systemPackages = with pkgs; [ + steam-run + ]; + + programs = { + steam = { + enable = true; + extraCompatPackages = [ pkgs.proton-ge-bin ]; + }; + gamemode.enable = true; + }; + + services.flatpak.packages = [ + "com.steamgriddb.SGDBoop" + "io.github.Foldex.AdwSteamGtk" + ]; + }; +} diff --git a/aspects/hosts/_alexandria/hardware-configuration.nix b/aspects/hosts/_alexandria/hardware-configuration.nix new file mode 100644 index 0000000..63ecba5 --- /dev/null +++ b/aspects/hosts/_alexandria/hardware-configuration.nix @@ -0,0 +1,49 @@ +{ + config, + lib, + modulesPath, + ... +}: + +{ + imports = [ (modulesPath + "/installer/scan/not-detected.nix") ]; + + boot = { + initrd = { + availableKernelModules = [ + "xhci_pci" + "ahci" + "usbhid" + "usb_storage" + "sd_mod" + ]; + kernelModules = [ ]; + }; + kernelModules = [ "kvm-intel" ]; + extraModulePackages = [ ]; + }; + + fileSystems = { + "/" = { + device = "/dev/disk/by-uuid/31289617-1d84-4432-a833-680b52e88525"; + fsType = "ext4"; + }; + "/boot" = { + device = "/dev/disk/by-uuid/4130-BE54"; + fsType = "vfat"; + }; + }; + + swapDevices = [ + { + device = "/swapfile"; + size = 8192; + } + ]; + + networking.useDHCP = lib.mkDefault true; + + powerManagement.cpuFreqGovernor = lib.mkDefault "powersave"; + + hardware.cpu.intel.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware; +} diff --git a/aspects/hosts/_alexandria/jellyfin.nix b/aspects/hosts/_alexandria/jellyfin.nix new file mode 100644 index 0000000..0b024bd --- /dev/null +++ b/aspects/hosts/_alexandria/jellyfin.nix @@ -0,0 +1,14 @@ +{ lib, inputs, ... }: +let + mkNginxVHosts = inputs.self.lib.mkNginxVHosts; +in +{ + services.jellyfin = { + enable = true; + openFirewall = true; + }; + + services.nginx.virtualHosts = mkNginxVHosts { + domains."jellyfin.baduhai.dev".locations."/".proxyPass = "http://127.0.0.1:8096/"; + }; +} diff --git a/aspects/hosts/_alexandria/nextcloud.nix b/aspects/hosts/_alexandria/nextcloud.nix new file mode 100644 index 0000000..cb9f2ac --- /dev/null +++ b/aspects/hosts/_alexandria/nextcloud.nix @@ -0,0 +1,95 @@ +{ + config, + inputs, + pkgs, + ... +}: + +let + mkNginxVHosts = inputs.self.lib.mkNginxVHosts; +in + +{ + services = { + nextcloud = { + enable = true; + package = pkgs.nextcloud32; + datadir = "/data/nextcloud"; + hostName = "cloud.baduhai.dev"; + configureRedis = true; + https = true; + secretFile = config.age.secrets."nextcloud-secrets.json".path; + database.createLocally = true; + maxUploadSize = "16G"; + extraApps = { + inherit (config.services.nextcloud.package.packages.apps) + calendar + contacts + notes + tasks + user_oidc + ; + }; + extraAppsEnable = true; + caching = { + apcu = true; + redis = true; + }; + settings = { + trusted_proxies = [ "127.0.0.1" ]; + default_phone_region = "BR"; + maintenance_window_start = "4"; + allow_local_remote_servers = true; + enabledPreviewProviders = [ + "OC\\Preview\\BMP" + "OC\\Preview\\EMF" + "OC\\Preview\\Font" + "OC\\Preview\\GIF" + "OC\\Preview\\HEIC" + "OC\\Preview\\Illustrator" + "OC\\Preview\\JPEG" + "OC\\Preview\\Krita" + "OC\\Preview\\MarkDown" + "OC\\Preview\\Movie" + "OC\\Preview\\MP3" + "OC\\Preview\\MSOffice2003" + "OC\\Preview\\MSOffice2007" + "OC\\Preview\\MSOfficeDoc" + "OC\\Preview\\OpenDocument" + "OC\\Preview\\PDF" + "OC\\Preview\\Photoshop" + "OC\\Preview\\PNG" + "OC\\Preview\\Postscript" + "OC\\Preview\\SVG" + "OC\\Preview\\TIFF" + "OC\\Preview\\TXT" + "OC\\Preview\\XBitmap" + ]; + }; + config = { + dbtype = "pgsql"; + adminpassFile = config.age.secrets.nextcloud-adminpass.path; + }; + phpOptions = { + "opcache.interned_strings_buffer" = "16"; + }; + }; + + nginx.virtualHosts = mkNginxVHosts { + domains."cloud.baduhai.dev" = { }; + }; + }; + + age.secrets = { + "nextcloud-secrets.json" = { + file = "${inputs.self}/secrets/nextcloud-secrets.json.age"; + owner = "nextcloud"; + group = "nextcloud"; + }; + nextcloud-adminpass = { + file = "${inputs.self}/secrets/nextcloud-adminpass.age"; + owner = "nextcloud"; + group = "nextcloud"; + }; + }; +} diff --git a/aspects/hosts/_alexandria/nginx.nix b/aspects/hosts/_alexandria/nginx.nix new file mode 100644 index 0000000..087faf4 --- /dev/null +++ b/aspects/hosts/_alexandria/nginx.nix @@ -0,0 +1,58 @@ +{ + config, + lib, + inputs, + ... +}: + +let + services = inputs.self.services; + + # Get all unique domains from shared services that have LAN IPs (served by this host) + localDomains = lib.unique (map (s: s.domain) (lib.filter (s: s.host == "alexandria") services)); + + # Generate ACME cert configs for all local domains + acmeCerts = lib.genAttrs localDomains (domain: { + group = "nginx"; + }); +in + +{ + security.acme = { + acceptTerms = true; + defaults = { + email = "baduhai@proton.me"; + dnsResolver = "1.1.1.1:53"; + dnsProvider = "cloudflare"; + credentialsFile = config.age.secrets.cloudflare.path; + }; + certs = acmeCerts; + }; + + services.nginx = { + enable = true; + recommendedGzipSettings = true; + recommendedOptimisation = true; + recommendedProxySettings = true; + recommendedTlsSettings = true; + virtualHosts = { + "_" = { + default = true; + locations."/".return = "444"; + }; + }; + }; + + users.users.nginx.extraGroups = [ "acme" ]; + + networking.firewall.allowedTCPPorts = [ + 80 + 443 + ]; + + age.secrets.cloudflare = { + file = "${inputs.self}/secrets/cloudflare.age"; + owner = "nginx"; + group = "nginx"; + }; +} diff --git a/aspects/hosts/_alexandria/unbound.nix b/aspects/hosts/_alexandria/unbound.nix new file mode 100644 index 0000000..8aedc37 --- /dev/null +++ b/aspects/hosts/_alexandria/unbound.nix @@ -0,0 +1,57 @@ +{ inputs, lib, ... }: + +let + services = inputs.self.services; +in + +{ + services.unbound = { + enable = true; + enableRootTrustAnchor = true; + settings = { + server = { + interface = [ + "0.0.0.0" + "::" + ]; + access-control = [ + "127.0.0.0/8 allow" + "192.168.0.0/16 allow" + "::1/128 allow" + ]; + + num-threads = 2; + msg-cache-size = "50m"; + rrset-cache-size = "100m"; + cache-min-ttl = 300; + cache-max-ttl = 86400; + prefetch = true; + prefetch-key = true; + hide-identity = true; + hide-version = true; + so-rcvbuf = "1m"; + so-sndbuf = "1m"; + + # LAN-only DNS records + local-zone = ''"baduhai.dev." transparent''; + local-data = map (e: ''"${e.domain}. IN A ${e.lanIP}"'') (lib.filter (e: e.lanIP != null) services); + }; + + forward-zone = [ + { + name = "."; + forward-addr = [ + "1.1.1.1@853#cloudflare-dns.com" + "1.0.0.1@853#cloudflare-dns.com" + ]; + forward-tls-upstream = true; + } + ]; + }; + }; + + networking.firewall = { + allowedTCPPorts = [ 53 ]; + allowedUDPPorts = [ 53 ]; + }; +} diff --git a/aspects/hosts/_alexandria/vaultwarden.nix b/aspects/hosts/_alexandria/vaultwarden.nix new file mode 100644 index 0000000..8577b2d --- /dev/null +++ b/aspects/hosts/_alexandria/vaultwarden.nix @@ -0,0 +1,25 @@ +{ + config, + lib, + inputs, + ... +}: +let + mkNginxVHosts = inputs.self.lib.mkNginxVHosts; +in +{ + services.vaultwarden = { + enable = true; + config = { + DOMAIN = "https://pass.baduhai.dev"; + SIGNUPS_ALLOWED = false; + ROCKET_ADDRESS = "127.0.0.1"; + ROCKET_PORT = 58222; + }; + }; + + services.nginx.virtualHosts = mkNginxVHosts { + domains."pass.baduhai.dev".locations."/".proxyPass = + "http://${config.services.vaultwarden.config.ROCKET_ADDRESS}:${toString config.services.vaultwarden.config.ROCKET_PORT}/"; + }; +} diff --git a/aspects/hosts/_io/boot.nix b/aspects/hosts/_io/boot.nix new file mode 100644 index 0000000..326f7dc --- /dev/null +++ b/aspects/hosts/_io/boot.nix @@ -0,0 +1,14 @@ +{ + boot = { + # TODO check if future kernel versions fix boot issue with systemd initrd with tpm + initrd.systemd.tpm2.enable = false; + kernelParams = [ + "nosgx" + "i915.fastboot=1" + "mem_sleep_default=deep" + ]; + extraModprobeConfig = '' + options snd-intel-dspcfg dsp_driver=3 + ''; + }; +} diff --git a/aspects/hosts/_io/disko.nix b/aspects/hosts/_io/disko.nix new file mode 100644 index 0000000..4e6c9d5 --- /dev/null +++ b/aspects/hosts/_io/disko.nix @@ -0,0 +1,79 @@ +{ inputs, ... }: + +{ + imports = [ inputs.disko.nixosModules.default ]; + + disko.devices.disk.main = { + type = "disk"; + device = "/dev/disk/by-id/mmc-hDEaP3_0x1041b689"; + content = { + type = "gpt"; + partitions = { + ESP = { + priority = 1; + name = "ESP"; + start = "1MiB"; + end = "1GiB"; + type = "EF00"; + content = { + type = "filesystem"; + format = "vfat"; + mountpoint = "/boot/efi"; + mountOptions = [ + "noatime" + "fmask=0077" + "dmask=0077" + ]; + }; + }; + cryptroot = { + priority = 2; + name = "root"; + size = "100%"; + content = { + type = "luks"; + name = "cryptroot"; + content = { + type = "btrfs"; + extraArgs = [ "-f" ]; + subvolumes = { + "@root" = { + mountpoint = "/"; + mountOptions = [ + "noatime" + "compress=zstd" + "subvol=@root" + ]; + }; + "@home" = { + mountpoint = "/home"; + mountOptions = [ + "noatime" + "compress=zstd" + "subvol=@home" + ]; + }; + "@nix" = { + mountpoint = "/nix"; + mountOptions = [ + "noatime" + "compress=zstd" + "subvol=@nix" + ]; + }; + "@persistent" = { + mountpoint = "/persistent"; + mountOptions = [ + "noatime" + "compress=zstd" + "subvol=@persistent" + ]; + }; + }; + }; + }; + }; + }; + }; + }; +} diff --git a/aspects/hosts/_io/hardware-configuration.nix b/aspects/hosts/_io/hardware-configuration.nix new file mode 100644 index 0000000..8e4dae4 --- /dev/null +++ b/aspects/hosts/_io/hardware-configuration.nix @@ -0,0 +1,37 @@ +{ + config, + lib, + modulesPath, + inputs, + ... +}: + +{ + imports = [ (modulesPath + "/installer/scan/not-detected.nix") ]; + + boot = { + initrd = { + availableKernelModules = [ + "xhci_pci" + "ahci" + "usb_storage" + "sd_mod" + "sdhci_pci" + ]; + }; + kernelModules = [ "kvm-intel" ]; + }; + + zramSwap = { + enable = true; + memoryPercent = 100; + }; + + powerManagement.cpuFreqGovernor = lib.mkDefault "powersave"; + + networking.useDHCP = lib.mkDefault true; + + nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux"; + + hardware.cpu.intel.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware; +} diff --git a/aspects/hosts/_io/programs.nix b/aspects/hosts/_io/programs.nix new file mode 100644 index 0000000..e272d22 --- /dev/null +++ b/aspects/hosts/_io/programs.nix @@ -0,0 +1,27 @@ +{ pkgs, ... }: + +let + cml-ucm-conf = pkgs.alsa-ucm-conf.overrideAttrs { + wttsrc = pkgs.fetchFromGitHub { + owner = "WeirdTreeThing"; + repo = "chromebook-ucm-conf"; + rev = "b6ce2a7"; + hash = "sha256-QRUKHd3RQmg1tnZU8KCW0AmDtfw/daOJ/H3XU5qWTCc="; + }; + postInstall = '' + echo "v0.4.1" > $out/chromebook.patched + cp -R $wttsrc/{common,codecs,platforms} $out/share/alsa/ucm2 + cp -R $wttsrc/{cml,sof-rt5682} $out/share/alsa/ucm2/conf.d + ''; + }; +in + +{ + environment = { + systemPackages = with pkgs; [ + maliit-keyboard + sof-firmware + ]; + sessionVariables.ALSA_CONFIG_UCM2 = "${cml-ucm-conf}/share/alsa/ucm2"; + }; +} diff --git a/aspects/hosts/_io/services.nix b/aspects/hosts/_io/services.nix new file mode 100644 index 0000000..df41a6f --- /dev/null +++ b/aspects/hosts/_io/services.nix @@ -0,0 +1,61 @@ +{ pkgs, ... }: + +{ + services = { + keyd = { + enable = true; + keyboards.main = { + ids = [ "0001:0001" ]; + settings = { + main = { + meta = "overload(meta, esc)"; + f1 = "back"; + f2 = "forward"; + f3 = "refresh"; + f4 = "M-f11"; + f5 = "M-w"; + f6 = "brightnessdown"; + f7 = "brightnessup"; + f8 = "timeout(mute, 200, micmute)"; + f9 = "play"; + f10 = "timeout(nextsong, 200, previoussong)"; + f13 = "delete"; + "102nd" = "layer(function)"; + }; + shift = { + leftshift = "capslock"; + rightshift = "capslock"; + }; + function = { + escape = "f1"; + f1 = "f2"; + f2 = "f3"; + f3 = "f4"; + f4 = "f5"; + f5 = "f6"; + f6 = "f7"; + f7 = "f8"; + f8 = "f9"; + f9 = "f10"; + f10 = "f11"; + f13 = "f12"; + y = "sysrq"; + k = "home"; + l = "pageup"; + "," = "end"; + "." = "pagedown"; + }; + }; + }; + }; + upower.enable = true; + power-profiles-daemon.enable = true; + }; + + # TODO: remove once gmodena/nix-flatpak/issues/45 fixed + systemd.services."flatpak-managed-install" = { + serviceConfig = { + ExecStartPre = "${pkgs.coreutils}/bin/sleep 5"; + }; + }; +} diff --git a/aspects/hosts/_rotterdam/boot.nix b/aspects/hosts/_rotterdam/boot.nix new file mode 100644 index 0000000..d038ede --- /dev/null +++ b/aspects/hosts/_rotterdam/boot.nix @@ -0,0 +1,31 @@ +{ pkgs, ... }: + +let + qubesnsh = pkgs.writeTextFile { + name = "qubes.nsh"; + text = "HD1f65535a1:EFI\\qubes\\grubx64.efi"; + }; +in + +{ + boot = { + kernelParams = [ + "processor.max_cstate=1" # Fixes bug where ryzen cpus freeze when in highest C state + "clearcpuid=514" + "amdgpu.ppfeaturemask=0xfffd3fff" # Fixes amdgpu freezing + ]; + # QubesOS boot entry + loader.systemd-boot = { + extraFiles = { + "efi/edk2-shell/shell.efi" = "${pkgs.edk2-uefi-shell}/shell.efi"; + "qubes.nsh" = qubesnsh; + }; + extraEntries."qubes.conf" = '' + title Qubes OS + efi /efi/edk2-shell/shell.efi + options -nointerrupt qubes.nsh + sort-key ab + ''; + }; + }; +} diff --git a/aspects/hosts/_rotterdam/hardware-configuration.nix b/aspects/hosts/_rotterdam/hardware-configuration.nix new file mode 100644 index 0000000..169c53f --- /dev/null +++ b/aspects/hosts/_rotterdam/hardware-configuration.nix @@ -0,0 +1,82 @@ +{ + config, + lib, + modulesPath, + ... +}: + +{ + imports = [ (modulesPath + "/installer/scan/not-detected.nix") ]; + + boot = { + initrd = { + availableKernelModules = [ + "amdgpu" + "nvme" + "xhci_pci" + "ahci" + "usbhid" + "sd_mod" + ]; + luks.devices."cryptroot" = { + device = "/dev/disk/by-uuid/f7dd4142-7109-4493-834d-4a831777f08d"; + keyFile = "/dev/disk/by-partuuid/add5fc14-e20f-48be-8b2a-0799ef04d3cb"; + }; + }; + kernelModules = [ "kvm-amd" ]; + }; + + fileSystems = { + "/" = { + device = "/dev/disk/by-uuid/3287dbc3-c0fa-4096-a0b3-59b017cfecc8"; + fsType = "btrfs"; + options = [ + "subvol=@root" + "noatime" + "compress=zstd" + ]; + }; + "/home" = { + device = "/dev/disk/by-uuid/3287dbc3-c0fa-4096-a0b3-59b017cfecc8"; + fsType = "btrfs"; + options = [ + "subvol=@home" + "noatime" + "compress=zstd" + ]; + }; + "/boot/efi" = { + device = "/dev/disk/by-uuid/F2A2-CF5A"; + fsType = "vfat"; + options = [ + "noatime" + "fmask=0077" + "dmask=0077" + ]; + }; + "/nix" = { + device = "/dev/disk/by-uuid/3287dbc3-c0fa-4096-a0b3-59b017cfecc8"; + fsType = "btrfs"; + options = [ + "subvol=@nix" + "noatime" + "compress=zstd" + ]; + }; + "/persistent" = { + device = "/dev/disk/by-uuid/3287dbc3-c0fa-4096-a0b3-59b017cfecc8"; + fsType = "btrfs"; + options = [ + "subvol=@persistent" + "noatime" + "compress=zstd" + ]; + }; + }; + + networking.useDHCP = lib.mkDefault true; + + nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux"; + + hardware.cpu.amd.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware; +} diff --git a/aspects/hosts/_rotterdam/hardware.nix b/aspects/hosts/_rotterdam/hardware.nix new file mode 100644 index 0000000..6f76e99 --- /dev/null +++ b/aspects/hosts/_rotterdam/hardware.nix @@ -0,0 +1,8 @@ +{ pkgs, ... }: + +{ + hardware = { + amdgpu.opencl.enable = true; + graphics.extraPackages = with pkgs; [ rocmPackages.clr.icd ]; + }; +} diff --git a/aspects/hosts/_rotterdam/programs.nix b/aspects/hosts/_rotterdam/programs.nix new file mode 100644 index 0000000..b4dcfd9 --- /dev/null +++ b/aspects/hosts/_rotterdam/programs.nix @@ -0,0 +1,31 @@ +{ pkgs, ... }: + +let + reboot-into-qubes = pkgs.makeDesktopItem { + name = "reboot-into-qubes"; + icon = pkgs.fetchurl { + url = "https://raw.githubusercontent.com/vinceliuice/Qogir-icon-theme/31f267e1f5fd4e9596bfd78dfb41a03d3a9f33ee/src/scalable/apps/distributor-logo-qubes.svg"; + sha256 = "sha256-QbHr7s5Wcs7uFtfqZctMyS0iDbMfiiZOKy2nHhDOfn0="; + }; + desktopName = "Qubes OS"; + genericName = "Reboot into Qubes OS"; + categories = [ "System" ]; + startupNotify = true; + exec = pkgs.writeShellScript "reboot-into-qubes" '' + ${pkgs.yad}/bin/yad --form \ + --title="Qubes OS" \ + --image distributor-logo-qubes \ + --text "Are you sure you want to reboot into Qubes OS?" \ + --button="Yes:0" --button="Cancel:1" + if [ $? -eq 0 ]; then + systemctl reboot --boot-loader-entry=qubes.conf + fi + ''; + }; +in + +{ + environment.systemPackages = [ reboot-into-qubes ]; + + programs.steam.dedicatedServer.openFirewall = true; +} diff --git a/aspects/hosts/_rotterdam/services.nix b/aspects/hosts/_rotterdam/services.nix new file mode 100644 index 0000000..0bf276f --- /dev/null +++ b/aspects/hosts/_rotterdam/services.nix @@ -0,0 +1,11 @@ +{ + services.keyd = { + enable = true; + keyboards.main = { + ids = [ "5653:0001" ]; + settings.main = { + esc = "overload(meta, esc)"; + }; + }; + }; +} diff --git a/aspects/hosts/_trantor/boot.nix b/aspects/hosts/_trantor/boot.nix new file mode 100644 index 0000000..0498818 --- /dev/null +++ b/aspects/hosts/_trantor/boot.nix @@ -0,0 +1,6 @@ +{ + boot = { + initrd.systemd.enable = true; + loader.efi.efiSysMountPoint = "/boot/efi"; + }; +} diff --git a/aspects/hosts/_trantor/disko.nix b/aspects/hosts/_trantor/disko.nix new file mode 100644 index 0000000..0e47058 --- /dev/null +++ b/aspects/hosts/_trantor/disko.nix @@ -0,0 +1,64 @@ +{ inputs, ... }: + +{ + imports = [ inputs.disko.nixosModules.default ]; + + disko.devices.disk.main = { + type = "disk"; + device = "/dev/disk/by-id/scsi-360b207ed25d84372a95d1ecf842f8e20"; + content = { + type = "gpt"; + partitions = { + ESP = { + priority = 1; + name = "ESP"; + start = "1MiB"; + end = "512MiB"; + type = "EF00"; + content = { + type = "filesystem"; + format = "vfat"; + mountpoint = "/boot/efi"; + mountOptions = [ + "noatime" + "fmask=0077" + "dmask=0077" + ]; + }; + }; + root = { + priority = 2; + name = "root"; + size = "100%"; + content = { + type = "btrfs"; + extraArgs = [ "-f" ]; + subvolumes = { + "@root" = { + mountpoint = "/"; + mountOptions = [ + "noatime" + "compress=zstd" + ]; + }; + "@nix" = { + mountpoint = "/nix"; + mountOptions = [ + "noatime" + "compress=zstd" + ]; + }; + "@persistent" = { + mountpoint = "/persistent"; + mountOptions = [ + "noatime" + "compress=zstd" + ]; + }; + }; + }; + }; + }; + }; + }; +} diff --git a/aspects/hosts/_trantor/fail2ban.nix b/aspects/hosts/_trantor/fail2ban.nix new file mode 100644 index 0000000..bc05139 --- /dev/null +++ b/aspects/hosts/_trantor/fail2ban.nix @@ -0,0 +1,23 @@ +{ config, pkgs, ... }: + +{ + services.fail2ban = { + enable = true; + maxretry = 5; + ignoreIP = [ + "127.0.0.0/8" + "::1" + "10.0.0.0/8" + "172.16.0.0/12" + "192.168.0.0/16" + "100.64.0.0/10" + ]; + bantime = "1h"; + bantime-increment = { + enable = true; + multipliers = "1 2 4 8 16 32 64"; + maxtime = "10000h"; + overalljails = true; + }; + }; +} diff --git a/aspects/hosts/_trantor/forgejo.nix b/aspects/hosts/_trantor/forgejo.nix new file mode 100644 index 0000000..6d702e2 --- /dev/null +++ b/aspects/hosts/_trantor/forgejo.nix @@ -0,0 +1,76 @@ +{ + config, + lib, + inputs, + ... +}: + +let + mkNginxVHosts = inputs.self.lib.mkNginxVHosts; +in + +{ + services = { + forgejo = { + enable = true; + settings = { + session.COOKIE_SECURE = true; + server = { + PROTOCOL = "http+unix"; + DOMAIN = "git.baduhai.dev"; + ROOT_URL = "https://git.baduhai.dev"; + OFFLINE_MODE = true; # disable use of CDNs + SSH_DOMAIN = "git.baduhai.dev"; + SSH_USER = "forgejo"; + SSH_PORT = lib.head config.services.openssh.ports; + }; + log.LEVEL = "Warn"; + mailer.ENABLED = false; + actions.ENABLED = false; + service.DISABLE_REGISTRATION = true; + oauth2_client = { + ENABLE_AUTO_REGISTRATION = true; + UPDATE_AVATAR = true; + ACCOUNT_LINKING = "login"; + USERNAME = "preferred_username"; + }; + }; + }; + nginx.virtualHosts = mkNginxVHosts { + domains."git.baduhai.dev".locations."/".proxyPass = + "http://unix:${config.services.forgejo.settings.server.HTTP_ADDR}:/"; + }; + fail2ban.jails.forgejo = { + settings = { + enabled = true; + filter = "forgejo"; + maxretry = 3; + findtime = "10m"; + bantime = "1h"; + }; + }; + }; + + environment = { + etc."fail2ban/filter.d/forgejo.conf".text = '' + [Definition] + failregex = .*(Failed authentication attempt|invalid credentials|Attempted access of unknown user).* from + ignoreregex = + journalmatch = _SYSTEMD_UNIT=forgejo.service + ''; + + persistence.main.directories = [ + { + directory = config.services.forgejo.stateDir; + inherit (config.services.forgejo) user group; + mode = "0700"; + } + ]; + }; + + # Disable PrivateMounts to allow LoadCredential to work with bind-mounted directories + systemd.services.forgejo.serviceConfig = { + PrivateMounts = lib.mkForce false; + ProtectSystem = lib.mkForce false; + }; +} diff --git a/aspects/hosts/_trantor/hardware-configuration.nix b/aspects/hosts/_trantor/hardware-configuration.nix new file mode 100644 index 0000000..039129e --- /dev/null +++ b/aspects/hosts/_trantor/hardware-configuration.nix @@ -0,0 +1,20 @@ +{ + lib, + modulesPath, + ... +}: + +{ + imports = [ (modulesPath + "/profiles/qemu-guest.nix") ]; + + boot.initrd.availableKernelModules = [ + "xhci_pci" + "virtio_pci" + "virtio_scsi" + "usbhid" + ]; + + networking.useDHCP = lib.mkDefault true; + + nixpkgs.hostPlatform = lib.mkDefault "aarch64-linux"; +} diff --git a/aspects/hosts/_trantor/networking.nix b/aspects/hosts/_trantor/networking.nix new file mode 100644 index 0000000..4dcbe1e --- /dev/null +++ b/aspects/hosts/_trantor/networking.nix @@ -0,0 +1,8 @@ +{ + networking = { + firewall = { + allowedTCPPorts = [ 25566 ]; + allowedUDPPorts = [ 25566 ]; + }; + }; +} diff --git a/aspects/hosts/_trantor/nginx.nix b/aspects/hosts/_trantor/nginx.nix new file mode 100644 index 0000000..24f96c3 --- /dev/null +++ b/aspects/hosts/_trantor/nginx.nix @@ -0,0 +1,56 @@ +{ + config, + lib, + inputs, + ... +}: + +let + services = inputs.self.services; + + localDomains = lib.unique (map (s: s.domain) (lib.filter (s: s.host == "trantor") services)); + + acmeCerts = lib.genAttrs localDomains (domain: { + group = "nginx"; + }); +in + +{ + security.acme = { + acceptTerms = true; + defaults = { + email = "baduhai@proton.me"; + dnsResolver = "1.1.1.1:53"; + dnsProvider = "cloudflare"; + credentialsFile = config.age.secrets.cloudflare.path; + }; + certs = acmeCerts; + }; + + services.nginx = { + enable = true; + recommendedGzipSettings = true; + recommendedOptimisation = true; + recommendedProxySettings = true; + recommendedTlsSettings = true; + virtualHosts = { + "_" = { + default = true; + locations."/".return = "444"; + }; + }; + }; + + users.users.nginx.extraGroups = [ "acme" ]; + + networking.firewall.allowedTCPPorts = [ + 80 + 443 + ]; + + age.secrets.cloudflare = { + file = "${inputs.self}/secrets/cloudflare.age"; + owner = "nginx"; + group = "nginx"; + }; +} diff --git a/aspects/hosts/_trantor/openssh.nix b/aspects/hosts/_trantor/openssh.nix new file mode 100644 index 0000000..704b3df --- /dev/null +++ b/aspects/hosts/_trantor/openssh.nix @@ -0,0 +1,23 @@ +{ ... }: + +{ + services = { + openssh = { + settings = { + PasswordAuthentication = false; + KbdInteractiveAuthentication = false; + }; + }; + fail2ban.jails.sshd = { + settings = { + enabled = true; + port = "ssh"; + filter = "sshd"; + logpath = "/var/log/auth.log"; + maxretry = 3; + findtime = "10m"; + bantime = "1h"; + }; + }; + }; +} diff --git a/aspects/hosts/_trantor/unbound.nix b/aspects/hosts/_trantor/unbound.nix new file mode 100644 index 0000000..9f84228 --- /dev/null +++ b/aspects/hosts/_trantor/unbound.nix @@ -0,0 +1,58 @@ +{ inputs, lib, ... }: + +let + services = inputs.self.services; +in + +{ + services.unbound = { + enable = true; + enableRootTrustAnchor = true; + settings = { + server = { + interface = [ + "0.0.0.0" + "::" + ]; + access-control = [ + "127.0.0.0/8 allow" + "100.64.0.0/10 allow" # Tailscale CGNAT range + "::1/128 allow" + "fd7a:115c:a1e0::/48 allow" # Tailscale IPv6 + ]; + + num-threads = 2; + msg-cache-size = "50m"; + rrset-cache-size = "100m"; + cache-min-ttl = 300; + cache-max-ttl = 86400; + prefetch = true; + prefetch-key = true; + hide-identity = true; + hide-version = true; + so-rcvbuf = "1m"; + so-sndbuf = "1m"; + + # Tailnet DNS records from shared services + local-zone = ''"baduhai.dev." transparent''; + local-data = map (e: ''"${e.domain}. IN A ${e.tailscaleIP}"'') services; + }; + + forward-zone = [ + { + name = "."; + forward-addr = [ + "1.1.1.1@853#cloudflare-dns.com" + "1.0.0.1@853#cloudflare-dns.com" + ]; + forward-tls-upstream = true; + } + ]; + }; + }; + + networking.firewall = { + allowedTCPPorts = [ 53 ]; + allowedUDPPorts = [ 53 ]; + }; +} diff --git a/aspects/hosts/alexandria.nix b/aspects/hosts/alexandria.nix new file mode 100644 index 0000000..be5027e --- /dev/null +++ b/aspects/hosts/alexandria.nix @@ -0,0 +1,19 @@ +{ inputs, ... }: + +let + mkHost = inputs.self.lib.mkHost; +in + +{ + flake.nixosConfigurations.alexandria = mkHost { + hostname = "alexandria"; + nixpkgs = inputs.nixpkgs-stable; + extraModules = with inputs.self.modules.nixos; [ + # base aspects + server + # other aspects + fwupd + libvirtd + ]; + }; +} diff --git a/aspects/hosts/io.nix b/aspects/hosts/io.nix new file mode 100644 index 0000000..cf5ecec --- /dev/null +++ b/aspects/hosts/io.nix @@ -0,0 +1,24 @@ +{ inputs, ... }: + +let + mkHost = inputs.self.lib.mkHost; +in + +{ + flake.nixosConfigurations.io = mkHost { + hostname = "io"; + ephemeralRootDev = "/dev/mapper/cryptroot"; + extraModules = with inputs.self.modules.nixos; [ + # base aspects + desktop + # other aspects + ai + bluetooth + dev + libvirtd + networkmanager + niri + podman + ]; + }; +} diff --git a/aspects/hosts/rotterdam.nix b/aspects/hosts/rotterdam.nix new file mode 100644 index 0000000..f3b6fca --- /dev/null +++ b/aspects/hosts/rotterdam.nix @@ -0,0 +1,26 @@ +{ inputs, ... }: + +let + mkHost = inputs.self.lib.mkHost; +in + +{ + flake.nixosConfigurations.rotterdam = mkHost { + hostname = "rotterdam"; + ephemeralRootDev = "/dev/mapper/cryptroot"; + extraModules = with inputs.self.modules.nixos; [ + # base aspects + desktop + gaming + # other aspects + ai + bluetooth + dev + fwupd + libvirtd + networkmanager + niri + podman + ]; + }; +} diff --git a/aspects/hosts/trantor.nix b/aspects/hosts/trantor.nix new file mode 100644 index 0000000..14f9dd7 --- /dev/null +++ b/aspects/hosts/trantor.nix @@ -0,0 +1,18 @@ +{ inputs, ... }: + +let + mkHost = inputs.self.lib.mkHost; +in + +{ + flake.nixosConfigurations.trantor = mkHost { + hostname = "trantor"; + system = "aarch64-linux"; + nixpkgs = inputs.nixpkgs-stable; + ephemeralRootDev = "/dev/disk/by-id/scsi-360b207ed25d84372a95d1ecf842f8e20-part2"; + extraModules = with inputs.self.modules.nixos; [ + # base aspects + server + ]; + }; +} diff --git a/aspects/libvirtd.nix b/aspects/libvirtd.nix new file mode 100644 index 0000000..360743d --- /dev/null +++ b/aspects/libvirtd.nix @@ -0,0 +1,27 @@ +{ ... }: +{ + flake.modules.nixos.libvirtd = + { + config, + lib, + pkgs, + ... + }: + { + virtualisation = { + libvirtd.enable = true; + spiceUSBRedirection.enable = true; + }; + + programs.virt-manager.enable = true; + + environment.systemPackages = with pkgs; [ lima ]; + + networking.firewall.trustedInterfaces = [ "virbr0" ]; + + users.users.user.extraGroups = [ + "libvirt" + "libvirtd" + ]; + }; +} diff --git a/aspects/lxc.nix b/aspects/lxc.nix new file mode 100644 index 0000000..4225e0c --- /dev/null +++ b/aspects/lxc.nix @@ -0,0 +1,22 @@ +{ ... }: + +{ + flake.modules.nixos.lxc = + { + config, + lib, + pkgs, + ... + }: + { + virtualisation = { + lxc = { + enable = true; + unprivilegedContainers = true; + }; + incus.enable = true; + }; + + users.users.user.extraGroups = [ "incus-admin" ]; + }; +} diff --git a/aspects/networkmanager.nix b/aspects/networkmanager.nix new file mode 100644 index 0000000..8bcb1f2 --- /dev/null +++ b/aspects/networkmanager.nix @@ -0,0 +1,18 @@ +{ ... }: +{ + flake.modules.nixos.networkmanager = + { + config, + lib, + pkgs, + ... + }: + { + networking.networkmanager = { + enable = true; + wifi.backend = "iwd"; + }; + + users.users.user.extraGroups = [ "networkmanager" ]; + }; +} diff --git a/aspects/podman.nix b/aspects/podman.nix new file mode 100644 index 0000000..6afa327 --- /dev/null +++ b/aspects/podman.nix @@ -0,0 +1,24 @@ +{ ... }: +{ + flake.modules.nixos.podman = + { + config, + lib, + pkgs, + ... + }: + { + virtualisation.podman = { + enable = true; + autoPrune.enable = true; + extraPackages = [ pkgs.podman-compose ]; + }; + + security.unprivilegedUsernsClone = true; # Needed for rootless podman + + systemd = { + services.podman-auto-update.enable = true; + timers.podman-auto-update.enable = true; + }; + }; +} diff --git a/aspects/stylix.nix b/aspects/stylix.nix new file mode 100644 index 0000000..f7eb9fa --- /dev/null +++ b/aspects/stylix.nix @@ -0,0 +1,69 @@ +{ ... }: + +{ + flake.modules = { + nixos.stylix = + { inputs, ... }: + { + imports = [ inputs.stylix.nixosModules.stylix ]; + }; + + homeManager.stylix = + { + config, + inputs, + pkgs, + ... + }: + { + imports = [ inputs.stylix.homeModules.stylix ]; + + stylix = { + enable = true; + polarity = "dark"; + base16Scheme = "${pkgs.base16-schemes}/share/themes/tokyodark.yaml"; + cursor = { + package = pkgs.kdePackages.breeze; + name = "breeze_cursors"; + size = 24; + }; + icons = { + enable = true; + package = pkgs.morewaita-icon-theme; + light = "MoreWaita"; + dark = "MoreWaita"; + }; + opacity = { + applications = 1.0; + desktop = 1.0; + popups = config.stylix.opacity.desktop; + terminal = 1.0; + }; + fonts = { + serif = { + package = pkgs.source-serif; + name = "Source Serif 4 Display"; + }; + sansSerif = { + package = pkgs.inter; + name = "Inter"; + }; + monospace = { + package = pkgs.nerd-fonts.fira-code; + name = "FiraCode Nerd Font"; + }; + emoji = { + package = pkgs.noto-fonts-color-emoji; + name = "Noto Color Emoji"; + }; + sizes = { + applications = 10; + desktop = config.stylix.fonts.sizes.applications; + popups = config.stylix.fonts.sizes.applications; + terminal = 12; + }; + }; + }; + }; + }; +} diff --git a/aspects/systems/base.nix b/aspects/systems/base.nix new file mode 100644 index 0000000..fdfc525 --- /dev/null +++ b/aspects/systems/base.nix @@ -0,0 +1,55 @@ +{ inputs, ... }: +{ + flake.modules = { + nixos.base = + { lib, pkgs, ... }: + { + imports = with inputs.self.modules.nixos; [ + boot + console + firewall + fish + locale + nix + security + ssh + ]; + environment = { + systemPackages = with pkgs; [ + git + fastfetch + nixos-firewall-tool + sysz + wget + yazi + ]; + shellAliases = { + cat = "${lib.getExe pkgs.bat} --paging=never --style=plain"; + ls = "${lib.getExe pkgs.eza} --git --icons --group-directories-first"; + tree = "ls --tree"; + }; + }; + + programs.command-not-found.enable = false; + + services = { + dbus.implementation = "broker"; + irqbalance.enable = true; + fstrim.enable = true; + tailscale = { + enable = true; + extraUpFlags = [ "--operator=user" ]; + }; + }; + }; + + homeManager.base = + { ... }: + { + imports = with inputs.self.modules.homeManager; [ + bash + fish + ]; + }; + }; +} diff --git a/aspects/systems/cli.nix b/aspects/systems/cli.nix new file mode 100644 index 0000000..2b95f0e --- /dev/null +++ b/aspects/systems/cli.nix @@ -0,0 +1,33 @@ +{ inputs, ... }: + +{ + flake.modules = { + nixos.cli = + { pkgs, ... }: + { + imports = with inputs.self.modules.nixos; [ + btop + helix + tmux + ]; + + environment.systemPackages = with pkgs; [ + p7zip + rclone + ]; + }; + homeManager.cli = + { ... }: + { + imports = with inputs.self.modules.homeManager; [ + btop + comma + direnv + helix + hm-cli + starship + tmux + ]; + }; + }; +} diff --git a/aspects/systems/desktop.nix b/aspects/systems/desktop.nix new file mode 100644 index 0000000..fb3aa1b --- /dev/null +++ b/aspects/systems/desktop.nix @@ -0,0 +1,210 @@ +{ + inputs, + ... +}: +{ + flake.modules = { + nixos.desktop = + { + config, + lib, + pkgs, + ... + }: + { + imports = [ + inputs.nix-flatpak.nixosModules.nix-flatpak + ] + ++ (with inputs.self.modules.nixos; [ + graphics + media + office + web + ]); + + boot = { + plymouth.enable = true; + initrd.systemd.enable = true; + loader.efi.efiSysMountPoint = "/boot/efi"; + kernelPackages = pkgs.linuxPackages_xanmod_latest; + extraModprobeConfig = '' + options bluetooth disable_ertm=1 + ''; + kernel.sysctl = { + "net.ipv4.tcp_mtu_probing" = 1; + }; + kernelParams = [ + "quiet" + "splash" + "i2c-dev" + "i2c-piix4" + "loglevel=3" + "udev.log_priority=3" + "rd.udev.log_level=3" + "rd.systemd.show_status=false" + ]; + }; + + nix = { + registry.nixpkgs.flake = inputs.nixpkgs; + nixPath = [ + "nixpkgs=${inputs.nixpkgs}" + "/nix/var/nix/profiles/per-user/root/channels" + ]; + }; + + environment = { + etc."channels/nixpkgs".source = inputs.nixpkgs.outPath; + sessionVariables = { + KDEHOME = "$XDG_CONFIG_HOME/kde4"; # Stops kde from placing a .kde4 folder in the home dir + NIXOS_OZONE_WL = "1"; # Forces chromium and most electron apps to run in wayland + }; + systemPackages = with pkgs; [ + adwaita-icon-theme + ghostty + gnome-disk-utility + junction + libfido2 + mission-center + nautilus + toggleaudiosink + unrar + ]; + }; + + services = { + printing.enable = true; + udev.packages = with pkgs; [ yubikey-personalization ]; + keyd = { + enable = true; + keyboards.all = { + ids = [ "*" ]; + settings.main.capslock = "overload(meta, esc)"; + }; + }; + pipewire = { + enable = true; + alsa.enable = true; + alsa.support32Bit = true; + pulse.enable = true; + jack.enable = true; + wireplumber.enable = true; + }; + greetd = { + enable = true; + settings.default_session.user = "greeter"; + }; + flatpak = { + enable = true; + packages = [ + "com.github.tchx84.Flatseal" + "com.rustdesk.RustDesk" + ]; + uninstallUnmanaged = true; + update.auto.enable = true; + }; + gvfs.enable = true; + }; + + security.rtkit.enable = true; # Needed for pipewire to acquire realtime priority + + users = { + users.greeter = { + isSystemUser = true; + group = "greeter"; + }; + groups.greeter = { }; + }; + + programs = { + kdeconnect = { + enable = true; + package = pkgs.valent; + }; + dconf.enable = true; + appimage = { + enable = true; + binfmt = true; + }; + }; + + fonts = { + fontDir.enable = true; + packages = with pkgs; [ + corefonts + inter + nerd-fonts.fira-code + noto-fonts-cjk-sans + noto-fonts-color-emoji + roboto + ]; + }; + + xdg.portal = { + extraPortals = with pkgs; [ + xdg-desktop-portal-gnome + xdg-desktop-portal-gtk + ]; + config.common.default = "*"; + }; + }; + + homeManager.desktop = + { + config, + lib, + pkgs, + inputs, + ... + }: + { + imports = [ + inputs.vicinae.homeManagerModules.default + ] + ++ (with inputs.self.modules.homeManager; [ media ]); + + fonts.fontconfig.enable = true; + + home = { + packages = with pkgs; [ xwayland-satellite ]; + sessionVariables.TERMINAL = "ghostty"; + }; + + services.vicinae = { + enable = true; + systemd = { + enable = true; + autoStart = true; + }; + }; + + programs = { + ghostty = { + enable = true; + settings = { + cursor-style = "block"; + shell-integration-features = "no-cursor"; + cursor-style-blink = false; + custom-shader = "${builtins.fetchurl { + url = "https://raw.githubusercontent.com/hackr-sh/ghostty-shaders/cb6eb4b0d1a3101c869c62e458b25a826f9dcde3/cursor_blaze.glsl"; + sha256 = "sha256:0g2lgqjdrn3c51glry7x2z30y7ml0y61arl5ykmf4yj0p85s5f41"; + }}"; + bell-features = ""; + gtk-titlebar-style = "tabs"; + keybind = [ "shift+enter=text:\\x1b\\r" ]; + }; + }; + + password-store = { + enable = true; + package = pkgs.pass-wayland; + }; + }; + + xdg = { + enable = true; + userDirs.enable = true; + }; + }; + }; +} diff --git a/aspects/systems/gaming.nix b/aspects/systems/gaming.nix new file mode 100644 index 0000000..e73a6fe --- /dev/null +++ b/aspects/systems/gaming.nix @@ -0,0 +1,48 @@ +{ inputs, ... }: + +{ + flake.modules = { + nixos.gaming = + { pkgs, ... }: + { + imports = with inputs.self.modules.nixos; [ + mangohud + steam + ]; + hardware = { + xpadneo.enable = true; + steam-hardware.enable = true; # Allow steam client to manage controllers + graphics.enable32Bit = true; # For OpenGL games + }; + + services.flatpak.packages = [ + "com.github.k4zmu2a.spacecadetpinball" + "io.itch.itch" + "io.mrarm.mcpelauncher" + "net.retrodeck.retrodeck" + "org.freedesktop.Platform.VulkanLayer.MangoHud/x86_64/25.08" + rec { + appId = "com.hypixel.HytaleLauncher"; + sha256 = "01307s44bklc1ldcigcn9n4lm8hf8q793v9fv7w4w04xd5zyh4rv"; + bundle = "${pkgs.fetchurl { + url = "https://launcher.hytale.com/builds/release/linux/amd64/hytale-launcher-latest.flatpak"; + inherit sha256; + }}"; + } + ]; + + environment.systemPackages = with pkgs; [ + clonehero + heroic + prismlauncher + ]; + }; + homeManager.gaming = + { ... }: + { + imports = with inputs.self.modules.homeManager; [ + mangohud + ]; + }; + }; +} diff --git a/aspects/systems/server.nix b/aspects/systems/server.nix new file mode 100644 index 0000000..c3c24f0 --- /dev/null +++ b/aspects/systems/server.nix @@ -0,0 +1,36 @@ +{ inputs, ... }: + +{ + flake.modules.nixos.server = + { + config, + lib, + pkgs, + ... + }: + { + boot = { + kernelPackages = pkgs.linuxPackages_hardened; + kernel.sysctl = { + "net.ipv4.ip_forward" = 1; + "net.ipv6.conf.all.forwarding" = 1; + }; + }; + + environment.etc."channels/nixpkgs".source = inputs.nixpkgs-stable.outPath; + + nix = { + registry.nixpkgs.flake = inputs.nixpkgs-stable; + nixPath = [ + "nixpkgs=/etc/channels/nixpkgs" + "/nix/var/nix/profiles/per-user/root/channels" + ]; + }; + + services.tailscale = { + extraSetFlags = [ "--advertise-exit-node" ]; + useRoutingFeatures = "server"; + }; + + }; +} diff --git a/aspects/users/_user/git.nix b/aspects/users/_user/git.nix new file mode 100644 index 0000000..40a5714 --- /dev/null +++ b/aspects/users/_user/git.nix @@ -0,0 +1,17 @@ +{ ... }: + +{ + programs = { + git = { + enable = true; + settings.user = { + name = "William"; + email = "baduhai@proton.me"; + }; + }; + diff-so-fancy = { + enable = true; + enableGitIntegration = true; + }; + }; +} diff --git a/aspects/users/root.nix b/aspects/users/root.nix new file mode 100644 index 0000000..ff04c56 --- /dev/null +++ b/aspects/users/root.nix @@ -0,0 +1,12 @@ +{ ... }: + +{ + flake.modules.nixos.root = + { pkgs, ... }: + { + users.users.root = { + shell = pkgs.fish; + hashedPassword = "!"; + }; + }; +} diff --git a/aspects/users/user.nix b/aspects/users/user.nix new file mode 100644 index 0000000..86bcddb --- /dev/null +++ b/aspects/users/user.nix @@ -0,0 +1,55 @@ +{ inputs, ... }: + +let + mkHomeConfiguration = inputs.self.lib.mkHomeConfiguration; +in + +{ + flake = { + modules.nixos.user = + { pkgs, ... }: + { + users.users.user = { + isNormalUser = true; + shell = pkgs.fish; + extraGroups = [ + "networkmanager" + "wheel" + ]; + openssh.authorizedKeys.keys = [ + "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAICQPkAyy+Du9Omc2WtnUF2TV8jFAF4H6mJi2D4IZ1nzg user@himalia" + "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIO3Y0PVpGfJHonqDS7qoCFhqzUvqGq9I9sax+F9e/5cs user@io" + "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIA1v3+q3EaruiiStWjubEJWvtejam/r41uoOpCdwJtLL user@rotterdam" + ]; + hashedPassword = "$6$Pj7v/CpstyuWQQV0$cNujVDhfMBdwlGVEnnd8t71.kZPixbo0u25cd.874iaqLTH4V5fa1f98V5zGapjQCz5JyZmsR94xi00sUrntT0"; + }; + }; + homeConfigurations = { + "user@rotterdam" = mkHomeConfiguration { + user = "user"; + hostname = "rotterdam"; + userModules = with inputs.self.modules.homeManager; [ + # system aspects + desktop + gaming + + # other aspects + stylix + niri + ]; + }; + "user@io" = mkHomeConfiguration { + user = "user"; + hostname = "io"; + userModules = with inputs.self.modules.homeManager; [ + # system aspects + desktop + + # other aspects + stylix + niri + ]; + }; + }; + }; +} diff --git a/data/services.nix b/data/services.nix new file mode 100644 index 0000000..ae7395c --- /dev/null +++ b/data/services.nix @@ -0,0 +1,42 @@ +# Shared service and host definitions +# This file can be imported directly (unlike aspects which use flake-parts) +{ + hosts = { + alexandria = { + lanIP = "192.168.15.142"; + tailscaleIP = "100.76.19.50"; + }; + trantor = { + tailscaleIP = "100.108.5.90"; + }; + }; + + services = [ + { + name = "kanidm"; + domain = "auth.baduhai.dev"; + host = "alexandria"; + } + { + name = "vaultwarden"; + domain = "pass.baduhai.dev"; + host = "alexandria"; + } + { + name = "forgejo"; + domain = "git.baduhai.dev"; + host = "trantor"; + public = true; + } + { + name = "nextcloud"; + domain = "cloud.baduhai.dev"; + host = "alexandria"; + } + { + name = "jellyfin"; + domain = "jellyfin.baduhai.dev"; + host = "alexandria"; + } + ]; +} diff --git a/flake.lock b/flake.lock index b5b63cf..a99cac7 100644 --- a/flake.lock +++ b/flake.lock @@ -10,11 +10,11 @@ "systems": "systems" }, "locked": { - "lastModified": 1762618334, - "narHash": "sha256-wyT7Pl6tMFbFrs8Lk/TlEs81N6L+VSybPfiIgzU8lbQ=", + "lastModified": 1770165109, + "narHash": "sha256-9VnK6Oqai65puVJ4WYtCTvlJeXxMzAp/69HhQuTdl/I=", "owner": "ryantm", "repo": "agenix", - "rev": "fcdea223397448d35d9b31f798479227e80183f6", + "rev": "b027ee29d959fda4b60b57566d64c98a202e0feb", "type": "github" }, "original": { @@ -97,14 +97,14 @@ "nix-ai-tools", "nixpkgs" ], - "systems": "systems_3" + "systems": "systems_2" }, "locked": { - "lastModified": 1767386128, - "narHash": "sha256-BJDu7dIMauO2nYRSL4aI8wDNtEm2KOb7lDKP3hxdrpo=", + "lastModified": 1771437256, + "narHash": "sha256-bLqwib+rtyBRRVBWhMuBXPCL/OThfokA+j6+uH7jDGU=", "owner": "numtide", "repo": "blueprint", - "rev": "0ed984d51a3031065925ab08812a5434f40b93d4", + "rev": "06ee7190dc2620ea98af9eb225aa9627b68b0e33", "type": "github" }, "original": { @@ -135,36 +135,16 @@ "type": "github" } }, - "deploy-rs": { - "inputs": { - "flake-compat": "flake-compat", - "nixpkgs": "nixpkgs", - "utils": "utils" - }, - "locked": { - "lastModified": 1766051518, - "narHash": "sha256-znKOwPXQnt3o7lDb3hdf19oDo0BLP4MfBOYiWkEHoik=", - "owner": "serokell", - "repo": "deploy-rs", - "rev": "d5eff7f948535b9c723d60cd8239f8f11ddc90fa", - "type": "github" - }, - "original": { - "owner": "serokell", - "repo": "deploy-rs", - "type": "github" - } - }, "disko": { "inputs": { - "nixpkgs": "nixpkgs_2" + "nixpkgs": "nixpkgs" }, "locked": { - "lastModified": 1768923567, - "narHash": "sha256-GVJ0jKsyXLuBzRMXCDY6D5J8wVdwP1DuQmmvYL/Vw/Q=", + "lastModified": 1769524058, + "narHash": "sha256-zygdD6X1PcVNR2PsyK4ptzrVEiAdbMqLos7utrMDEWE=", "owner": "nix-community", "repo": "disko", - "rev": "00395d188e3594a1507f214a2f15d4ce5c07cb28", + "rev": "71a3fc97d80881e91710fe721f1158d3b96ae14d", "type": "github" }, "original": { @@ -190,22 +170,6 @@ } }, "flake-compat": { - "flake": false, - "locked": { - "lastModified": 1733328505, - "narHash": "sha256-NeCCThCEP3eCl2l/+27kNNK7QrwZB1IJCrXfrbv5oqU=", - "owner": "edolstra", - "repo": "flake-compat", - "rev": "ff81ac966bb2cae68946d5ed5fc4994f96d0ffec", - "type": "github" - }, - "original": { - "owner": "edolstra", - "repo": "flake-compat", - "type": "github" - } - }, - "flake-compat_2": { "flake": false, "locked": { "lastModified": 1767039857, @@ -221,7 +185,7 @@ "type": "github" } }, - "flake-compat_3": { + "flake-compat_2": { "flake": false, "locked": { "lastModified": 1747046372, @@ -242,11 +206,11 @@ "nixpkgs-lib": "nixpkgs-lib" }, "locked": { - "lastModified": 1768135262, - "narHash": "sha256-PVvu7OqHBGWN16zSi6tEmPwwHQ4rLPU9Plvs8/1TUBY=", + "lastModified": 1769996383, + "narHash": "sha256-AnYjnFWgS49RlqX7LrC4uA+sCCDBj0Ry/WOJ5XWAsa0=", "owner": "hercules-ci", "repo": "flake-parts", - "rev": "80daad04eddbbf5a4d883996a73f3f542fa437ac", + "rev": "57928607ea566b5db3ad13af0e57e921e6b12381", "type": "github" }, "original": { @@ -378,11 +342,11 @@ ] }, "locked": { - "lastModified": 1768927746, - "narHash": "sha256-zyMpWHqcpKVmRc1W2NEK7DAuyVJZV62Jdjqudg70b1k=", + "lastModified": 1770915843, + "narHash": "sha256-ZwU5wXKNqpOQvjNz6aBp1j5peiBZow1++6pLnk5VAhs=", "owner": "nix-community", "repo": "home-manager", - "rev": "63a87808f5f9b6e4195a1d33f6ea25d23f4aa0df", + "rev": "6a1f7101d2c3ee87d485a87880d73b4665c6a4bd", "type": "github" }, "original": { @@ -421,11 +385,11 @@ ] }, "locked": { - "lastModified": 1768434960, - "narHash": "sha256-cJbFn17oyg6qAraLr+NVeNJrXsrzJdrudkzI4H2iTcg=", + "lastModified": 1769872935, + "narHash": "sha256-07HMIGQ/WJeAQJooA7Kkg1SDKxhAiV6eodvOwTX6WKI=", "owner": "nix-community", "repo": "home-manager", - "rev": "b4d88c9ac42ae1a745283f6547701da43b6e9f9b", + "rev": "f4ad5068ee8e89e4a7c2e963e10dd35cd77b37b7", "type": "github" }, "original": { @@ -437,14 +401,14 @@ "impermanence": { "inputs": { "home-manager": "home-manager_3", - "nixpkgs": "nixpkgs_3" + "nixpkgs": "nixpkgs_2" }, "locked": { - "lastModified": 1768835187, - "narHash": "sha256-6nY0ixjGjPQCL+/sUC1B1MRiO1LOI3AkRSIywm3i3bE=", + "lastModified": 1769548169, + "narHash": "sha256-03+JxvzmfwRu+5JafM0DLbxgHttOQZkUtDWBmeUkN8Y=", "owner": "nix-community", "repo": "impermanence", - "rev": "0d633a69480bb3a3e2f18c080d34a8fa81da6395", + "rev": "7b1d382faf603b6d264f58627330f9faa5cba149", "type": "github" }, "original": { @@ -453,94 +417,33 @@ "type": "github" } }, - "niri": { - "inputs": { - "nixpkgs": "nixpkgs_4", - "rust-overlay": "rust-overlay" - }, + "import-tree": { "locked": { - "lastModified": 1760963745, - "narHash": "sha256-FVf9YFw2wQnMAxvMxEk+vFakXhPQUSapDpGmlLzAxjg=", - "owner": "baduhai", - "repo": "niri", - "rev": "dd3e3d1009991ecd87ab7253c9e7696acf2bc943", + "lastModified": 1763762820, + "narHash": "sha256-ZvYKbFib3AEwiNMLsejb/CWs/OL/srFQ8AogkebEPF0=", + "owner": "vic", + "repo": "import-tree", + "rev": "3c23749d8013ec6daa1d7255057590e9ca726646", "type": "github" }, "original": { - "owner": "baduhai", - "ref": "auto-center-when-space-available", - "repo": "niri", - "type": "github" - } - }, - "niri-flake": { - "inputs": { - "niri-stable": "niri-stable", - "niri-unstable": "niri-unstable", - "nixpkgs": "nixpkgs_5", - "nixpkgs-stable": "nixpkgs-stable", - "xwayland-satellite-stable": "xwayland-satellite-stable", - "xwayland-satellite-unstable": "xwayland-satellite-unstable" - }, - "locked": { - "lastModified": 1768877436, - "narHash": "sha256-ct4qxmFJeJbaJKiOnXOZmRmVmk7TpT+lohuTgTr+kYQ=", - "owner": "sodiboo", - "repo": "niri-flake", - "rev": "6581f5458309233622c1b73c8902dcaea7be16eb", - "type": "github" - }, - "original": { - "owner": "sodiboo", - "repo": "niri-flake", - "type": "github" - } - }, - "niri-stable": { - "flake": false, - "locked": { - "lastModified": 1756556321, - "narHash": "sha256-RLD89dfjN0RVO86C/Mot0T7aduCygPGaYbog566F0Qo=", - "owner": "YaLTeR", - "repo": "niri", - "rev": "01be0e65f4eb91a9cd624ac0b76aaeab765c7294", - "type": "github" - }, - "original": { - "owner": "YaLTeR", - "ref": "v25.08", - "repo": "niri", - "type": "github" - } - }, - "niri-unstable": { - "flake": false, - "locked": { - "lastModified": 1768678265, - "narHash": "sha256-Ub8eed4DsfIDWyg30xEe+8bSxL/z5Af/gCjmvJ0V/Hs=", - "owner": "YaLTeR", - "repo": "niri", - "rev": "d7184a04b904e07113f4623610775ae78d32394c", - "type": "github" - }, - "original": { - "owner": "YaLTeR", - "repo": "niri", + "owner": "vic", + "repo": "import-tree", "type": "github" } }, "nix-ai-tools": { "inputs": { "blueprint": "blueprint", - "nixpkgs": "nixpkgs_6", + "nixpkgs": "nixpkgs_3", "treefmt-nix": "treefmt-nix" }, "locked": { - "lastModified": 1768922080, - "narHash": "sha256-gFoGvnW2YDWsxKD56kdiXbhh9vBPAU3yusssbXF0UMo=", + "lastModified": 1771816560, + "narHash": "sha256-q5Wsb1573qDfIPJctG9CBZP0NMniejoB7SmBLZIVAHg=", "owner": "numtide", "repo": "llm-agents.nix", - "rev": "78f3fdc13ef903475aa5bfc0f85eeefaa36af837", + "rev": "db94a329058a1a37b49d3209af85708b3338559a", "type": "github" }, "original": { @@ -572,11 +475,11 @@ ] }, "locked": { - "lastModified": 1765267181, - "narHash": "sha256-d3NBA9zEtBu2JFMnTBqWj7Tmi7R5OikoU2ycrdhQEws=", + "lastModified": 1770315571, + "narHash": "sha256-hy0gcAgAcxrnSWKGuNO+Ob0x6jQ2xkR6hoaR0qJBHYs=", "owner": "nix-community", "repo": "nix-index-database", - "rev": "82befcf7dc77c909b0f2a09f5da910ec95c5b78f", + "rev": "2684bb8080a6f2ca5f9d494de5ef875bc1c4ecdb", "type": "github" }, "original": { @@ -587,17 +490,17 @@ }, "nixos-cli": { "inputs": { - "flake-compat": "flake-compat_2", + "flake-compat": "flake-compat", "flake-parts": "flake-parts_2", - "nixpkgs": "nixpkgs_7", + "nixpkgs": "nixpkgs_4", "optnix": "optnix" }, "locked": { - "lastModified": 1768778579, - "narHash": "sha256-6w1Mhg6+46LlaheCa1O/jIk02ukerZ7DdUf9GlQVGxc=", + "lastModified": 1770862985, + "narHash": "sha256-TFRhwVzPg3ly388J3CYYvjrma/dWjsBVpNE437bWeHk=", "owner": "nix-community", "repo": "nixos-cli", - "rev": "5e79001c7a8b556c3c61d4ef38f0f0fa1187ee90", + "rev": "9a2e97e8832b211df22c5cb21a55ebf1c3eb2be1", "type": "github" }, "original": { @@ -608,11 +511,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1743014863, - "narHash": "sha256-jAIUqsiN2r3hCuHji80U7NNEafpIMBXiwKlSrjWMlpg=", + "lastModified": 1769330179, + "narHash": "sha256-yxgb4AmkVHY5OOBrC79Vv6EVd4QZEotqv+6jcvA212M=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "bd3bac8bfb542dbde7ffffb6987a1a1f9d41699f", + "rev": "48698d12cc10555a4f3e3222d9c669b884a49dfe", "type": "github" }, "original": { @@ -624,11 +527,11 @@ }, "nixpkgs-lib": { "locked": { - "lastModified": 1765674936, - "narHash": "sha256-k00uTP4JNfmejrCLJOwdObYC9jHRrr/5M/a/8L2EIdo=", + "lastModified": 1769909678, + "narHash": "sha256-cBEymOf4/o3FD5AZnzC3J9hLbiZ+QDT/KDuyHXVJOpM=", "owner": "nix-community", "repo": "nixpkgs.lib", - "rev": "2075416fcb47225d9b68ac469a5c4801a9c4dd85", + "rev": "72716169fe93074c333e8d0173151350670b824c", "type": "github" }, "original": { @@ -654,27 +557,11 @@ }, "nixpkgs-stable": { "locked": { - "lastModified": 1768773494, - "narHash": "sha256-XsM7GP3jHlephymxhDE+/TKKO1Q16phz/vQiLBGhpF4=", - "owner": "NixOS", - "repo": "nixpkgs", - "rev": "77ef7a29d276c6d8303aece3444d61118ef71ac2", - "type": "github" - }, - "original": { - "owner": "NixOS", - "ref": "nixos-25.11", - "repo": "nixpkgs", - "type": "github" - } - }, - "nixpkgs-stable_2": { - "locked": { - "lastModified": 1768773494, - "narHash": "sha256-XsM7GP3jHlephymxhDE+/TKKO1Q16phz/vQiLBGhpF4=", + "lastModified": 1770770419, + "narHash": "sha256-iKZMkr6Cm9JzWlRYW/VPoL0A9jVKtZYiU4zSrVeetIs=", "owner": "nixos", "repo": "nixpkgs", - "rev": "77ef7a29d276c6d8303aece3444d61118ef71ac2", + "rev": "6c5e707c6b5339359a9a9e215c5e66d6d802fd7a", "type": "github" }, "original": { @@ -684,135 +571,39 @@ "type": "github" } }, - "nixpkgs_10": { - "locked": { - "lastModified": 1767767207, - "narHash": "sha256-Mj3d3PfwltLmukFal5i3fFt27L6NiKXdBezC1EBuZs4=", - "owner": "NixOS", - "repo": "nixpkgs", - "rev": "5912c1772a44e31bf1c63c0390b90501e5026886", - "type": "github" - }, - "original": { - "owner": "NixOS", - "ref": "nixos-unstable", - "repo": "nixpkgs", - "type": "github" - } - }, - "nixpkgs_11": { - "locked": { - "lastModified": 1762111121, - "narHash": "sha256-4vhDuZ7OZaZmKKrnDpxLZZpGIJvAeMtK6FKLJYUtAdw=", - "owner": "NixOS", - "repo": "nixpkgs", - "rev": "b3d51a0365f6695e7dd5cdf3e180604530ed33b4", - "type": "github" - }, - "original": { - "owner": "NixOS", - "ref": "nixos-unstable", - "repo": "nixpkgs", - "type": "github" - } - }, - "nixpkgs_12": { - "locked": { - "lastModified": 1768127708, - "narHash": "sha256-1Sm77VfZh3mU0F5OqKABNLWxOuDeHIlcFjsXeeiPazs=", - "owner": "nixos", - "repo": "nixpkgs", - "rev": "ffbc9f8cbaacfb331b6017d5a5abb21a492c9a38", - "type": "github" - }, - "original": { - "owner": "nixos", - "ref": "nixos-unstable", - "repo": "nixpkgs", - "type": "github" - } - }, "nixpkgs_2": { "locked": { - "lastModified": 1768661221, - "narHash": "sha256-MJwOjrIISfOpdI9x4C+5WFQXvHtOuj5mqLZ4TMEtk1M=", - "owner": "NixOS", + "lastModified": 1768564909, + "narHash": "sha256-Kell/SpJYVkHWMvnhqJz/8DqQg2b6PguxVWOuadbHCc=", + "owner": "nixos", "repo": "nixpkgs", - "rev": "3327b113f2ef698d380df83fbccefad7e83d7769", + "rev": "e4bae1bd10c9c57b2cf517953ab70060a828ee6f", "type": "github" }, "original": { - "owner": "NixOS", - "ref": "nixpkgs-unstable", + "owner": "nixos", + "ref": "nixos-unstable", "repo": "nixpkgs", "type": "github" } }, "nixpkgs_3": { "locked": { - "lastModified": 1768564909, - "narHash": "sha256-Kell/SpJYVkHWMvnhqJz/8DqQg2b6PguxVWOuadbHCc=", - "owner": "nixos", + "lastModified": 1771207753, + "narHash": "sha256-b9uG8yN50DRQ6A7JdZBfzq718ryYrlmGgqkRm9OOwCE=", + "owner": "NixOS", "repo": "nixpkgs", - "rev": "e4bae1bd10c9c57b2cf517953ab70060a828ee6f", + "rev": "d1c15b7d5806069da59e819999d70e1cec0760bf", "type": "github" }, "original": { - "owner": "nixos", - "ref": "nixos-unstable", + "owner": "NixOS", + "ref": "nixpkgs-unstable", "repo": "nixpkgs", "type": "github" } }, "nixpkgs_4": { - "locked": { - "lastModified": 1757967192, - "narHash": "sha256-/aA9A/OBmnuOMgwfzdsXRusqzUpd8rQnQY8jtrHK+To=", - "owner": "NixOS", - "repo": "nixpkgs", - "rev": "0d7c15863b251a7a50265e57c1dca1a7add2e291", - "type": "github" - }, - "original": { - "owner": "NixOS", - "ref": "nixpkgs-unstable", - "repo": "nixpkgs", - "type": "github" - } - }, - "nixpkgs_5": { - "locked": { - "lastModified": 1768564909, - "narHash": "sha256-Kell/SpJYVkHWMvnhqJz/8DqQg2b6PguxVWOuadbHCc=", - "owner": "NixOS", - "repo": "nixpkgs", - "rev": "e4bae1bd10c9c57b2cf517953ab70060a828ee6f", - "type": "github" - }, - "original": { - "owner": "NixOS", - "ref": "nixos-unstable", - "repo": "nixpkgs", - "type": "github" - } - }, - "nixpkgs_6": { - "locked": { - "lastModified": 1768783163, - "narHash": "sha256-tLj4KcRDLakrlpvboTJDKsrp6z2XLwyQ4Zmo+w8KsY4=", - "owner": "NixOS", - "repo": "nixpkgs", - "rev": "bde09022887110deb780067364a0818e89258968", - "type": "github" - }, - "original": { - "owner": "NixOS", - "ref": "nixpkgs-unstable", - "repo": "nixpkgs", - "type": "github" - } - }, - "nixpkgs_7": { "locked": { "lastModified": 1767151656, "narHash": "sha256-ujL2AoYBnJBN262HD95yer7QYUmYp5kFZGYbyCCKxq8=", @@ -828,7 +619,7 @@ "type": "github" } }, - "nixpkgs_8": { + "nixpkgs_5": { "locked": { "lastModified": 1759070547, "narHash": "sha256-JVZl8NaVRYb0+381nl7LvPE+A774/dRpif01FKLrYFQ=", @@ -844,13 +635,61 @@ "type": "github" } }, - "nixpkgs_9": { + "nixpkgs_6": { "locked": { - "lastModified": 1768564909, - "narHash": "sha256-Kell/SpJYVkHWMvnhqJz/8DqQg2b6PguxVWOuadbHCc=", + "lastModified": 1770562336, + "narHash": "sha256-ub1gpAONMFsT/GU2hV6ZWJjur8rJ6kKxdm9IlCT0j84=", "owner": "nixos", "repo": "nixpkgs", - "rev": "e4bae1bd10c9c57b2cf517953ab70060a828ee6f", + "rev": "d6c71932130818840fc8fe9509cf50be8c64634f", + "type": "github" + }, + "original": { + "owner": "nixos", + "ref": "nixos-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs_7": { + "locked": { + "lastModified": 1767767207, + "narHash": "sha256-Mj3d3PfwltLmukFal5i3fFt27L6NiKXdBezC1EBuZs4=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "5912c1772a44e31bf1c63c0390b90501e5026886", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixos-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs_8": { + "locked": { + "lastModified": 1762111121, + "narHash": "sha256-4vhDuZ7OZaZmKKrnDpxLZZpGIJvAeMtK6FKLJYUtAdw=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "b3d51a0365f6695e7dd5cdf3e180604530ed33b4", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixos-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs_9": { + "locked": { + "lastModified": 1769461804, + "narHash": "sha256-msG8SU5WsBUfVVa/9RPLaymvi5bI8edTavbIq3vRlhI=", + "owner": "nixos", + "repo": "nixpkgs", + "rev": "bfc1b8a4574108ceef22f02bafcf6611380c100d", "type": "github" }, "original": { @@ -867,11 +706,11 @@ ] }, "locked": { - "lastModified": 1768924718, - "narHash": "sha256-T4H/VMjGwBuHEIrPYWfXQ73XV0foCuFGgH7k3SNSJDo=", + "lastModified": 1770922006, + "narHash": "sha256-xg40mnp5KKBepACmvlPzmn5iPyUBxktfv50saSVUn0M=", "owner": "noctalia-dev", "repo": "noctalia-shell", - "rev": "1ef5c0eb307e8a4f30dfa6bcc75cf90ae8c6af46", + "rev": "d87364964948b9d691f8363f85a5e23bee154df9", "type": "github" }, "original": { @@ -907,8 +746,8 @@ }, "optnix": { "inputs": { - "flake-compat": "flake-compat_3", - "nixpkgs": "nixpkgs_8" + "flake-compat": "flake-compat_2", + "nixpkgs": "nixpkgs_5" }, "locked": { "lastModified": 1765418479, @@ -927,19 +766,17 @@ "root": { "inputs": { "agenix": "agenix", - "deploy-rs": "deploy-rs", "disko": "disko", "flake-parts": "flake-parts", "home-manager": "home-manager_2", "impermanence": "impermanence", - "niri": "niri", - "niri-flake": "niri-flake", + "import-tree": "import-tree", "nix-ai-tools": "nix-ai-tools", "nix-flatpak": "nix-flatpak", "nix-index-database": "nix-index-database", "nixos-cli": "nixos-cli", - "nixpkgs": "nixpkgs_9", - "nixpkgs-stable": "nixpkgs-stable_2", + "nixpkgs": "nixpkgs_6", + "nixpkgs-stable": "nixpkgs-stable", "noctalia": "noctalia", "stylix": "stylix", "terranix": "terranix", @@ -947,27 +784,6 @@ "zen-browser": "zen-browser" } }, - "rust-overlay": { - "inputs": { - "nixpkgs": [ - "niri", - "nixpkgs" - ] - }, - "locked": { - "lastModified": 1757989933, - "narHash": "sha256-9cpKYWWPCFhgwQTww8S94rTXgg8Q8ydFv9fXM6I8xQM=", - "owner": "oxalica", - "repo": "rust-overlay", - "rev": "8249aa3442fb9b45e615a35f39eca2fe5510d7c3", - "type": "github" - }, - "original": { - "owner": "oxalica", - "repo": "rust-overlay", - "type": "github" - } - }, "stylix": { "inputs": { "base16": "base16", @@ -977,9 +793,9 @@ "firefox-gnome-theme": "firefox-gnome-theme", "flake-parts": "flake-parts_3", "gnome-shell": "gnome-shell", - "nixpkgs": "nixpkgs_10", + "nixpkgs": "nixpkgs_7", "nur": "nur", - "systems": "systems_4", + "systems": "systems_3", "tinted-foot": "tinted-foot", "tinted-kitty": "tinted-kitty", "tinted-schemes": "tinted-schemes", @@ -987,11 +803,11 @@ "tinted-zed": "tinted-zed" }, "locked": { - "lastModified": 1768744881, - "narHash": "sha256-3+h7OxqfrPIB/tRsiZXWE9sCbTm7NQN5Ie428p+S6BA=", + "lastModified": 1770914701, + "narHash": "sha256-QHFYyngohNhih4w+3IqQty5DV+p1txsx1kkk6XJWar8=", "owner": "danth", "repo": "stylix", - "rev": "06684f00cfbee14da96fd4307b966884de272d3a", + "rev": "db03fed72e5ca02be34e1d24789345a943329738", "type": "github" }, "original": { @@ -1075,28 +891,13 @@ "type": "github" } }, - "systems_6": { - "locked": { - "lastModified": 1681028828, - "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", - "owner": "nix-systems", - "repo": "default", - "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", - "type": "github" - }, - "original": { - "owner": "nix-systems", - "repo": "default", - "type": "github" - } - }, "terranix": { "inputs": { "flake-parts": "flake-parts_4", "nixpkgs": [ "nixpkgs" ], - "systems": "systems_5" + "systems": "systems_4" }, "locked": { "lastModified": 1762472226, @@ -1201,11 +1002,11 @@ ] }, "locked": { - "lastModified": 1768158989, - "narHash": "sha256-67vyT1+xClLldnumAzCTBvU0jLZ1YBcf4vANRWP3+Ak=", + "lastModified": 1770228511, + "narHash": "sha256-wQ6NJSuFqAEmIg2VMnLdCnUc0b7vslUohqqGGD+Fyxk=", "owner": "numtide", "repo": "treefmt-nix", - "rev": "e96d59dff5c0d7fddb9d113ba108f03c3ef99eca", + "rev": "337a4fe074be1042a35086f15481d763b8ddc0e7", "type": "github" }, "original": { @@ -1214,35 +1015,17 @@ "type": "github" } }, - "utils": { - "inputs": { - "systems": "systems_2" - }, - "locked": { - "lastModified": 1731533236, - "narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=", - "owner": "numtide", - "repo": "flake-utils", - "rev": "11707dc2f618dd54ca8739b309ec4fc024de578b", - "type": "github" - }, - "original": { - "owner": "numtide", - "repo": "flake-utils", - "type": "github" - } - }, "vicinae": { "inputs": { - "nixpkgs": "nixpkgs_11", - "systems": "systems_6" + "nixpkgs": "nixpkgs_8", + "systems": "systems_5" }, "locked": { - "lastModified": 1768856963, - "narHash": "sha256-u5bWDuwk6oieTnvm1YjNotcYK8iJSddH5+S68+X4TSc=", + "lastModified": 1770912475, + "narHash": "sha256-21lurBRyHgJbVD3E0/i7Fhxi4rBUxyznGfKpdGVtEdc=", "owner": "vicinaehq", "repo": "vicinae", - "rev": "934bc0ad47be6dbd6498a0dac655c4613fd0ab27", + "rev": "0c70267ab7e07d7972012fcf8ae58808a32a2e86", "type": "github" }, "original": { @@ -1251,50 +1034,17 @@ "type": "github" } }, - "xwayland-satellite-stable": { - "flake": false, - "locked": { - "lastModified": 1755491097, - "narHash": "sha256-m+9tUfsmBeF2Gn4HWa6vSITZ4Gz1eA1F5Kh62B0N4oE=", - "owner": "Supreeeme", - "repo": "xwayland-satellite", - "rev": "388d291e82ffbc73be18169d39470f340707edaa", - "type": "github" - }, - "original": { - "owner": "Supreeeme", - "ref": "v0.7", - "repo": "xwayland-satellite", - "type": "github" - } - }, - "xwayland-satellite-unstable": { - "flake": false, - "locked": { - "lastModified": 1768765571, - "narHash": "sha256-C1JbyJ3ftogmN3vmLNfyPtnJw2wY64TiUTIhFtk1Leg=", - "owner": "Supreeeme", - "repo": "xwayland-satellite", - "rev": "ed1cef792b4def3321ff9ab5479df09609f17a69", - "type": "github" - }, - "original": { - "owner": "Supreeeme", - "repo": "xwayland-satellite", - "type": "github" - } - }, "zen-browser": { "inputs": { "home-manager": "home-manager_4", - "nixpkgs": "nixpkgs_12" + "nixpkgs": "nixpkgs_9" }, "locked": { - "lastModified": 1768919538, - "narHash": "sha256-w10iy/aqd5LtD78NDWWG+eKGzkb+cGhAAo7PVciLbWE=", + "lastModified": 1771000521, + "narHash": "sha256-5UDaXr770MaDac9HcFvGlUjsqyOoNbFdHArmjmtHcVk=", "owner": "0xc000022070", "repo": "zen-browser-flake", - "rev": "37149a5b77e8fd2b5332e8cec9edf39ca5b8e8bc", + "rev": "80ce62fd26af1934454f405bcb2510ceeea8d3a2", "type": "github" }, "original": { diff --git a/flake.nix b/flake.nix index 549724f..2036828 100644 --- a/flake.nix +++ b/flake.nix @@ -2,57 +2,57 @@ description = "My nix hosts"; inputs = { + # nix tools flake-parts.url = "github:hercules-ci/flake-parts"; + import-tree.url = "github:vic/import-tree"; + # nixos/hm nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable"; nixpkgs-stable.url = "github:nixos/nixpkgs/nixos-25.11"; - home-manager = { url = "github:nix-community/home-manager/master"; inputs.nixpkgs.follows = "nixpkgs"; }; + # nixos/hm functionality modules agenix = { url = "github:ryantm/agenix"; inputs.nixpkgs.follows = "nixpkgs-stable"; }; - disko.url = "github:nix-community/disko"; - - noctalia = { - url = "github:noctalia-dev/noctalia-shell"; - inputs.nixpkgs.follows = "nixpkgs"; - }; - - nixos-cli.url = "github:nix-community/nixos-cli"; - - nix-flatpak.url = "github:gmodena/nix-flatpak/main"; - - zen-browser.url = "github:0xc000022070/zen-browser-flake"; - impermanence.url = "github:nix-community/impermanence"; + nixos-cli.url = "github:nix-community/nixos-cli"; + nix-flatpak.url = "github:gmodena/nix-flatpak/main"; + stylix.url = "github:danth/stylix"; - deploy-rs.url = "github:serokell/deploy-rs"; - - niri-flake.url = "github:sodiboo/niri-flake"; - + # nixos/hm program modules + nix-ai-tools.url = "github:numtide/llm-agents.nix"; nix-index-database = { url = "github:nix-community/nix-index-database"; inputs.nixpkgs.follows = "nixpkgs"; }; + noctalia = { + url = "github:noctalia-dev/noctalia-shell"; + inputs.nixpkgs.follows = "nixpkgs"; + }; + vicinae.url = "github:vicinaehq/vicinae"; + zen-browser.url = "github:0xc000022070/zen-browser-flake"; + # stand-alone tools terranix = { url = "github:terranix/terranix"; inputs.nixpkgs.follows = "nixpkgs"; }; - - nix-ai-tools.url = "github:numtide/llm-agents.nix"; - - vicinae.url = "github:vicinaehq/vicinae"; }; outputs = - inputs@{ flake-parts, ... }: + inputs@{ flake-parts, import-tree, ... }: + let + aspectsModules = import-tree ./aspects; + packagesModules = import-tree ./packages; + shellsModules = import-tree ./shells; + terranixModules = import-tree ./terranix; + in flake-parts.lib.mkFlake { inherit inputs; } { systems = [ "x86_64-linux" @@ -60,14 +60,12 @@ ]; imports = [ - ./deploy.nix - ./devShells.nix - ./homeConfigurations.nix - ./nixosConfigurations.nix - ./nixosModules.nix - ./overlays.nix - ./packages.nix - ./terranixConfigurations.nix - ]; + flake-parts.flakeModules.modules + inputs.terranix.flakeModule + ] + ++ aspectsModules.imports + ++ packagesModules.imports + ++ shellsModules.imports + ++ terranixModules.imports; }; } diff --git a/modules/nix/agenix.nix b/modules/nix/agenix.nix deleted file mode 100644 index bf7c3c2..0000000 --- a/modules/nix/agenix.nix +++ /dev/null @@ -1,37 +0,0 @@ -{ - self, - inputs, - ... -}: -{ - flake-file.inputs = { - agenix = { - url = "github:ryantm/agenix"; - inputs.nixpkgs.follows = "nixpkgs"; - inputs.home-manager.follows = "home-manager"; - }; - secrets = { - url = "path:./secrets"; - flake = false; - }; - }; - - flake.modules = { - nixos.secrets = - { pkgs, ... }: - { - imports = [ - inputs.agenix.nixosModules.default - ]; - environment.systemPackages = [ inputs.agenix.packages.${pkgs.stdenv.hostPlatform.system}.default ]; - }; - - # homeManager.secrets = - # { pkgs, ... }: - # { - # imports = [ - # inputs.agenix.homeManagerModules.default - # ]; - # }; - }; -} diff --git a/modules/nix/dendritic-tools.nix b/modules/nix/dendritic-tools.nix deleted file mode 100644 index 134cd20..0000000 --- a/modules/nix/dendritic-tools.nix +++ /dev/null @@ -1,25 +0,0 @@ -{ - inputs, - ... -}: -{ - flake-file.inputs = { - flake-parts.url = "github:hercules-ci/flake-parts"; - flake-file.url = "github:vic/flake-file"; - import-tree.url = "github:vic/import-tree"; - }; - - imports = [ - inputs.flake-parts.flakeModules.modules - inputs.flake-file.flakeModules.default - ]; - - flake-file.outputs = '' - inputs: inputs.flake-parts.lib.mkFlake { inherit inputs; } (inputs.import-tree ./modules) - ''; - - systems = [ - "aarch64-linux" - "x86_64-linux" - ]; -} diff --git a/modules/nix/factory.nix b/modules/nix/factory.nix deleted file mode 100644 index 427e055..0000000 --- a/modules/nix/factory.nix +++ /dev/null @@ -1,12 +0,0 @@ -{ - lib, - ... -}: -{ - # factory: storage for factory aspect functions - - options.flake.factory = lib.mkOption { - type = lib.types.attrsOf lib.types.unspecified; - default = { }; - }; -} diff --git a/modules/nix/home-manager.nix b/modules/nix/home-manager.nix deleted file mode 100644 index 819bc34..0000000 --- a/modules/nix/home-manager.nix +++ /dev/null @@ -1,36 +0,0 @@ -{ - inputs, - config, - ... -}: - -let - home-manager-config = - { lib, ... }: - { - home-manager = { - verbose = false; - useUserPackages = true; - useGlobalPkgs = true; - backupFileExtension = "backup"; - backupCommand = "rm"; - overwriteBackup = true; - }; - }; -in - -{ - flake-file.inputs = { - home-manager = { - url = "github:nix-community/home-manager/master"; - inputs.nixpkgs.follows = "nixpkgs"; - }; - }; - - flake.modules.nixos.home-manager = { - imports = [ - inputs.home-manager.nixosModules.home-manager - home-manager-config - ]; - }; -} diff --git a/modules/nix/impermanence.nix b/modules/nix/impermanence.nix deleted file mode 100644 index 31d4a21..0000000 --- a/modules/nix/impermanence.nix +++ /dev/null @@ -1,54 +0,0 @@ -{ inputs, ... }: - -{ - flake-file.inputs = { - impermanence.url = "github:nix-community/impermanence"; - }; - - # convenience function to set persistence settings only, if impermanence module was imported - flake.lib = { - mkIfPersistence = - config: settings: - if config ? home then - (if config.home ? persistence then settings else { }) - else - (if config.environment ? persistence then settings else { }); - }; - - flake.modules.nixos.impermanence = - { config, ... }: - { - imports = [ - inputs.impermanence.nixosModules.impermanence - ]; - - environment.persistence."/persistent" = { - hideMounts = true; - directories = [ - "/var/log" - "/var/lib/nixos" - "/var/lib/systemd/coredump" - "/etc/NetworkManager/system-connections" - ]; - files = [ - "/etc/machine-id" - "/etc/ssh/ssh_host_ed25519_key" - "/etc/ssh/ssh_host_ed25519_key.pub" - "/etc/ssh/ssh_host_rsa_key" - "/etc/ssh/ssh_host_rsa_key.pub" - ]; - }; - - # home-manager.sharedModules = [ - # { - # home.persistence."/persistent" = { - # }; - # } - # ]; - - fileSystems."/persistent".neededForBoot = true; - - programs.fuse.userAllowOther = true; - }; - -} diff --git a/modules/nix/lib.nix b/modules/nix/lib.nix deleted file mode 100644 index b1a3fa3..0000000 --- a/modules/nix/lib.nix +++ /dev/null @@ -1,34 +0,0 @@ -{ - inputs, - lib, - ... -}: -{ - # Helper functions for creating system & home-manager configurations - - options.flake.lib = lib.mkOption { - type = lib.types.attrsOf lib.types.unspecified; - default = { }; - }; - - config.flake.lib = { - mkNixos = system: name: { - ${name} = inputs.nixpkgs.lib.nixosSystem { - modules = [ - inputs.self.modules.nixos.${name} - { nixpkgs.hostPlatform = lib.mkDefault system; } - ]; - }; - }; - - mkHomeManager = system: name: { - ${name} = inputs.home-manager.lib.homeManagerConfiguration { - pkgs = inputs.nixpkgs.legacyPackages.${system}; - modules = [ - inputs.self.modules.homeManager.${name} - { nixpkgs.config.allowUnfree = true; } - ]; - }; - }; - }; -} diff --git a/modules/nix/pkgs-by-name.nix b/modules/nix/pkgs-by-name.nix deleted file mode 100644 index 533c549..0000000 --- a/modules/nix/pkgs-by-name.nix +++ /dev/null @@ -1,42 +0,0 @@ -{ - inputs, - withSystem, - ... -}: -{ - flake-file.inputs = { - pkgs-by-name-for-flake-parts.url = "github:drupol/pkgs-by-name-for-flake-parts"; - packages = { - url = "path:./packages"; - flake = false; - }; - }; - - imports = [ - inputs.pkgs-by-name-for-flake-parts.flakeModule - ]; - - perSystem = - { system, ... }: - { - pkgsDirectory = inputs.packages; - }; - - flake = { - overlays.default = _final: prev: { - local = withSystem prev.stdenv.hostPlatform.system ({ config, ... }: config.packages); - }; - - modules.generic.pkgs-by-name = - { pkgs, ... }: - { - nixpkgs.overlays = [ - inputs.self.overlays.default - ]; - nixpkgs-stable.overlays = [ - inputs.self.overlays.default - ]; - }; - }; - -} diff --git a/packages/base16-schemes.nix b/packages/base16-schemes.nix new file mode 100644 index 0000000..fbb1341 --- /dev/null +++ b/packages/base16-schemes.nix @@ -0,0 +1,35 @@ +{ ... }: + +{ + perSystem = + { pkgs, ... }: + { + packages.base16-schemes = pkgs.stdenv.mkDerivation (finalAttrs: { + pname = "base16-schemes"; + version = "0-unstable-2025-06-04"; + + src = pkgs.fetchFromGitHub { + owner = "tinted-theming"; + repo = "schemes"; + rev = "317a5e10c35825a6c905d912e480dfe8e71c7559"; + hash = "sha256-d4km8W7w2zCUEmPAPUoLk1NlYrGODuVa3P7St+UrqkM="; + }; + + installPhase = '' + runHook preInstall + + mkdir -p $out/share/themes/ + install base16/*.yaml $out/share/themes/ + + runHook postInstall + ''; + + meta = { + description = "All the color schemes for use in base16 packages"; + homepage = "https://github.com/tinted-theming/schemes"; + maintainers = [ pkgs.lib.maintainers.DamienCassou ]; + license = pkgs.lib.licenses.mit; + }; + }); + }; +} diff --git a/packages/fastfetch.nix b/packages/fastfetch.nix new file mode 100644 index 0000000..aa8d616 --- /dev/null +++ b/packages/fastfetch.nix @@ -0,0 +1,84 @@ +{ ... }: + +{ + perSystem = + { pkgs, lib, ... }: + let + fastfetch-logo = pkgs.fetchurl { + url = "https://discourse.nixos.org/uploads/default/original/3X/3/6/36954e6d6aa32c8b00f50ca43f142d898c1ff535.png"; + hash = "sha256-aLHz8jSAFocrn+Pb4vRq0wtkYFJpBpZRevd+VoZC/PQ="; + }; + + fastfetch-config = pkgs.writeText "fastfetch-config.json" ( + builtins.toJSON { + "$schema" = "https://github.com/fastfetch-cli/fastfetch/raw/dev/doc/json_schema.json"; + modules = [ + "title" + "separator" + { + type = "os"; + keyWidth = 9; + } + { + type = "kernel"; + keyWidth = 9; + } + { + type = "uptime"; + keyWidth = 9; + } + { + type = "shell"; + keyWidth = 9; + } + "break" + { + type = "cpu"; + keyWidth = 11; + } + { + type = "memory"; + keyWidth = 11; + } + { + type = "swap"; + keyWidth = 11; + } + { + type = "disk"; + folders = "/"; + keyWidth = 11; + } + { + type = "command"; + key = "Systemd"; + keyWidth = 11; + text = "echo \"$(systemctl list-units --state=failed --no-legend | wc -l) failed units, $(systemctl list-jobs --no-legend | wc -l) queued jobs\""; + } + "break" + { + type = "command"; + key = "Public IP"; + keyWidth = 15; + text = "curl -s -4 ifconfig.me 2>/dev/null || echo 'N/A'"; + } + { + type = "command"; + key = "Tailscale IP"; + keyWidth = 15; + text = "tailscale ip -4 2>/dev/null || echo 'N/A'"; + } + { + type = "command"; + key = "Local IP"; + keyWidth = 15; + text = "ip -4 addr show scope global | grep inet | head -n1 | awk '{print $2}' | cut -d/ -f1"; + } + ]; + } + ); + in + { + packages.fastfetch = pkgs.writeShellScriptBin "fastfetch" ''exec ${lib.getExe pkgs.fastfetch} --config ${fastfetch-config} --logo-type kitty --logo ${fastfetch-logo} --logo-padding-right 1 --logo-width 36 "$@" ''; + }; +} diff --git a/packages/hm-cli.nix b/packages/hm-cli.nix new file mode 100644 index 0000000..59f4b4f --- /dev/null +++ b/packages/hm-cli.nix @@ -0,0 +1,107 @@ +{ ... }: + +{ + perSystem = + { pkgs, ... }: + { + packages.hm-cli = pkgs.writeShellScriptBin "hm" '' + HM="${pkgs.lib.getExe pkgs.home-manager}" + FLAKE_PATH="''${HM_PATH:-$HOME/.config/home-manager}" + FLAKE_OUTPUT="''${HM_USER:-$(whoami)@$(hostname)}" + + show_usage() { + cat < [args] + + Commands: + apply Switch to a new generation + generation list List all generations + generation delete ID... Delete specified generation(s) + generation rollback Rollback to the previous generation + generation switch ID Switch to the specified generation + generation cleanup Delete all but the current generation + + Environment Variables: + HM_PATH Override default flake path (~/.config/home-manager) + Currently set to "''${HM_PATH:-}" + HM_USER Override default user output ("$(whoami)@$(hostname)") + Currently set to "''${HM_USER:-}" + EOF + } + + if [[ $# -eq 0 ]]; then + show_usage + exit 1 + fi + + case "$1" in + apply) + "$HM" switch --flake "$FLAKE_PATH#$FLAKE_OUTPUT" -b bkp + ;; + generation) + if [[ $# -lt 2 ]]; then + echo "Error: generation command requires a subcommand" + show_usage + exit 1 + fi + + case "$2" in + list) + "$HM" generations + ;; + delete) + if [[ $# -lt 3 ]]; then + echo "Error: delete requires at least one generation ID" + exit 1 + fi + shift 2 + "$HM" remove-generations "$@" + ;; + rollback) + PREV_GEN=$("$HM" generations | \ + sed -n 's/^[[:space:]]*id \([0-9]\+\).*/\1/p' | \ + head -n 2 | tail -n 1) + if [[ -z "$PREV_GEN" ]]; then + echo "Error: could not determine previous generation (possibly only one generation exists)" + exit 1 + fi + "$HM" switch --flake "$FLAKE_PATH" --switch-generation "$PREV_GEN" -b bkp + ;; + switch) + if [[ $# -ne 3 ]]; then + echo "Error: switch requires exactly one generation ID" + exit 1 + fi + "$HM" switch --flake "$FLAKE_PATH" --switch-generation "$3" -b bkp + ;; + cleanup) + CURRENT_GEN=$("$HM" generations | sed -n 's/^.*id \([0-9]\+\) .* (current)$/\1/p') + if [[ -z "$CURRENT_GEN" ]]; then + echo "Error: could not determine current generation" + exit 1 + fi + OLD_GENS=$("$HM" generations | sed -n 's/^.*id \([0-9]\+\) .*/\1/p' | grep -v "^$CURRENT_GEN$") + if [[ -z "$OLD_GENS" ]]; then + echo "No old generations to delete" + else + echo "Deleting generations: $(echo $OLD_GENS | tr '\n' ' ')" + echo "$OLD_GENS" | xargs "$HM" remove-generations + echo "Cleanup complete. Current generation $CURRENT_GEN preserved." + fi + ;; + *) + echo "Error: unknown generation subcommand '$2'" + show_usage + exit 1 + ;; + esac + ;; + *) + echo "Error: unknown command '$1'" + show_usage + exit 1 + ;; + esac + ''; + }; +} diff --git a/packages/kwrite.nix b/packages/kwrite.nix index 14ebce1..67ce69e 100644 --- a/packages/kwrite.nix +++ b/packages/kwrite.nix @@ -1,15 +1,21 @@ -{ pkgs }: +{ ... }: -pkgs.symlinkJoin { - name = "kwrite"; - paths = [ pkgs.kdePackages.kate ]; - postBuild = '' - rm -rf $out/bin/kate \ - $out/bin/.kate-wrapped \ - $out/share/applications/org.kde.kate.desktop \ - $out/share/man \ - $out/share/icons/hicolor/*/apps/kate.png \ - $out/share/icons/hicolor/scalable/apps/kate.svg \ - $out/share/appdata/org.kde.kate.appdata.xml - ''; +{ + perSystem = + { pkgs, ... }: + { + packages.kwrite = pkgs.symlinkJoin { + name = "kwrite"; + paths = [ pkgs.kdePackages.kate ]; + postBuild = '' + rm -rf $out/bin/kate \ + $out/bin/.kate-wrapped \ + $out/share/applications/org.kde.kate.desktop \ + $out/share/man \ + $out/share/icons/hicolor/*/apps/kate.png \ + $out/share/icons/hicolor/scalable/apps/kate.svg \ + $out/share/appdata/org.kde.kate.appdata.xml + ''; + }; + }; } diff --git a/packages/niri-auto-centre.nix b/packages/niri-auto-centre.nix new file mode 100644 index 0000000..dd7b04c --- /dev/null +++ b/packages/niri-auto-centre.nix @@ -0,0 +1,32 @@ +{ ... }: + +{ + perSystem = + { pkgs, ... }: + { + packages.niri-auto-centre = pkgs.writeShellApplication { + name = "niri-auto-centre"; + runtimeInputs = [ pkgs.jq ]; + text = '' + while true; do + ACTIVE_WORKSPACE=$(niri msg --json workspaces | jq -r '.[] | select(.is_active == true)') + WORKSPACE_ID=$(echo "$ACTIVE_WORKSPACE" | jq -r '.id') + OUTPUT_NAME=$(echo "$ACTIVE_WORKSPACE" | jq -r '.output') + + MONITOR_WIDTH=$(niri msg --json outputs | jq -r ".\"$OUTPUT_NAME\".logical.width") + + SUMMED_TILE_WIDTH=$(niri msg --json windows | jq --argjson wid "$WORKSPACE_ID" -r ' + [.[] | select(.workspace_id == $wid) | {col: .layout.pos_in_scrolling_layout[0], width: .layout.tile_size[0]}] + | group_by(.col) | map(first.width) | add + ') + + if awk "BEGIN {exit !($SUMMED_TILE_WIDTH < $MONITOR_WIDTH)}"; then + niri msg action center-visible-columns + fi + + sleep 0.1 + done + ''; + }; + }; +} diff --git a/packages/overlays.nix b/packages/overlays.nix new file mode 100644 index 0000000..169a67b --- /dev/null +++ b/packages/overlays.nix @@ -0,0 +1,23 @@ +{ inputs, ... }: + +let + packageDir = builtins.readDir ./.; + + # Filter to .nix files, excluding overlays.nix + isPackageFile = name: name != "overlays.nix" && builtins.match ".*\\.nix$" name != null; + + # Extract package name from filename (e.g., "foo-bar.nix" -> "foo-bar") + toPackageName = filename: builtins.head (builtins.match "(.+)\\.nix$" filename); + + packageNames = map toPackageName (builtins.filter isPackageFile (builtins.attrNames packageDir)); +in +{ + flake.overlays.default = + final: prev: + builtins.listToAttrs ( + map (name: { + inherit name; + value = inputs.self.packages.${final.system}.${name}; + }) packageNames + ); +} diff --git a/packages/toggleaudiosink.nix b/packages/toggleaudiosink.nix index 623346f..22e0d44 100644 --- a/packages/toggleaudiosink.nix +++ b/packages/toggleaudiosink.nix @@ -1,48 +1,52 @@ +{ ... }: + { - pkgs ? import { }, -}: + perSystem = + { pkgs, ... }: + { + packages.toggleaudiosink = pkgs.writeShellScriptBin "toggleaudiosink" '' + #!/usr/bin/env bash -pkgs.writeShellScriptBin "toggleaudiosink" '' - #!/usr/bin/env bash + sound_server="pipewire" - sound_server="pipewire" + # Grab a count of how many audio sinks we have + sink_count=$(${pkgs.pulseaudio}/bin/pactl list sinks | grep -c "Sink #[[:digit:]]") + # Create an array of the actual sink IDs + sinks=() + mapfile -t sinks < <(${pkgs.pulseaudio}/bin/pactl list sinks | grep 'Sink #[[:digit:]]' | sed -n -e 's/.*Sink #\([[:digit:]]\)/\1/p') + # Get the ID of the active sink + active_sink_name=$(${pkgs.pulseaudio}/bin/pactl info | grep 'Default Sink:' | sed -n -e 's/.*Default Sink:[[:space:]]\+\(.*\)/\1/p') + active_sink=$(${pkgs.pulseaudio}/bin/pactl list sinks | grep -B 2 "$active_sink_name" | sed -n -e 's/Sink #\([[:digit:]]\)/\1/p' | head -n 1) - # Grab a count of how many audio sinks we have - sink_count=$(${pkgs.pulseaudio}/bin/pactl list sinks | grep -c "Sink #[[:digit:]]") - # Create an array of the actual sink IDs - sinks=() - mapfile -t sinks < <(${pkgs.pulseaudio}/bin/pactl list sinks | grep 'Sink #[[:digit:]]' | sed -n -e 's/.*Sink #\([[:digit:]]\)/\1/p') - # Get the ID of the active sink - active_sink_name=$(${pkgs.pulseaudio}/bin/pactl info | grep 'Default Sink:' | sed -n -e 's/.*Default Sink:[[:space:]]\+\(.*\)/\1/p') - active_sink=$(${pkgs.pulseaudio}/bin/pactl list sinks | grep -B 2 "$active_sink_name" | sed -n -e 's/Sink #\([[:digit:]]\)/\1/p' | head -n 1) + # Get the ID of the last sink in the array + final_sink=''${sinks[$((sink_count - 1))]} - # Get the ID of the last sink in the array - final_sink=''${sinks[$((sink_count - 1))]} + # Find the index of the active sink + for index in "''${!sinks[@]}"; do + if [[ "''${sinks[$index]}" == "$active_sink" ]]; then + active_sink_index=$index + fi + done - # Find the index of the active sink - for index in "''${!sinks[@]}"; do - if [[ "''${sinks[$index]}" == "$active_sink" ]]; then - active_sink_index=$index - fi - done + # Default to the first sink in the list + next_sink=''${sinks[0]} + next_sink_index=0 - # Default to the first sink in the list - next_sink=''${sinks[0]} - next_sink_index=0 + # If we're not at the end of the list, move up the list + if [[ $active_sink -ne $final_sink ]]; then + next_sink_index=$((active_sink_index + 1)) + next_sink=''${sinks[$next_sink_index]} + fi - # If we're not at the end of the list, move up the list - if [[ $active_sink -ne $final_sink ]]; then - next_sink_index=$((active_sink_index + 1)) - next_sink=''${sinks[$next_sink_index]} - fi + # Change the default sink + # Get the name of the next sink + next_sink_name=$(${pkgs.pulseaudio}/bin/pactl list sinks | grep -C 2 "Sink #$next_sink" | sed -n -e 's/.*Name:[[:space:]]\+\(.*\)/\1/p' | head -n 1) + ${pkgs.pulseaudio}/bin/pactl set-default-sink "$next_sink_name" - # Change the default sink - # Get the name of the next sink - next_sink_name=$(${pkgs.pulseaudio}/bin/pactl list sinks | grep -C 2 "Sink #$next_sink" | sed -n -e 's/.*Name:[[:space:]]\+\(.*\)/\1/p' | head -n 1) - ${pkgs.pulseaudio}/bin/pactl set-default-sink "$next_sink_name" - - # Move all inputs to the new sink - for app in $(${pkgs.pulseaudio}/bin/pactl list sink-inputs | sed -n -e 's/.*Sink Input #\([[:digit:]]\)/\1/p'); do - ${pkgs.pulseaudio}/bin/pactl "move-sink-input $app $next_sink" - done -'' + # Move all inputs to the new sink + for app in $(${pkgs.pulseaudio}/bin/pactl list sink-inputs | sed -n -e 's/.*Sink Input #\([[:digit:]]\)/\1/p'); do + ${pkgs.pulseaudio}/bin/pactl "move-sink-input $app $next_sink" + done + ''; + }; +} diff --git a/readme.md b/readme.md new file mode 100644 index 0000000..e36ccec --- /dev/null +++ b/readme.md @@ -0,0 +1,73 @@ +# NixOS Flake Configuration + +Modular NixOS configuration using flake-parts with the [dendritic](https://github.com/gytis-ivaskevicius/dendritic) pattern. + +## Structure + +``` +. +├── aspects/ # Reusable NixOS/home-manager modules (dendritic) +│ ├── base/ # Base system configuration +│ ├── hosts/ # Host-specific configurations +│ │ ├── _alexandria/ +│ │ ├── _io/ +│ │ ├── _rotterdam/ +│ │ └── _trantor/ +│ ├── systems/ # System type modules (desktop, server, cli, gaming) +│ └── users/ # User account configurations +├── data/ # Shared host/service definitions +├── packages/ # Custom packages and overlays +├── shells/ # Shell configurations +└── terranix/ # Terraform configurations for cloud resources +``` + +## Hosts + +| Host | Architecture | Type | Description | +|------|--------------|------|-------------| +| trantor | aarch64-linux | server | ARM server running Forgejo | +| alexandria | x86_64-linux | server | x86 server (Kanidm, Vaultwarden, Nextcloud, Jellyfin) | +| rotterdam | x86_64-linux | desktop | Main workstation setup for gaming | +| io | x86_64-linux | desktop | Workstation | + +## Services + +- **git.baduhai.dev** (Forgejo) - Publicly accessible on trantor + +Other services (LAN/Tailscale only): Vaultwarden, Nextcloud, Jellyfin + +## Features + +- **Ephemeral root**: Automatic btrfs subvolume rollover with impermanence +- **Secrets**: Managed via agenix with age encryption +- **Disk management**: disko for declarative disk partitioning +- **Modular architecture**: Each aspect is a separate module imported via import-tree +- **Dendritic pattern**: Aspects are imported as a unified flake module + +## Building + +```bash +# Build specific host +nix build .#nixosConfigurations.trantor.config.system.build.toplevel + +# Rebuild host (if using nixos-cli on the host) +sudo nixos apply +``` + +## Terranix + +Terraform configurations for cloud infrastructure managed via terranix: + +- baduhai.dev DNS on CloudFlare +- VPS provisioning on OCI +- Tailscale subnet routers + +## Key Dependencies + +- nixpkgs (nixos-unstable for workstations, nixos for servers) +- home-manager +- agenix +- disko +- impermanence +- nix-flatpak +- nixos-cli diff --git a/shells/default.nix b/shells/default.nix new file mode 100644 index 0000000..d9eb50b --- /dev/null +++ b/shells/default.nix @@ -0,0 +1,15 @@ +{ inputs, ... }: + +{ + perSystem = + { pkgs, system, ... }: + { + devShells.default = pkgs.mkShell { + packages = with pkgs; [ + inputs.agenix.packages.${stdenv.hostPlatform.system}.default + nil + nixfmt + ]; + }; + }; +} diff --git a/terranix/baduhai.dev.nix b/terranix/baduhai.dev.nix new file mode 100644 index 0000000..cea9f22 --- /dev/null +++ b/terranix/baduhai.dev.nix @@ -0,0 +1,113 @@ +# Required environment variables: +# CLOUDFLARE_API_TOKEN - API token with "Edit zone DNS" permissions +# AWS_ACCESS_KEY_ID - Cloudflare R2 access key for state storage +# AWS_SECRET_ACCESS_KEY - Cloudflare R2 secret key for state storage + +{ ... }: + +{ + perSystem = + { pkgs, ... }: + { + terranix.terranixConfigurations.cloudflare-baduhaidev = { + terraformWrapper.package = pkgs.opentofu; + modules = [ + ( + { config, lib, ... }: + + let + sharedData = import ../data/services.nix; + # Enrich services with host IPs + services = map ( + svc: + let + hostInfo = sharedData.hosts.${svc.host} or { }; + in + svc + // { + lanIP = hostInfo.lanIP or null; + tailscaleIP = hostInfo.tailscaleIP or null; + } + ) sharedData.services; + + # Helper to extract subdomain from full domain (e.g., "git.baduhai.dev" -> "git") + getSubdomain = domain: lib.head (lib.splitString "." domain); + + # Generate DNS records for services + # Public services point to trantor's public IP + # Private services point to their tailscale IP + mkServiceRecords = lib.listToAttrs ( + lib.imap0 ( + i: svc: + let + subdomain = getSubdomain svc.domain; + targetIP = + if svc.public or false then + config.data.terraform_remote_state.trantor "outputs.instance_public_ip" + else + svc.tailscaleIP; + in + { + name = "service_${toString i}"; + value = { + zone_id = config.variable.zone_id.default; + name = subdomain; + type = "A"; + content = targetIP; + proxied = false; + ttl = 3600; + }; + } + ) services + ); + in + + { + terraform.required_providers.cloudflare = { + source = "cloudflare/cloudflare"; + version = "~> 5.0"; + }; + + terraform.backend.s3 = { + bucket = "terraform-state"; + key = "cloudflare/baduhai.dev.tfstate"; + region = "auto"; + endpoint = "https://fcdf920bde00c3d013ee541f984da70e.r2.cloudflarestorage.com"; + skip_credentials_validation = true; + skip_metadata_api_check = true; + skip_region_validation = true; + skip_requesting_account_id = true; + use_path_style = true; + }; + + variable = { + zone_id = { + default = "c63a8332fdddc4a8e5612ddc54557044"; + type = "string"; + }; + }; + + data = { + terraform_remote_state.trantor = { + backend = "s3"; + config = { + bucket = "terraform-state"; + key = "oci/trantor.tfstate"; + region = "auto"; + endpoint = "https://fcdf920bde00c3d013ee541f984da70e.r2.cloudflarestorage.com"; + skip_credentials_validation = true; + skip_metadata_api_check = true; + skip_region_validation = true; + skip_requesting_account_id = true; + use_path_style = true; + }; + }; + }; + + resource.cloudflare_dns_record = mkServiceRecords; + } + ) + ]; + }; + }; +} diff --git a/terranix/kernelpanic.space.nix b/terranix/kernelpanic.space.nix new file mode 100644 index 0000000..91b615e --- /dev/null +++ b/terranix/kernelpanic.space.nix @@ -0,0 +1,20 @@ +# Cloudflare kernelpanic.space configuration placeholder +{ ... }: + +{ + perSystem = + { pkgs, ... }: + { + terranix.terranixConfigurations.cloudflare-kernelpanicspace = { + terraformWrapper.package = pkgs.opentofu; + modules = [ + ( + { config, ... }: + { + # Terraform config goes here + } + ) + ]; + }; + }; +} diff --git a/terranix/tailnet.nix b/terranix/tailnet.nix new file mode 100644 index 0000000..4e01ab9 --- /dev/null +++ b/terranix/tailnet.nix @@ -0,0 +1,57 @@ +# Required environment variables: +# TAILSCALE_API_KEY - Tailscale API key with appropriate permissions +# TAILSCALE_TAILNET - Your tailnet name (e.g., "user@example.com" or "example.org.github") +# AWS_ACCESS_KEY_ID - Cloudflare R2 access key for state storage +# AWS_SECRET_ACCESS_KEY - Cloudflare R2 secret key for state storage + +{ ... }: + +{ + perSystem = + { pkgs, ... }: + { + terranix.terranixConfigurations.tailscale-tailnet = { + terraformWrapper.package = pkgs.opentofu; + modules = [ + ( + { config, ... }: + { + terraform.required_providers.tailscale = { + source = "tailscale/tailscale"; + version = "~> 0.17"; + }; + + terraform.backend.s3 = { + bucket = "terraform-state"; + key = "tailscale/tailnet.tfstate"; + region = "auto"; + endpoint = "https://fcdf920bde00c3d013ee541f984da70e.r2.cloudflarestorage.com"; + skip_credentials_validation = true; + skip_metadata_api_check = true; + skip_region_validation = true; + skip_requesting_account_id = true; + use_path_style = true; + }; + + variable = { + trantor_tailscale_ip = { + default = "100.108.5.90"; + type = "string"; + }; + }; + + resource = { + tailscale_dns_nameservers.global = { + nameservers = [ + config.variable.trantor_tailscale_ip.default + "1.1.1.1" + "1.0.0.1" + ]; + }; + }; + } + ) + ]; + }; + }; +} diff --git a/terranix/terminus.nix b/terranix/terminus.nix new file mode 100644 index 0000000..d7689f9 --- /dev/null +++ b/terranix/terminus.nix @@ -0,0 +1,20 @@ +# OCI Terminus configuration placeholder +{ ... }: + +{ + perSystem = + { pkgs, ... }: + { + terranix.terranixConfigurations.oci-terminus = { + terraformWrapper.package = pkgs.opentofu; + modules = [ + ( + { config, ... }: + { + # Terraform config goes here + } + ) + ]; + }; + }; +} diff --git a/terranix/trantor.nix b/terranix/trantor.nix new file mode 100644 index 0000000..5f19e22 --- /dev/null +++ b/terranix/trantor.nix @@ -0,0 +1,272 @@ +# Required environment variables: +# instead of OCI variables, ~/.oci/config may also be used +# OCI_TENANCY_OCID - Oracle tenancy OCID (or use TF_VAR_* to override variables) +# OCI_USER_OCID - Oracle user OCID +# OCI_FINGERPRINT - API key fingerprint +# OCI_PRIVATE_KEY_PATH - Path to OCI API private key +# AWS variables are required +# AWS_ACCESS_KEY_ID - Cloudflare R2 access key for state storage +# AWS_SECRET_ACCESS_KEY - Cloudflare R2 secret key for state storage + +{ ... }: + +{ + perSystem = + { pkgs, ... }: + { + terranix.terranixConfigurations.oci-trantor = { + terraformWrapper.package = pkgs.opentofu; + modules = [ + ( + { config, ... }: + { + terraform.required_providers.oci = { + source = "oracle/oci"; + version = "~> 7.0"; + }; + + provider.oci.region = "sa-saopaulo-1"; + + terraform.backend.s3 = { + bucket = "terraform-state"; + key = "oci/trantor.tfstate"; + region = "auto"; + endpoint = "https://fcdf920bde00c3d013ee541f984da70e.r2.cloudflarestorage.com"; + skip_credentials_validation = true; + skip_metadata_api_check = true; + skip_region_validation = true; + skip_requesting_account_id = true; + use_path_style = true; + }; + + variable = { + tenancy_ocid = { + default = "ocid1.tenancy.oc1..aaaaaaaap3vfdz4piygqza6e6zqunbcuso43ddqfo3ydmpmnomidyghh7rvq"; + type = "string"; + }; + + compartment_name = { + default = "trantor"; + type = "string"; + }; + + vcn_cidr = { + default = "10.0.0.0/24"; + type = "string"; + }; + + instance_name = { + default = "trantor"; + type = "string"; + }; + + ssh_public_keys = { + default = [ + "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAICQPkAyy+Du9Omc2WtnUF2TV8jFAF4H6mJi2D4IZ1nzg user@himalia" + "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIO3Y0PVpGfJHonqDS7qoCFhqzUvqGq9I9sax+F9e/5cs user@io" + "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIA1v3+q3EaruiiStWjubEJWvtejam/r41uoOpCdwJtLL user@rotterdam" + ]; + type = "list(string)"; + }; + }; + + data = { + oci_identity_availability_domains.ads = { + compartment_id = config.variable.tenancy_ocid.default; + }; + + oci_core_images.ubuntu_arm = { + compartment_id = config.variable.tenancy_ocid.default; + operating_system = "Canonical Ubuntu"; + operating_system_version = "24.04"; + shape = "VM.Standard.A1.Flex"; + sort_by = "TIMECREATED"; + sort_order = "DESC"; + }; + }; + + resource = { + oci_identity_compartment.trantor = { + compartment_id = config.variable.tenancy_ocid.default; + description = "trantor infrastructure compartment"; + name = config.variable.compartment_name.default; + }; + + oci_core_vcn.vcn = { + compartment_id = config.resource.oci_identity_compartment.trantor "id"; + cidr_blocks = [ config.variable.vcn_cidr.default ]; + display_name = "trantor-vcn"; + dns_label = "trantor"; + }; + + oci_core_internet_gateway.ig = { + compartment_id = config.resource.oci_identity_compartment.trantor "id"; + vcn_id = config.resource.oci_core_vcn.vcn "id"; + display_name = "trantor-ig"; + enabled = true; + }; + + oci_core_route_table.rt = { + compartment_id = config.resource.oci_identity_compartment.trantor "id"; + vcn_id = config.resource.oci_core_vcn.vcn "id"; + display_name = "trantor-rt"; + + route_rules = [ + { + network_entity_id = config.resource.oci_core_internet_gateway.ig "id"; + destination = "0.0.0.0/0"; + destination_type = "CIDR_BLOCK"; + } + ]; + }; + + oci_core_security_list.sl = { + compartment_id = config.resource.oci_identity_compartment.trantor "id"; + vcn_id = config.resource.oci_core_vcn.vcn "id"; + display_name = "trantor-sl"; + + egress_security_rules = [ + { + destination = "0.0.0.0/0"; + protocol = "all"; + stateless = false; + } + ]; + + ingress_security_rules = [ + { + protocol = "6"; # TCP + source = "0.0.0.0/0"; + stateless = false; + tcp_options = { + min = 22; + max = 22; + }; + } + { + protocol = "6"; # TCP + source = "0.0.0.0/0"; + stateless = false; + tcp_options = { + min = 80; + max = 80; + }; + } + { + protocol = "6"; # TCP + source = "0.0.0.0/0"; + stateless = false; + tcp_options = { + min = 443; + max = 443; + }; + } + { + protocol = "6"; # TCP + source = "0.0.0.0/0"; + stateless = false; + tcp_options = { + min = 25565; + max = 25565; + }; + } + { + protocol = "6"; # TCP + source = "0.0.0.0/0"; + stateless = false; + tcp_options = { + min = 19132; + max = 19133; + }; + } + { + protocol = "17"; # UDP + source = "0.0.0.0/0"; + stateless = false; + udp_options = { + min = 19132; + max = 19133; + }; + } + ]; + }; + + oci_core_subnet.subnet = { + compartment_id = config.resource.oci_identity_compartment.trantor "id"; + vcn_id = config.resource.oci_core_vcn.vcn "id"; + cidr_block = config.variable.vcn_cidr.default; + display_name = "trantor-subnet"; + dns_label = "subnet"; + route_table_id = config.resource.oci_core_route_table.rt "id"; + security_list_ids = [ (config.resource.oci_core_security_list.sl "id") ]; + prohibit_public_ip_on_vnic = false; + }; + + oci_core_instance.trantor = { + availability_domain = config.data.oci_identity_availability_domains.ads "availability_domains[0].name"; + compartment_id = config.resource.oci_identity_compartment.trantor "id"; + display_name = config.variable.instance_name.default; + shape = "VM.Standard.A1.Flex"; + + shape_config = { + ocpus = 2; + memory_in_gbs = 12; + }; + + source_details = { + source_type = "image"; + source_id = config.data.oci_core_images.ubuntu_arm "images[0].id"; + boot_volume_size_in_gbs = 100; + }; + + create_vnic_details = { + subnet_id = config.resource.oci_core_subnet.subnet "id"; + display_name = "trantor-vnic"; + assign_public_ip = true; + hostname_label = config.variable.instance_name.default; + }; + + metadata = { + ssh_authorized_keys = builtins.concatStringsSep "\n" config.variable.ssh_public_keys.default; + }; + + preserve_boot_volume = false; + }; + + oci_budget_budget.trantor_budget = { + compartment_id = config.variable.tenancy_ocid.default; + targets = [ (config.resource.oci_identity_compartment.trantor "id") ]; + amount = 1; + reset_period = "MONTHLY"; + display_name = "trantor-budget"; + description = "Monthly budget for trantor compartment"; + target_type = "COMPARTMENT"; + }; + + oci_budget_alert_rule.daily_spend_alert = { + budget_id = config.resource.oci_budget_budget.trantor_budget "id"; + type = "ACTUAL"; + threshold = 5; + threshold_type = "PERCENTAGE"; + display_name = "daily-spend-alert"; + recipients = "baduhai@proton.me"; + description = "Alert when daily spending exceeds $0.05"; + message = "Daily spending has exceeded $0.05 in the trantor compartment"; + }; + }; + + output = { + compartment_id = { + value = config.resource.oci_identity_compartment.trantor "id"; + }; + + instance_public_ip = { + value = config.resource.oci_core_instance.trantor "public_ip"; + }; + }; + } + ) + ]; + }; + }; +}