diff --git a/desktop/x11.nix b/desktop/x11.nix index 252b536..e571bc5 100644 --- a/desktop/x11.nix +++ b/desktop/x11.nix @@ -1,8 +1,16 @@ -{ config, pkgs, ... }: +{ + config, + pkgs, + lib, + ... +}: { # Enable the X11 windowing system. services.xserver.enable = true; services.xserver.xkb.layout = "gb"; - services.xserver.xkb.options = "eurosign:e"; + services.xserver.xkb.options = lib.concatStringsSep "," [ + "eurosign:e" + "compose:ralt" + ]; } diff --git a/flake.lock b/flake.lock index 12682b8..b85ef07 100644 --- a/flake.lock +++ b/flake.lock @@ -72,11 +72,11 @@ ] }, "locked": { - "lastModified": 1727447169, - "narHash": "sha256-3KyjMPUKHkiWhwR91J1YchF6zb6gvckCAY1jOE+ne0U=", + "lastModified": 1749105467, + "narHash": "sha256-hXh76y/wDl15almBcqvjryB50B0BaiXJKk20f314RoE=", "owner": "serokell", "repo": "deploy-rs", - "rev": "aa07eb05537d4cd025e2310397a6adcedfe72c76", + "rev": "6bc76b872374845ba9d645a2f012b764fecd765f", "type": "github" }, "original": { @@ -129,11 +129,11 @@ }, "locked": { "dir": "pkgs/firefox-addons", - "lastModified": 1749009805, - "narHash": "sha256-eRv4m89aPJvIAX9mZQcJM+l3sYG+OJvcLsiHvAvXalg=", + "lastModified": 1749143092, + "narHash": "sha256-IrVT37SUU8/B3X53rwEzDrx3djGLIfa8tmsyqVJxpR4=", "owner": "rycee", "repo": "nur-expressions", - "rev": "622c38d004cdded682d9a5ab7323181dc6efb0c1", + "rev": "d62d10f250ca6a37cbbe05a35a0e1e7ae3b4b5c2", "type": "gitlab" }, "original": { @@ -146,11 +146,11 @@ "flake-compat": { "flake": false, "locked": { - "lastModified": 1696426674, - "narHash": "sha256-kvjfFW7WAETZlt09AgDn1MrtKzP7t90Vf7vypd3OL1U=", + "lastModified": 1733328505, + "narHash": "sha256-NeCCThCEP3eCl2l/+27kNNK7QrwZB1IJCrXfrbv5oqU=", "owner": "edolstra", "repo": "flake-compat", - "rev": "0f9255e01c2351cc7d116c072cb317785dd33b33", + "rev": "ff81ac966bb2cae68946d5ed5fc4994f96d0ffec", "type": "github" }, "original": { @@ -299,11 +299,11 @@ ] }, "locked": { - "lastModified": 1748665073, - "narHash": "sha256-RMhjnPKWtCoIIHiuR9QKD7xfsKb3agxzMfJY8V9MOew=", + "lastModified": 1749154018, + "narHash": "sha256-gjN3j7joRvT3a8Zgcylnd4NFsnXeDBumqiu4HmY1RIg=", "owner": "nix-community", "repo": "home-manager", - "rev": "282e1e029cb6ab4811114fc85110613d72771dea", + "rev": "7aae0ee71a17b19708b93b3ed448a1a0952bf111", "type": "github" }, "original": { @@ -353,11 +353,11 @@ }, "nixos-hardware": { "locked": { - "lastModified": 1748942041, - "narHash": "sha256-HEu2gTct7nY0tAPRgBtqYepallryBKR1U8B4v2zEEqA=", + "lastModified": 1749195551, + "narHash": "sha256-W5GKQHgunda/OP9sbKENBZhMBDNu2QahoIPwnsF6CeM=", "owner": "NixOS", "repo": "nixos-hardware", - "rev": "fc7c4714125cfaa19b048e8aaf86b9c53e04d853", + "rev": "4602f7e1d3f197b3cb540d5accf5669121629628", "type": "github" }, "original": { @@ -368,11 +368,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1749024892, - "narHash": "sha256-OGcDEz60TXQC+gVz5sdtgGJdKVYr6rwdzQKuZAJQpCA=", + "lastModified": 1749086602, + "narHash": "sha256-DJcgJMekoxVesl9kKjfLPix2Nbr42i7cpEHJiTnBUwU=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "8f1b52b04f2cb6e5ead50bd28d76528a2f0380ef", + "rev": "4792576cb003c994bd7cc1edada3129def20b27d", "type": "github" }, "original": { @@ -423,11 +423,11 @@ "systems": "systems_3" }, "locked": { - "lastModified": 1749025503, - "narHash": "sha256-Me3mk/wLz4msOQAASCaf2+mQizje1Q37rgNfExJse6M=", + "lastModified": 1749198233, + "narHash": "sha256-5YEDpGF46A5pnHX52ALqmFMlAB1orI0SnZhI6LQiw9w=", "owner": "astro", "repo": "nix-openwrt-imagebuilder", - "rev": "1b157ee2f34fc67f365a62c5a4fca63ba86040c6", + "rev": "7eb902386112129be892e06cd5a51ffdfeb2517e", "type": "github" }, "original": { diff --git a/flake.nix b/flake.nix index 53ca564..cf2c29e 100644 --- a/flake.nix +++ b/flake.nix @@ -104,6 +104,7 @@ rec { flakeDefaults = import ./modules/flakeDefaults.nix; systemdNotify = import ./modules/systemdNotify.nix; inadyn = import ./modules/inadyn.nix; + nginx-authelia = import ./modules/nginx-authelia.nix; }; }; perSystem = diff --git a/hardware/home-pc.nix b/hardware/home-pc.nix deleted file mode 100644 index d8aab7a..0000000 --- a/hardware/home-pc.nix +++ /dev/null @@ -1,63 +0,0 @@ -# Do not modify this file! It was generated by ‘nixos-generate-config’ -# and may be overwritten by future invocations. Please make changes -# to /etc/nixos/configuration.nix instead. -{ - config, - lib, - pkgs, - modulesPath, - ... -}: - -{ - boot.initrd.availableKernelModules = [ - "nvme" - "ahci" - "xhci_pci" - "usb_storage" - "usbhid" - "sd_mod" - ]; - boot.initrd.kernelModules = [ ]; - boot.kernelModules = [ "kvm-amd" ]; - boot.extraModulePackages = [ ]; - - fileSystems."/" = { - device = "/dev/disk/by-uuid/5830e9b3-260b-451c-bfee-2028c64c6199"; - fsType = "btrfs"; - options = [ - "subvol=@" - "compress-force=zstd:1" - "noatime" - ]; - }; - - boot.initrd.luks.devices."enc".device = "/dev/disk/by-uuid/1dd848b6-cd7f-4959-8500-a03ffdaeae66"; - - fileSystems."/home" = { - device = "/dev/disk/by-uuid/5830e9b3-260b-451c-bfee-2028c64c6199"; - fsType = "btrfs"; - options = [ - "subvol=@home" - "compress-force=zstd:1" - "noatime" - ]; - }; - - fileSystems."/.snapshots" = { - device = "/dev/disk/by-uuid/5830e9b3-260b-451c-bfee-2028c64c6199"; - fsType = "btrfs"; - options = [ - "subvol=@snapshots" - "compress-force=zstd:1" - "noatime" - ]; - }; - - fileSystems."/boot" = { - device = "/dev/disk/by-uuid/17B2-42C2"; - fsType = "vfat"; - }; - - hardware.cpu.amd.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware; -} diff --git a/hardware/lattepanda.nix b/hardware/lattepanda.nix deleted file mode 100644 index 0239167..0000000 --- a/hardware/lattepanda.nix +++ /dev/null @@ -1,58 +0,0 @@ -{ config, lib, ... }: - -{ - boot.initrd.availableKernelModules = [ - "xhci_pci" - "ahci" - "nvme" - "usbhid" - "usb_storage" - "sd_mod" - "sdhci_pci" - "rtsx_usb_sdmmc" - ]; - boot.initrd.kernelModules = [ ]; - boot.kernelModules = [ "kvm-intel" ]; - boot.kernelParams = [ "i915.enable_guc=3" ]; - boot.extraModulePackages = [ ]; - - fileSystems."/" = { - device = "/dev/disk/by-uuid/70f03d67-e248-42f6-a204-c02e4f180531"; - fsType = "btrfs"; - options = [ - "subvol=@" - "compress-force=zstd:1" - "noatime" - ]; - }; - - boot.initrd.luks.devices."enc".device = "/dev/disk/by-uuid/d3b12d0e-7e8e-4130-9a8f-680abcdc9682"; - - fileSystems."/home" = { - device = "/dev/disk/by-uuid/70f03d67-e248-42f6-a204-c02e4f180531"; - fsType = "btrfs"; - options = [ - "subvol=@home" - "compress-force=zstd:1" - "noatime" - ]; - }; - - fileSystems."/.snapshots" = { - device = "/dev/disk/by-uuid/70f03d67-e248-42f6-a204-c02e4f180531"; - fsType = "btrfs"; - options = [ - "subvol=@snapshots" - "compress-force=zstd:1" - "noatime" - ]; - }; - - fileSystems."/boot" = { - device = "/dev/disk/by-uuid/95FC-D4E5"; - fsType = "vfat"; - }; - - powerManagement.cpuFreqGovernor = lib.mkDefault "powersave"; - hardware.cpu.intel.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware; -} diff --git a/home/base.nix b/home/base.nix new file mode 100644 index 0000000..3a1b576 --- /dev/null +++ b/home/base.nix @@ -0,0 +1,5 @@ +_: + +{ + imports = [ ./nixpkgs.nix ]; +} diff --git a/home/desktop/cosmic.nix b/home/desktop/cosmic.nix new file mode 100644 index 0000000..3337b21 --- /dev/null +++ b/home/desktop/cosmic.nix @@ -0,0 +1,32 @@ +_: + +{ + imports = [ ../modules/cosmic ]; + + programs.cosmic = { + enable = true; + settings = { + "com.system76.CosmicTk".v1 = { + icon_theme = "Cosmic"; + }; + "com.system76.CosmicFiles".v1 = { + tab.show_hidden = true; + favorites = [ + "Home" + "Documents" + "Downloads" + "Music" + "Pictures" + "Videos" + ''Path("/home/felschr/dev")'' + ''Path("/home/felschr/dev/work")'' + ''Path("/home/felschr/dev/mscs")'' + ''Path("/home/felschr/Documents/CU Boulder MSCS")'' + ]; + }; + "com.system76.CosmicAppletAudio".v1 = { + show_media_controls_in_top_panel = true; + }; + }; + }; +} diff --git a/home/desktop/default.nix b/home/desktop/default.nix index b5d0adb..ee28be4 100644 --- a/home/desktop/default.nix +++ b/home/desktop/default.nix @@ -4,6 +4,7 @@ imports = [ ./gtk.nix ./gnome.nix + ./cosmic.nix ./mimeapps.nix ]; } diff --git a/home/felschr-server.nix b/home/felschr-server.nix index 82c0de5..71414f5 100644 --- a/home/felschr-server.nix +++ b/home/felschr-server.nix @@ -7,6 +7,7 @@ { imports = [ + ./base.nix ./shell ./editors/lsp.nix ./editors/helix diff --git a/home/felschr-work.nix b/home/felschr-work.nix index 73e4003..ce4cb8f 100644 --- a/home/felschr-work.nix +++ b/home/felschr-work.nix @@ -3,6 +3,7 @@ with pkgs; { imports = [ + ./base.nix ./shell ./tailscale.nix ./editors diff --git a/home/felschr.nix b/home/felschr.nix index b0e32b0..95c4076 100644 --- a/home/felschr.nix +++ b/home/felschr.nix @@ -2,6 +2,7 @@ { imports = [ + ./base.nix ./shell ./tailscale.nix ./editors diff --git a/home/flake-module.nix b/home/flake-module.nix index f6b54ac..2849f00 100644 --- a/home/flake-module.nix +++ b/home/flake-module.nix @@ -16,15 +16,12 @@ let pkgs = self.pkgsFor system; extraSpecialArgs = { inherit inputs; }; - modules = - (with self.homeModules; [ nixpkgs ]) - ++ [ - { - home.username = user; - home.homeDirectory = "/home/${user}"; - } - ] - ++ modules; + modules = [ + { + home.username = user; + home.homeDirectory = "/home/${user}"; + } + ] ++ modules; }; in { @@ -32,11 +29,11 @@ in flake = { homeModules = { - nixpkgs = import ./modules/nixpkgs.nix; git = import ./modules/git.nix; firefox = import ./modules/firefox/firefox.nix; tor-browser = import ./modules/firefox/tor-browser.nix; mullvad-browser = import ./modules/firefox/mullvad-browser.nix; + cosmic = import ./modules/cosmic; # users felschr = import ./felschr.nix; diff --git a/home/modules/cosmic/default.nix b/home/modules/cosmic/default.nix new file mode 100644 index 0000000..7a5cc08 --- /dev/null +++ b/home/modules/cosmic/default.nix @@ -0,0 +1,53 @@ +{ config, lib, ... }: + +# Based on: +# https://github.com/tristanbeedell/home-manager/tree/efa4d272f6c2b14d4a3b67b0b1e4b38ae46e5588/modules/programs/cosmic + +let + cfg = config.programs.cosmic; + + ron = import ./ron.nix { inherit lib; }; +in +{ + imports = [ ./settings.nix ]; + + options.programs.cosmic = { + enable = lib.mkEnableOption "COSMIC Desktop"; + settings = lib.mkOption { + default = { }; + type = lib.types.submodule { + freeformType = lib.types.submodule { + freeformType = lib.types.attrsOf lib.types.anything; + }; + }; + description = '' + An attrset of explicit settings for COSMIC apps, using their full config path. + ''; + example = lib.literalExpression '' + { + "com.system76.CosmicPanel.Dock".v1 = { + opacity = 0.8; + }; + }; + ''; + }; + }; + + config = lib.mkIf cfg.enable { + xdg.configFile = lib.concatMapAttrs ( + component: + lib.concatMapAttrs ( + version: + lib.concatMapAttrs ( + option: value: + lib.optionalAttrs (value != null) { + "cosmic/${component}/${version}/${option}" = { + enable = true; + text = ron.serialise value; + }; + } + ) + ) + ) cfg.settings; + }; +} diff --git a/home/modules/cosmic/ron.nix b/home/modules/cosmic/ron.nix new file mode 100644 index 0000000..3727ea9 --- /dev/null +++ b/home/modules/cosmic/ron.nix @@ -0,0 +1,129 @@ +{ lib }: +let + inherit (lib) + filterAttrs + concatStrings + concatStringsSep + mapAttrsToList + concatLists + foldlAttrs + boolToString + ; + inherit (builtins) typeOf toString stringLength; + + # list -> array + array = a: "[${concatStringsSep "," (map serialise a)}]"; + + # attrset -> hashmap + _assoc = a: mapAttrsToList (name: val: "${name}: ${val},") a; + assoc = a: '' + { + ${concatStringsSep "\n " (concatLists (map _assoc a))} + } + ''; + + stringArray = a: array (map toQuotedString a); + + tuple = a: "(${concatStringsSep "," (map serialise a)})"; + enum = + s: + if isNull s.value then + s.name + else + concatStrings [ + s.name + "(" + (serialise s.value) + ")" + ]; + + option = + value: + if isNull value then + "None" + else + enum { + name = "Some"; + inherit value; + }; + + # attrset -> struct + _struct_kv = + k: v: + if v == null then + "" + else + (concatStringsSep ": " [ + k + (serialise v) + ]); + _struct_concat = + s: + foldlAttrs ( + acc: k: v: + if stringLength acc > 0 then + concatStringsSep ", " [ + acc + (_struct_kv k v) + ] + else + _struct_kv k v + ) "" s; + _struct_filt = s: _struct_concat (filterAttrs (k: v: v != null) s); + struct = s: "(${_struct_filt s})"; + + toQuotedString = s: ''"${toString s}"''; + + # this is an enum, but use string interp to make sure it's put in the nix store + path = p: ''Path("${p}")''; + + # attrset for best-effort serialisation of nix types + # currently, no way to differentiate between enums and structs + serialisers = { + int = toString; + float = toString; + bool = boolToString; + # can't assume quoted string, sometimes it's a Rust enum + string = toString; + path = path; + null = _: "None"; + set = struct; + list = array; + }; + + serialise = v: serialisers.${typeOf v} v; + +in +{ + inherit + array + assoc + tuple + stringArray + serialise + option + path + struct + toQuotedString + enum + ; + + # some handy wrapper types, to reduce transformation effort in modules producing Ron + types = { + # string type, but implicitly wraps in quote marks for usage in Ron + str = (lib.types.coercedTo lib.types.str toQuotedString lib.types.str) // { + description = "string"; + }; + + # takes a (non submodule) type, and implicitly wraps in Rust Option<> type + option = + type: + let + wantedType = lib.types.nullOr (type); + in + (lib.types.coercedTo (wantedType) (option) lib.types.str) + // { + description = wantedType.description; + }; + }; +} diff --git a/home/modules/cosmic/settings.nix b/home/modules/cosmic/settings.nix new file mode 100644 index 0000000..8a8a101 --- /dev/null +++ b/home/modules/cosmic/settings.nix @@ -0,0 +1,108 @@ +{ lib, ... }: + +# Known definitions for settings options + +let + inherit (lib) types; + ron = import ./ron.nix { inherit lib; }; + cosmic = { + types = import ./types.nix { inherit lib ron; }; + }; +in +{ + options.programs.cosmic.settings = { + # https://github.com/pop-os/libcosmic/blob/1fce5df160f595d1b1e5a8e2bb2a24775419f82d/src/config/mod.rs#L85 + "com.system76.CosmicTk".v1 = { + apply_theme_global = lib.mkOption { + type = types.nullOr types.bool; + default = null; + description = "Apply the theme to other toolkits."; + }; + show_minimize = lib.mkOption { + type = types.nullOr types.bool; + default = null; + description = "Show minimize button in window header."; + }; + show_maximize = lib.mkOption { + type = types.nullOr types.bool; + default = null; + description = "Show maximize button in window header."; + }; + icon_theme = lib.mkOption { + type = types.nullOr ron.types.str; + default = null; + description = "Preferred icon theme."; + }; + header_size = lib.mkOption { + type = types.nullOr cosmic.types.density; + default = null; + description = "Density of CSD/SSD header bars."; + }; + interface_density = lib.mkOption { + type = types.nullOr cosmic.types.density; + default = null; + description = "Interface density."; + }; + interface_font = lib.mkOption { + type = types.nullOr cosmic.types.font_config; + default = null; + description = "Interface font family"; + }; + monospace_font = lib.mkOption { + type = types.nullOr cosmic.types.font_config; + default = null; + description = "Mono font family"; + }; + }; + + # https://github.com/pop-os/cosmic-files/blob/1a5a4501ee501b3155295cbfccc1c992b5ec9c01/src/config.rs#L106 + "com.system76.CosmicFiles".v1 = { + app_theme = lib.mkOption { + type = types.nullOr cosmic.types.theme; + default = null; + description = ""; + }; + desktop = lib.mkOption { + type = types.nullOr cosmic.types.files_desktop; + default = null; + description = ""; + }; + favorites = lib.mkOption { + type = types.nullOr cosmic.types.files_favorites; + default = null; + description = ""; + }; + show_details = lib.mkOption { + type = types.nullOr types.bool; + default = null; + description = ""; + }; + tab = lib.mkOption { + type = types.nullOr cosmic.types.files_tab_config; + default = null; + description = ""; + }; + type_to_search = lib.mkOption { + type = types.nullOr ( + types.enum [ + "Recursive" + "EnterPath" + ] + ); + default = null; + description = ""; + }; + }; + + # https://github.com/pop-os/cosmic-applets/blob/b4b465712218be8d26b6772a382d19f4c3ff97f8/cosmic-applet-audio/src/config.rs#L9 + "com.system76.CosmicAppletAudio".v1 = { + show_media_controls_in_top_panel = lib.mkOption { + type = types.nullOr types.bool; + default = null; + description = ""; + }; + }; + + # ... + }; +} diff --git a/home/modules/cosmic/types.nix b/home/modules/cosmic/types.nix new file mode 100644 index 0000000..9ad749a --- /dev/null +++ b/home/modules/cosmic/types.nix @@ -0,0 +1,145 @@ +{ lib, ron }: + +let + inherit (lib) types; +in +lib.fix (self: { + theme = types.enum [ + "Dark" + "Light" + "System" + ]; + density = types.enum [ + "Compact" + "Spacious" + "Standard" + ]; + weight = types.enum [ + "Thin" + "ExtraLight" + "Light" + "Normal" + "Medium" + "Semibold" + "Bold" + "ExtraBold" + "Black" + ]; + stretch = types.enum [ + "UltraCondensed" + "ExtraCondensed" + "Condensed" + "SemiCondensed" + "Normal" + "SemiExpanded" + "Expanded" + "ExtraExpanded" + "UltraExpanded" + ]; + style = types.enum [ + "Normal" + "Italic" + "Oblique" + ]; + + # libcosmic + font_config = types.submodule { + options = { + family = lib.mkOption { + type = ron.types.str; + default = null; + }; + weight = lib.mkOption { + type = types.nullOr self.weight; + default = null; + }; + stretch = lib.mkOption { + type = types.nullOr self.stretch; + default = null; + }; + style = lib.mkOption { + type = types.nullOr self.style; + default = null; + }; + }; + }; + + # Files + files_desktop = types.submodule { + options = { + grid_spacing = lib.mkOption { + type = types.nullOr types.int; + default = null; + }; + icon_size = lib.mkOption { + type = types.nullOr types.int; + default = null; + }; + show_content = lib.mkOption { + type = types.nullOr types.bool; + default = null; + }; + show_mounted_drives = lib.mkOption { + type = types.nullOr types.bool; + default = null; + }; + show_trash = lib.mkOption { + type = types.nullOr types.bool; + default = null; + }; + }; + }; + files_favorites = types.listOf ( + types.oneOf [ + (types.enum [ + "Home" + "Documents" + "Downloads" + "Music" + "Pictures" + "Videos" + ]) + (lib.types.strMatching ''^Path\(".*"\)$'') + ] + ); + files_view = types.enum [ + "Grid" + "List" + ]; + files_icon_sizes = types.submodule { + options = { + list = lib.mkOption { + type = types.nullOr types.int; + default = null; + }; + grid = lib.mkOption { + type = types.nullOr types.int; + default = null; + }; + }; + }; + files_tab_config = types.submodule { + options = { + view = lib.mkOption { + type = types.nullOr self.files_view; + default = null; + }; + folders_first = lib.mkOption { + type = types.nullOr types.bool; + default = null; + }; + show_hidden = lib.mkOption { + type = types.nullOr types.bool; + default = null; + }; + icon_sizes = lib.mkOption { + type = types.nullOr self.files_icon_sizes; + default = null; + }; + single_click = lib.mkOption { + type = types.nullOr types.bool; + default = null; + }; + }; + }; +}) diff --git a/home/modules/nixpkgs.nix b/home/nixpkgs.nix similarity index 100% rename from home/modules/nixpkgs.nix rename to home/nixpkgs.nix diff --git a/hosts/flake-module.nix b/hosts/flake-module.nix index c963958..a762134 100644 --- a/hosts/flake-module.nix +++ b/hosts/flake-module.nix @@ -2,19 +2,22 @@ { flake = { diskoConfigurations = { + home-pc = import ./home-pc/disk-config.nix; + home-server = import ./home-server/disk-config.nix; cmdframe = import ./cmdframe/disk-config.nix; }; nixosConfigurations = { home-pc = inputs.nixpkgs.lib.nixosSystem { system = "x86_64-linux"; modules = [ + inputs.disko.nixosModules.disko inputs.nixpkgs.nixosModules.notDetected inputs.nixos-hardware.nixosModules.common-pc inputs.nixos-hardware.nixosModules.common-pc-ssd inputs.nixos-hardware.nixosModules.common-cpu-amd-pstate inputs.nixos-hardware.nixosModules.common-gpu-amd (self.lib.createSystemModule "home-pc" { - hardwareConfig = ../hardware/home-pc.nix; + hardwareConfig = ../hosts/home-pc/hardware.nix; config = ../hosts/home-pc/default.nix; }) self.lib.createMediaGroup @@ -35,7 +38,7 @@ ( { pkgs, ... }: { - environment.systemPackages = [ inputs.deploy-rs.defaultPackage.x86_64-linux ]; + environment.systemPackages = [ inputs.deploy-rs.packages.x86_64-linux.default ]; } ) ]; @@ -46,6 +49,7 @@ home-server = inputs.nixpkgs.lib.nixosSystem { system = "x86_64-linux"; modules = [ + inputs.disko.nixosModules.disko inputs.nixpkgs.nixosModules.notDetected inputs.nixos-hardware.nixosModules.common-pc inputs.nixos-hardware.nixosModules.common-pc-ssd @@ -53,7 +57,7 @@ inputs.nixos-hardware.nixosModules.common-gpu-intel-kaby-lake inputs.matrix-appservices.nixosModule (self.lib.createSystemModule "home-server" { - hardwareConfig = ../hardware/lattepanda.nix; + hardwareConfig = ../hosts/home-server/hardware.nix; config = ../hosts/home-server/default.nix; }) self.lib.createMediaGroup diff --git a/hosts/home-pc/default.nix b/hosts/home-pc/default.nix index 5e32deb..0cbba48 100644 --- a/hosts/home-pc/default.nix +++ b/hosts/home-pc/default.nix @@ -2,6 +2,7 @@ { imports = [ + ./disk-config.nix ../../hardware/base.nix ../../hardware/bluetooth.nix ../../hardware/xbox.nix diff --git a/hosts/home-pc/disk-config.nix b/hosts/home-pc/disk-config.nix new file mode 100644 index 0000000..82ad757 --- /dev/null +++ b/hosts/home-pc/disk-config.nix @@ -0,0 +1,62 @@ +{ + disko.devices = { + disk = { + main = { + type = "disk"; + device = "/dev/nvme0n1"; + content = { + type = "gpt"; + partitions = { + ESP = { + size = "512M"; + type = "EF00"; + content = { + type = "filesystem"; + format = "vfat"; + mountpoint = "/boot"; + mountOptions = [ "umask=0077" ]; + }; + }; + luks = { + size = "100%"; + content = { + type = "luks"; + name = "enc"; + settings = { + allowDiscards = true; + }; + content = { + type = "btrfs"; + extraArgs = [ "-f" ]; + subvolumes = { + "@" = { + mountpoint = "/"; + mountOptions = [ + "compress-force=zstd:1" + "noatime" + ]; + }; + "@home" = { + mountpoint = "/home"; + mountOptions = [ + "compress-force=zstd:1" + "noatime" + ]; + }; + "@snapshots" = { + mountpoint = "/.snapshots"; + mountOptions = [ + "compress-force=zstd:1" + "noatime" + ]; + }; + }; + }; + }; + }; + }; + }; + }; + }; + }; +} diff --git a/hosts/home-pc/hardware.nix b/hosts/home-pc/hardware.nix new file mode 100644 index 0000000..3704143 --- /dev/null +++ b/hosts/home-pc/hardware.nix @@ -0,0 +1,26 @@ +# Do not modify this file! It was generated by ‘nixos-generate-config’ +# and may be overwritten by future invocations. Please make changes +# to /etc/nixos/configuration.nix instead. +{ + config, + lib, + pkgs, + modulesPath, + ... +}: + +{ + boot.initrd.availableKernelModules = [ + "nvme" + "ahci" + "xhci_pci" + "usb_storage" + "usbhid" + "sd_mod" + ]; + boot.initrd.kernelModules = [ ]; + boot.kernelModules = [ "kvm-amd" ]; + boot.extraModulePackages = [ ]; + + hardware.cpu.amd.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware; +} diff --git a/hosts/home-server/default.nix b/hosts/home-server/default.nix index 0a8c4bd..931d571 100644 --- a/hosts/home-server/default.nix +++ b/hosts/home-server/default.nix @@ -18,6 +18,7 @@ let in { imports = [ + ./disk-config.nix ../../hardware/base.nix ../../desktop/x11.nix ../../system/server.nix diff --git a/hosts/home-server/disk-config.nix b/hosts/home-server/disk-config.nix new file mode 100644 index 0000000..82ad757 --- /dev/null +++ b/hosts/home-server/disk-config.nix @@ -0,0 +1,62 @@ +{ + disko.devices = { + disk = { + main = { + type = "disk"; + device = "/dev/nvme0n1"; + content = { + type = "gpt"; + partitions = { + ESP = { + size = "512M"; + type = "EF00"; + content = { + type = "filesystem"; + format = "vfat"; + mountpoint = "/boot"; + mountOptions = [ "umask=0077" ]; + }; + }; + luks = { + size = "100%"; + content = { + type = "luks"; + name = "enc"; + settings = { + allowDiscards = true; + }; + content = { + type = "btrfs"; + extraArgs = [ "-f" ]; + subvolumes = { + "@" = { + mountpoint = "/"; + mountOptions = [ + "compress-force=zstd:1" + "noatime" + ]; + }; + "@home" = { + mountpoint = "/home"; + mountOptions = [ + "compress-force=zstd:1" + "noatime" + ]; + }; + "@snapshots" = { + mountpoint = "/.snapshots"; + mountOptions = [ + "compress-force=zstd:1" + "noatime" + ]; + }; + }; + }; + }; + }; + }; + }; + }; + }; + }; +} diff --git a/hosts/home-server/hardware.nix b/hosts/home-server/hardware.nix new file mode 100644 index 0000000..626774a --- /dev/null +++ b/hosts/home-server/hardware.nix @@ -0,0 +1,21 @@ +{ config, lib, ... }: + +{ + boot.initrd.availableKernelModules = [ + "xhci_pci" + "ahci" + "nvme" + "usbhid" + "usb_storage" + "sd_mod" + "sdhci_pci" + "rtsx_usb_sdmmc" + ]; + boot.initrd.kernelModules = [ ]; + boot.kernelModules = [ "kvm-intel" ]; + boot.kernelParams = [ "i915.enable_guc=3" ]; + boot.extraModulePackages = [ ]; + + powerManagement.cpuFreqGovernor = lib.mkDefault "powersave"; + hardware.cpu.intel.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware; +} diff --git a/modules/nginx-authelia.nix b/modules/nginx-authelia.nix new file mode 100644 index 0000000..c6662dc --- /dev/null +++ b/modules/nginx-authelia.nix @@ -0,0 +1,145 @@ +{ config, lib, ... }: + +let + cfg = config.services.nginx-authelia; + vhostOptionsAuth = + { config, ... }: + { + options = { + enableAutheliaAuth = lib.mkEnableOption "Enable authelia auth"; + }; + config = lib.mkIf config.enableAutheliaAuth { + locations."/authelia".extraConfig = '' + set $upstream_authelia http://${cfg.host}:${toString cfg.port}/api/verify; + + ## Essential Proxy Configuration + internal; + proxy_pass $upstream_authelia; + + ## Headers + ## The headers starting with X-* are required. + proxy_set_header X-Original-URL $scheme://$http_host$request_uri; + proxy_set_header X-Original-Method $request_method; + proxy_set_header X-Forwarded-Method $request_method; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_set_header X-Forwarded-Host $http_host; + proxy_set_header X-Forwarded-Uri $request_uri; + proxy_set_header X-Forwarded-For $remote_addr; + proxy_set_header Content-Length ""; + proxy_set_header Connection ""; + + ## Basic Proxy Configuration + proxy_pass_request_body off; + proxy_next_upstream error timeout invalid_header http_500 http_502 http_503; # Timeout if the real server is dead + proxy_redirect http:// $scheme://; + proxy_http_version 1.1; + proxy_cache_bypass $cookie_session; + proxy_no_cache $cookie_session; + proxy_buffers 4 32k; + client_body_buffer_size 128k; + + ## Advanced Proxy Configuration + send_timeout 5m; + proxy_read_timeout 240; + proxy_send_timeout 240; + proxy_connect_timeout 240; + ''; + locations."/".extraConfig = '' + ## Send a subrequest to Authelia to verify if the user is authenticated and has permission to access the resource. + auth_request /authelia; + + ## Set the $target_url variable based on the original request. + + ## Requires nginx http_set_misc module. + set_escape_uri $target_url $scheme://$http_host$request_uri; + + ## Save the upstream response headers from Authelia to variables. + auth_request_set $user $upstream_http_remote_user; + auth_request_set $groups $upstream_http_remote_groups; + auth_request_set $name $upstream_http_remote_name; + auth_request_set $email $upstream_http_remote_email; + + ## Inject the response headers from the variables into the request made to the backend. + proxy_set_header Remote-User $user; + proxy_set_header Remote-Groups $groups; + proxy_set_header Remote-Name $name; + proxy_set_header Remote-Email $email; + + ## If the subreqest returns 200 pass to the backend, if the subrequest returns 401 redirect to the portal. + error_page 401 =302 https://auth.zx.dev/?rd=$target_url; + ''; + }; + }; + + vhostOptionsProxy = + { config, ... }: + { + options = { + useAutheliaProxyConf = lib.mkEnableOption "Use recommended authelia proxy configuration"; + }; + config = lib.mkIf config.useAutheliaProxyConf { + locations."/".extraConfig = '' + ## Headers + proxy_set_header Host $host; + proxy_set_header X-Original-URL $scheme://$http_host$request_uri; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_set_header X-Forwarded-Host $http_host; + proxy_set_header X-Forwarded-Uri $request_uri; + proxy_set_header X-Forwarded-Ssl on; + proxy_set_header X-Forwarded-For $remote_addr; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header Connection ""; + + ## Basic Proxy Configuration + client_body_buffer_size 128k; + proxy_next_upstream error timeout invalid_header http_500 http_502 http_503; ## Timeout if the real server is dead. + proxy_redirect http:// $scheme://; + proxy_http_version 1.1; + proxy_cache_bypass $cookie_session; + proxy_no_cache $cookie_session; + proxy_buffers 64 256k; + + ## Trusted Proxies Configuration + ## Please read the following documentation before configuring this: + ## https://www.authelia.com/integration/proxies/nginx/#trusted-proxies + # set_real_ip_from 10.0.0.0/8; + # set_real_ip_from 172.16.0.0/12; + # set_real_ip_from 192.168.0.0/16; + # set_real_ip_from fc00::/7; + real_ip_header X-Forwarded-For; + real_ip_recursive on; + + ## Advanced Proxy Configuration + send_timeout 5m; + proxy_read_timeout 360; + proxy_send_timeout 360; + proxy_connect_timeout 360; + ''; + }; + }; +in +{ + options = { + services.nginx-authelia = { + host = lib.mkOption { + type = lib.types.str; + default = "localhost"; + }; + port = lib.mkOption { + type = lib.types.int; + default = 9091; + }; + }; + + services.nginx.virtualHosts = lib.mkOption { + type = lib.types.attrsOf ( + lib.types.submodule [ + vhostOptionsAuth + vhostOptionsProxy + ] + ); + }; + }; + + config = { }; +} diff --git a/secrets/secrets.nix b/secrets/secrets.nix index a906a73..eb46594 100644 --- a/secrets/secrets.nix +++ b/secrets/secrets.nix @@ -3,7 +3,7 @@ let felschr = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIGbQpMo1JOGk59Rzl6pVoOcMHOoqezph+aIlEXZP4rBu"; users = [ felschr ]; - # `ssh-keygen -t ed25519 -N "" -f /etc/secrets/initrd/ssh_host_ed25519_key` + # `ssh-keygen -t ed25519 -N "" -f /etc/ssh/ssh_host_ed25519_key` home-pc = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIBFTQvIcSdhEKl/Kq+pcS/cPCyyZ1ygj+djfuaXzaRMx"; home-server = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAILO+OLPr8zdOMYyKtm98AFJai7zbaxw7JhVWgOwu7K3C"; cmdframe = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIAMcPrg69IqmH3V+7lgoXif/J6z4/aEi7w7p5jRn/lkp"; diff --git a/services/adguardhome.nix b/services/adguardhome.nix index b92c593..4bbf1ad 100644 --- a/services/adguardhome.nix +++ b/services/adguardhome.nix @@ -37,9 +37,6 @@ in certificate_path = "${config.security.acme.certs."${host}".directory}/fullchain.pem"; private_key_path = "${config.security.acme.certs."${host}".directory}/key.pem"; }; - # HINT: users needs to be set up manually: - # https://github.com/AdguardTeam/AdGuardHome/wiki/Configuration#password-reset - # users = [ { name = "felschr"; } ]; querylog = { enabled = true; interval = "24h"; @@ -104,6 +101,7 @@ in services.nginx = { virtualHosts."${host}" = { + enableAutheliaAuth = true; enableACME = true; forceSSL = true; http3 = true; diff --git a/services/authelia.nix b/services/authelia.nix index 011bfb1..6209d9f 100644 --- a/services/authelia.nix +++ b/services/authelia.nix @@ -63,6 +63,8 @@ let smtpAccount = config.programs.msmtp.accounts.default; in { + imports = [ ../modules/nginx-authelia.nix ]; + age.secrets.authelia-jwt = { file = ../secrets/authelia/jwt.age; owner = cfg.user; @@ -208,6 +210,10 @@ in "lldap.service" ]; + services.nginx-authelia = { + inherit port; + }; + services.postgresql = { enable = true; ensureDatabases = [ cfg.user ]; diff --git a/system/networking.nix b/system/networking.nix index 38dcc07..0c35c5c 100644 --- a/system/networking.nix +++ b/system/networking.nix @@ -1,4 +1,9 @@ -{ config, lib, ... }: +{ + config, + pkgs, + lib, + ... +}: let isAdguardHost = config.services.adguardhome.enable; @@ -10,7 +15,7 @@ let lan = rec { IPv4Prefix = "192.168.1"; - IPv4CIDR = "${IPv4Prefix}.1/24"; + IPv4CIDR = "${IPv4Prefix}.0/24"; IPv6ULAPrefix = "fd1c:ca95:d74d"; IPv6ULACIDR = "${IPv6ULAPrefix}::/48"; }; @@ -83,4 +88,12 @@ in # mDNS already handled by systemd-resolved services.avahi.enable = false; + + programs.mtr.enable = true; + programs.mosh.enable = true; + + environment.systemPackages = with pkgs; [ + dig + wireguard-tools + ]; } diff --git a/system/nix.nix b/system/nix.nix index 3a8a7f5..c2616d7 100644 --- a/system/nix.nix +++ b/system/nix.nix @@ -1,4 +1,9 @@ -{ inputs, config, ... }: +{ + inputs, + config, + pkgs, + ... +}: let inherit (inputs.self.outputs) nixConfig; @@ -6,6 +11,8 @@ in { nixpkgs.config.allowUnfree = true; + nix.package = pkgs.lix; + nix.gc = { automatic = true; dates = "04:00";