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";