about summary refs log tree commit diff
diff options
context:
space:
mode:
authorAzat Bahawi <azat@bahawi.net>2023-02-14 23:04:05 +0300
committerAzat Bahawi <azat@bahawi.net>2023-02-14 23:04:05 +0300
commit7ed022bc9a3c89834016c866e387b60ba4523eb6 (patch)
treea0984c8df3016e84910818a60d7f3aeb42b7a718
parent2023-02-03 (diff)
2023-02-14
-rw-r--r--darwinConfigurations/mairon/default.nix18
-rw-r--r--flake.lock127
-rw-r--r--flake.nix13
-rw-r--r--modules/darwin/common/nix.nix26
-rw-r--r--modules/darwin/profiles/default.nix4
-rw-r--r--modules/darwin/profiles/headful.nix2
-rw-r--r--modules/nixfiles/common/nix/default.nix4
-rw-r--r--modules/nixfiles/emacs/default.nix130
-rw-r--r--modules/nixfiles/emacs/doom/init.el1
-rw-r--r--modules/nixfiles/firefox/default.nix33
-rw-r--r--modules/nixfiles/firefox/userChrome.css266
-rw-r--r--modules/nixfiles/firefox/userContent.css49
-rw-r--r--modules/nixfiles/nmap.nix61
-rw-r--r--modules/nixfiles/profiles/default.nix2
-rw-r--r--modules/nixfiles/profiles/dev/containers.nix12
-rw-r--r--modules/nixfiles/vim/rc.vim6
-rw-r--r--modules/nixos/bluetooth.nix11
-rw-r--r--modules/nixos/grafana.nix6
-rw-r--r--modules/nixos/kde.nix1
-rw-r--r--modules/nixos/matrix/dendrite.nix193
-rw-r--r--modules/nixos/monitoring/default.nix7
-rw-r--r--modules/nixos/openssh.nix21
-rw-r--r--modules/nixos/profiles/headless.nix5
23 files changed, 617 insertions, 381 deletions
diff --git a/darwinConfigurations/mairon/default.nix b/darwinConfigurations/mairon/default.nix
index 86021c1..31ab461 100644
--- a/darwinConfigurations/mairon/default.nix
+++ b/darwinConfigurations/mairon/default.nix
@@ -1,6 +1,7 @@
 {
   config,
   lib,
+  pkgs,
   this,
   ...
 }:
@@ -8,11 +9,18 @@ with lib; {
   nixfiles.modules.vscode.enable = true;
 
   # TODO Make this per-directory/per-remote.
-  hm.programs.git = {
-    userName = mkForce "Firstname Lastname";
-    userEmail = mkForce "username@work.com";
-    signing.key = mkForce "@PGP_KEY@";
-    extraConfig."url \"git@gitlab.services.work.com:\"".insteadOf = "work:";
+  hm = {
+    packages = with pkgs; [
+      ansible
+      ansible-lint
+    ];
+
+    programs.git = {
+      userName = mkForce "Firstname Lastname";
+      userEmail = mkForce "username@work.com";
+      signing.key = mkForce "@PGP_KEY@";
+      extraConfig."url \"git@gitlab.services.work.com:\"".insteadOf = "work:";
+    };
   };
 
   networking = {
diff --git a/flake.lock b/flake.lock
index 2a7560b..01e3e00 100644
--- a/flake.lock
+++ b/flake.lock
@@ -257,16 +257,17 @@
     },
     "agenix": {
       "inputs": {
+        "darwin": "darwin",
         "nixpkgs": [
           "nixpkgs"
         ]
       },
       "locked": {
-        "lastModified": 1675021904,
-        "narHash": "sha256-jkg8ZwPi0aYKxtaGvGXzxz14kGkGxMrdJZj2gGxRo3E=",
+        "lastModified": 1676153903,
+        "narHash": "sha256-uetRyjgMiZCs6srmZ10M764Vn7F53M9mVuqnzHmyBqU=",
         "owner": "ryantm",
         "repo": "agenix",
-        "rev": "6d3a415637981b966f3bdb813aefcff405630a7f",
+        "rev": "ea17cc71b4e1bc5b2601f210a1c85db9453ad723",
         "type": "github"
       },
       "original": {
@@ -299,16 +300,16 @@
         ]
       },
       "locked": {
-        "lastModified": 1674385484,
-        "narHash": "sha256-sZ78pRCF5SXWq8/lIQ5bqED6wTQxY5waUBn+Jbu9J10=",
+        "lastModified": 1675676290,
+        "narHash": "sha256-ho4MyqHPrUBQqBTZl0X0aTliloKQNk1iUbwGgkvUw4g=",
         "owner": "dwarfmaster",
         "repo": "arkenfox-nixos",
-        "rev": "9e799c371416daf163a8a54829aef4c1ae85c7bc",
+        "rev": "5985ba832c841af5805c89d64f78bfae2a0f331f",
         "type": "github"
       },
       "original": {
         "owner": "dwarfmaster",
-        "ref": "main",
+        "ref": "5985ba832c841af5805c89d64f78bfae2a0f331f",
         "repo": "arkenfox-nixos",
         "type": "github"
       }
@@ -349,6 +350,28 @@
     "darwin": {
       "inputs": {
         "nixpkgs": [
+          "agenix",
+          "nixpkgs"
+        ]
+      },
+      "locked": {
+        "lastModified": 1673295039,
+        "narHash": "sha256-AsdYgE8/GPwcelGgrntlijMg4t3hLFJFCRF3tL5WVjA=",
+        "owner": "lnl7",
+        "repo": "nix-darwin",
+        "rev": "87b9d090ad39b25b2400029c64825fc2a8868943",
+        "type": "github"
+      },
+      "original": {
+        "owner": "lnl7",
+        "ref": "master",
+        "repo": "nix-darwin",
+        "type": "github"
+      }
+    },
+    "darwin_2": {
+      "inputs": {
+        "nixpkgs": [
           "nixpkgs"
         ]
       },
@@ -434,11 +457,11 @@
         ]
       },
       "locked": {
-        "lastModified": 1675015755,
-        "narHash": "sha256-4orQ2IM5xKueh3lV9HUdM0P/0DBRo6TZEAVo73/dZSk=",
+        "lastModified": 1676398447,
+        "narHash": "sha256-8pAf1ZkyDiFJPrfN7GM9f8kGWJx/AEkJu55GFvR5cbQ=",
         "owner": "nix-community",
         "repo": "emacs-overlay",
-        "rev": "1d2409effbdebad47fb887ff6305f3da1fea5965",
+        "rev": "8d9eaa57b64e7fe74f29f4b7c6823a541bbf5556",
         "type": "github"
       },
       "original": {
@@ -580,16 +603,16 @@
     },
     "flake-utils": {
       "locked": {
-        "lastModified": 1667395993,
-        "narHash": "sha256-nuEHfE/LcWyuSWnS8t12N1wc105Qtau+/OdUAjtQ0rA=",
+        "lastModified": 1676283394,
+        "narHash": "sha256-XX2f9c3iySLCw54rJ/CZs+ZK6IQy7GXNY4nSOyu2QG4=",
         "owner": "numtide",
         "repo": "flake-utils",
-        "rev": "5aed5285a952e0b949eb3ba02c12fa4fcfef535f",
+        "rev": "3db36a8b464d0c4532ba1c7dda728f4576d6d073",
         "type": "github"
       },
       "original": {
         "owner": "numtide",
-        "ref": "master",
+        "ref": "main",
         "repo": "flake-utils",
         "type": "github"
       }
@@ -642,11 +665,11 @@
         ]
       },
       "locked": {
-        "lastModified": 1674928308,
-        "narHash": "sha256-elVU4NUZEl11BdT4gC+lrpLYM8Ccxqxs19Ix84HTI9o=",
+        "lastModified": 1675935446,
+        "narHash": "sha256-WajulTn7QdwC7QuXRBavrANuIXE5z+08EdxdRw1qsNs=",
         "owner": "nix-community",
         "repo": "home-manager",
-        "rev": "08a778d80308353f4f65c9dcd3790b5da02d6306",
+        "rev": "2dce7f1a55e785a22d61668516df62899278c9e4",
         "type": "github"
       },
       "original": {
@@ -658,11 +681,11 @@
     },
     "impermanence": {
       "locked": {
-        "lastModified": 1668668915,
-        "narHash": "sha256-QjY4ZZbs9shwO4LaLpvlU2bO9J1juYhO9NtV3nrbnYQ=",
+        "lastModified": 1675359654,
+        "narHash": "sha256-FPxzuvJkcO49g4zkWLSeuZkln54bLoTtrggZDJBH90I=",
         "owner": "nix-community",
         "repo": "impermanence",
-        "rev": "5df9108b346f8a42021bf99e50de89c9caa251c3",
+        "rev": "6138eb8e737bffabd4c8fc78ae015d4fd6a7e2fd",
         "type": "github"
       },
       "original": {
@@ -691,11 +714,11 @@
     "master": {
       "flake": false,
       "locked": {
-        "lastModified": 1673196505,
-        "narHash": "sha256-YsQbH6bqp2I52meYf0X0DQpwLlDdu5pK9XHMT/9RqOg=",
+        "lastModified": 1674781645,
+        "narHash": "sha256-NGp5BLOQmiXsUh9nrXP+PeVXyK1c8Ij5EnwtFXAkD9w=",
         "owner": "arkenfox",
         "repo": "user.js",
-        "rev": "62a68f08147123b0c2c288ffdecc3f03e4ab1ae8",
+        "rev": "b99dd27de828be13530ce2f48c9178d34f5f82ab",
         "type": "github"
       },
       "original": {
@@ -741,11 +764,11 @@
         "ws-butler": "ws-butler"
       },
       "locked": {
-        "lastModified": 1674782939,
-        "narHash": "sha256-mf+RaqdCqqLraVVOQ5c8LRj+9ChnVzsUNlOjJSPdBbc=",
+        "lastModified": 1675387812,
+        "narHash": "sha256-fGjWMg97w1mP0cDIR9Y8qCa77sEtiIdYzqiRB+P2YcM=",
         "owner": "nix-community",
         "repo": "nix-doom-emacs",
-        "rev": "e92e5b6021b1ad4290e051111010ba51921507cd",
+        "rev": "8de922e4e23158790970a266234a853305b1928d",
         "type": "github"
       },
       "original": {
@@ -765,11 +788,11 @@
         ]
       },
       "locked": {
-        "lastModified": 1674956856,
-        "narHash": "sha256-u1DZQpUE3VepKxaEpcM6qz+bDCTb9muFPf0AcRdnuPI=",
+        "lastModified": 1676339309,
+        "narHash": "sha256-haiQG9mO6CWcY0+oecOtNiZkbFN5FslJhJKX43E9A4s=",
         "owner": "Infinidoge",
         "repo": "nix-minecraft",
-        "rev": "0fe27d63d2801eb5fa430b534d6776d290450c6f",
+        "rev": "1787321cb4e13160086bb92280c83987d4e49234",
         "type": "github"
       },
       "original": {
@@ -797,11 +820,11 @@
     },
     "nixos-hardware": {
       "locked": {
-        "lastModified": 1674550793,
-        "narHash": "sha256-ljJlIFQZwtBbzWqWTmmw2O5BFmQf1A/DspwMOQtGXHk=",
+        "lastModified": 1675933606,
+        "narHash": "sha256-y427VhPQHOKkYvkc9MMsL/2R7M11rQxzsRdRLM3htx8=",
         "owner": "NixOS",
         "repo": "nixos-hardware",
-        "rev": "b7ac0a56029e4f9e6743b9993037a5aaafd57103",
+        "rev": "44ae00e02e8036a66c08f4decdece7e3bbbefee2",
         "type": "github"
       },
       "original": {
@@ -813,11 +836,11 @@
     },
     "nixpkgs": {
       "locked": {
-        "lastModified": 1674958881,
-        "narHash": "sha256-p1E20TGSgzs+EUhRPMe6fyZIxUV6CbcwilZEzy+XmAk=",
+        "lastModified": 1676209454,
+        "narHash": "sha256-alj9mBkV9U6tTPDK026671D2pesLSYZZc9j5dBZJ9f0=",
         "owner": "NixOS",
         "repo": "nixpkgs",
-        "rev": "a0feb36dc510bfa8f8809980a8230617fb9eb618",
+        "rev": "8c619a1f3cedd16ea172146e30645e703d21bfc1",
         "type": "github"
       },
       "original": {
@@ -829,11 +852,11 @@
     },
     "nixpkgs-master": {
       "locked": {
-        "lastModified": 1675023360,
-        "narHash": "sha256-IGXCr47L9OQaZkzyogT/4SlljkueU/+on5u8VOeKQ78=",
+        "lastModified": 1676398261,
+        "narHash": "sha256-ILP8TnCgfmb1Aal/9f2YgeoEzsJwE85lsLsChu1cbcU=",
         "owner": "NixOS",
         "repo": "nixpkgs",
-        "rev": "dc9441ccc34a5cb56d09ebbe82aa4225a2e3d91d",
+        "rev": "3bee4ab8db244db328b41ae5f4fbce19b658f1be",
         "type": "github"
       },
       "original": {
@@ -845,11 +868,11 @@
     },
     "nixpkgs-stable": {
       "locked": {
-        "lastModified": 1675018232,
-        "narHash": "sha256-sN98tnO63DXhDX1BAfrLu+7z1ZEW51jEsk3ErmMmUaI=",
+        "lastModified": 1676396097,
+        "narHash": "sha256-uBimVNocWHZ/fTxTZu5IMHjiDVOPqlnKqgeZRZNbB4c=",
         "owner": "NixOS",
         "repo": "nixpkgs",
-        "rev": "a296508344909b1251442a1e38d9c4080c9bf7c0",
+        "rev": "75e0a511d0e6edaff6e3f5de0815102d3c640d08",
         "type": "github"
       },
       "original": {
@@ -911,11 +934,11 @@
     },
     "nur": {
       "locked": {
-        "lastModified": 1674999880,
-        "narHash": "sha256-mmALt2MFFLsJj0wddOxLqTg453wtPskS00U1TD120FA=",
+        "lastModified": 1676385929,
+        "narHash": "sha256-qaIM1TBKKQ+FTTuUpr2AfUP8NQ6q8QwL1BEaYHG9Gls=",
         "owner": "nix-community",
         "repo": "NUR",
-        "rev": "1955f5e2c384d156efcc0b4ce7a0f635c3ea0997",
+        "rev": "32f2fc312516b3b2b47708105c8fc87cea1df5d2",
         "type": "github"
       },
       "original": {
@@ -1016,16 +1039,16 @@
         ]
       },
       "locked": {
-        "lastModified": 1671576765,
-        "narHash": "sha256-L6o9OK560Tkkfj18y7SD10E9BewDqa73tDZ+N1DSn4A=",
+        "lastModified": 1675636511,
+        "narHash": "sha256-k7EkqHY0Q1fuJQgOe6p/HXOuLPVRzbUfxItXaZVbOC4=",
         "owner": "fn2006",
         "repo": "PollyMC",
-        "rev": "689a653cc476241220a8758dcbbc3b197e2aa156",
+        "rev": "f61f4fe722a93c40e8bfd903b7ad7eaa3205f8bf",
         "type": "github"
       },
       "original": {
         "owner": "fn2006",
-        "ref": "6.1",
+        "ref": "6.3",
         "repo": "PollyMC",
         "type": "github"
       }
@@ -1047,11 +1070,11 @@
         ]
       },
       "locked": {
-        "lastModified": 1674761200,
-        "narHash": "sha256-v0ypL0eDhFWmgd3f5nnbffaMA5BUoOnYUiEso7fk+q0=",
+        "lastModified": 1676279938,
+        "narHash": "sha256-RDyvVdituVQQZtGA7DNaJruJLDz/pfkREpUcI4ZQvsk=",
         "owner": "cachix",
         "repo": "pre-commit-hooks.nix",
-        "rev": "8539119ba0b17b15e60de60da0348d8c73bbfdf2",
+        "rev": "1583077009b6ef4236d1899c0f43cf1ce1db8085",
         "type": "github"
       },
       "original": {
@@ -1082,7 +1105,7 @@
         "agenix": "agenix",
         "arkenfox-nixos": "arkenfox-nixos",
         "azahi-cc": "azahi-cc",
-        "darwin": "darwin",
+        "darwin": "darwin_2",
         "dns-nix": "dns-nix",
         "emacs-overlay": "emacs-overlay",
         "flake-compat": "flake-compat",
diff --git a/flake.nix b/flake.nix
index 4f3eacb..5cdf643 100644
--- a/flake.nix
+++ b/flake.nix
@@ -7,6 +7,8 @@
   # [1]: https://github.com/NixOS/nix/issues/5373
   inputs = {
     nixpkgs = {
+      # type = "path";
+      # path = "/home/azahi/src/nixpkgs";
       type = "github";
       owner = "NixOS";
       repo = "nixpkgs";
@@ -56,6 +58,8 @@
     };
 
     home-manager = {
+      # type = "path";
+      # path = "/home/azahi/src/home-manager";
       type = "github";
       owner = "nix-community";
       repo = "home-manager";
@@ -88,11 +92,14 @@
       type = "github";
       owner = "dwarfmaster";
       repo = "arkenfox-nixos";
-      ref = "main";
+      # FIXME https://github.com/dwarfmaster/arkenfox-nixos/issues/20
+      ref = "5985ba832c841af5805c89d64f78bfae2a0f331f";
       inputs.nixpkgs.follows = "nixpkgs";
     };
 
     nix-doom-emacs = {
+      # type = "path";
+      # path = "/home/azahi/src/nix-doom-emacs";
       type = "github";
       owner = "nix-community";
       repo = "nix-doom-emacs";
@@ -120,7 +127,7 @@
       type = "github";
       owner = "fn2006";
       repo = "PollyMC";
-      ref = "6.1";
+      ref = "6.3";
       inputs = {
         flake-compat.follows = "flake-compat";
         nixpkgs.follows = "nixpkgs";
@@ -165,7 +172,7 @@
       type = "github";
       owner = "numtide";
       repo = "flake-utils";
-      ref = "master";
+      ref = "main";
     };
 
     flake-registry = {
diff --git a/modules/darwin/common/nix.nix b/modules/darwin/common/nix.nix
index a522cb0..2b39e7d 100644
--- a/modules/darwin/common/nix.nix
+++ b/modules/darwin/common/nix.nix
@@ -1,15 +1,37 @@
 {
+  config,
+  inputs,
   lib,
   this,
   ...
 }:
 with lib; {
+  _module.args = let
+    importNixpkgsx86 = nixpkgs:
+      import nixpkgs {
+        inherit (config.nixpkgs) config;
+        system = "x86_64-darwin";
+      };
+  in rec {
+    pkgsx86 = importNixpkgsx86 inputs.nixpkgs;
+    pkgsLocalx86 = importNixpkgsx86 "${config.my.home}/src/nixpkgs"; # Impure!
+    pkgsMasterx86 = importNixpkgsx86 inputs.nixpkgs-master;
+    pkgsStablex86 = importNixpkgsx86 inputs.nixpkgs-stable;
+    pkgsRevx86 = rev: hash:
+      importNixpkgsx86 (pkgs.fetchFromGitHub {
+        owner = "NixOS";
+        repo = "nixpkgs";
+        inherit rev hash;
+      });
+    pkgsPRx86 = pr: pkgsRevx86 "refs/pull/${toString pr}/head";
+  };
+
   nix = {
     daemonIOLowPriority = false;
     daemonProcessType = "Standard";
 
-    extraOptions = optionalString (this.system == "aarch64-darwin") ''
-      extra-platforms = x86_64-darwin aarch64-darwin
+    settings.extra-platforms = optionalString (this.system == "aarch64-darwin") ''
+      x86_64-darwin aarch64-darwin
     '';
 
     settings.trusted-users = ["@admin"];
diff --git a/modules/darwin/profiles/default.nix b/modules/darwin/profiles/default.nix
index f42647a..3e783b9 100644
--- a/modules/darwin/profiles/default.nix
+++ b/modules/darwin/profiles/default.nix
@@ -50,7 +50,9 @@ in {
           orientation = "bottom";
           tilesize = 18;
 
-          show-recents = false;
+          # Don't change these options because this will disallow rearranging
+          # shortcuts.
+          show-recents = true;
           static-only = false;
 
           # Disable hot corners.
diff --git a/modules/darwin/profiles/headful.nix b/modules/darwin/profiles/headful.nix
index 44695f6..5484dfe 100644
--- a/modules/darwin/profiles/headful.nix
+++ b/modules/darwin/profiles/headful.nix
@@ -12,7 +12,9 @@ in {
     nixfiles.modules.homebrew.enable = true;
 
     homebrew.casks = [
+      {name = "chromium";}
       {name = "firefox";}
+      {name = "iterm2";}
       {name = "telegram-desktop";}
     ];
   };
diff --git a/modules/nixfiles/common/nix/default.nix b/modules/nixfiles/common/nix/default.nix
index 2f7904a..5ce54f9 100644
--- a/modules/nixfiles/common/nix/default.nix
+++ b/modules/nixfiles/common/nix/default.nix
@@ -4,6 +4,7 @@
   lib,
   localUsername ? lib.my.username,
   pkgs,
+  pkgsPR,
   this,
   ...
 }:
@@ -94,6 +95,8 @@ with lib; {
         alejandra = super.alejandra.overrideAttrs (_: _: {
           patches = [./patches/alejandra-no-ads.patch];
         });
+
+        inherit (pkgsPR "215704" "sha256-o2F/ZAugljJKlVIAHMTBK6+Lj6BiBwteA5OuaWPKXm0=") dendrite;
       }
       // (with super; let
         np = nodePackages;
@@ -123,7 +126,6 @@ with lib; {
 
   environment.systemPackages = with pkgs;
     optionals this.isHeadful [
-      nix-du
       nix-top
       nix-tree
     ];
diff --git a/modules/nixfiles/emacs/default.nix b/modules/nixfiles/emacs/default.nix
index 499dd59..975c809 100644
--- a/modules/nixfiles/emacs/default.nix
+++ b/modules/nixfiles/emacs/default.nix
@@ -3,6 +3,7 @@
   inputs,
   lib,
   pkgs,
+  this,
   ...
 }:
 with lib; let
@@ -30,69 +31,72 @@ in {
         extraConfig = let
           # NOTE gopls will require the "go" executable which must be provided
           # by the project's flake/shell.
-          extraBins = with pkgs; [
-            (aspellWithDicts (p: with p; [en ru])) # :checkers (spell +aspell)
-            (python3.withPackages (p:
-              with p; [
-                # :lang python :ui (treemacs +lsp)
-                black # :lang python :editor format
-                isort # :lang python
-                pyflakes # :lang python
-                python-lsp-server # :lang (python +lsp)
-              ]))
-            asmfmt # :editor format
-            bash-language-server # :lang (sh +lsp)
-            clang-tools # :lang (cc +lsp) :editor format
-            cmake-format # :lang cc :editor format
-            cmigemo # :lang japanese
-            css-language-server # :lang (web +lsp)
-            dhall-language-server # :lang (dhall +lsp)
-            dockerfile-language-server # :tools (docker +lsp)
-            editorconfig # :tools editorconfig
-            fd # doom!
-            gdb # :tools debugger
-            gnuplot # :lang (org +gnuplot)
-            gnutls # doom!
-            go-language-server # :lang (go +lsp)
-            gomodifytags # :lang go
-            gore # :lang go
-            gotests # :lang go
-            graphviz # :lang (org +roam2) :lang plantuml
-            haskell-language-server # :lang (haskell +lsp)
-            # haskellPackages.brittany # :lang haskell :editor format # FIXME Dependency marked as broken.
-            haskellPackages.cabal-fmt # :lang haskell :editor format
-            haskellPackages.cabal-install # :lang haskell
-            haskellPackages.hoogle # :lang haskell
-            html-language-server # :lang (web +lsp)
-            html-tidy # :lang web
-            jre # :lang plantuml
-            json-language-server # :lang (json +lsp)
-            lldb # :tools debugger
-            lua-language-server # :lang (lua +lsp)
-            nix-language-server # :lang (nix +lsp)
-            nixfmt # :lang nix :editor format
-            nodePackages.js-beautify # :lang web
-            nodePackages.lua-fmt # :lang lua :editor format
-            nodePackages.prettier # :editor format
-            nodePackages.stylelint # :lang web
-            nodejs # :tools debugger
-            pandoc # :lang org markdown latex
-            pinentry-emacs # doom!
-            pre-commit # :tools magit
-            ripgrep # doom!
-            rust-analyzer # :lang (rust +lsp)
-            rustfmt # :lang rust
-            shellcheck # :lang sh
-            shfmt # :lang sh :editor format
-            sqlite # :lang (org +roam2) :tools lookup
-            texlab # lang (tex +lsp)
-            texlive.combined.scheme-full # :lang org tex
-            unzip # :tools debugger
-            wordnet # :tools (lookup +dictionary +offline)
-            yaml-language-server # :lang (yaml +lsp)
-            zls # :lang (zig +lsp)
-            zstd # :emacs undo
-          ];
+          extraBins = with pkgs;
+            [
+              (aspellWithDicts (p: with p; [en ru])) # :checkers (spell +aspell)
+              (python3.withPackages (p:
+                with p; [
+                  # :lang python :ui (treemacs +lsp)
+                  black # :lang python :editor format
+                  isort # :lang python
+                  pyflakes # :lang python
+                  python-lsp-server # :lang (python +lsp)
+                ]))
+              asmfmt # :editor format
+              bash-language-server # :lang (sh +lsp)
+              clang-tools # :lang (cc +lsp) :editor format
+              cmake-format # :lang cc :editor format
+              cmigemo # :lang japanese
+              css-language-server # :lang (web +lsp)
+              dhall-language-server # :lang (dhall +lsp)
+              dockerfile-language-server # :tools (docker +lsp)
+              editorconfig # :tools editorconfig
+              fd # doom!
+              gnuplot # :lang (org +gnuplot)
+              gnutls # doom!
+              go-language-server # :lang (go +lsp)
+              gomodifytags # :lang go
+              gore # :lang go
+              gotests # :lang go
+              graphviz # :lang (org +roam2) :lang plantuml
+              haskellPackages.haskell-language-server # :lang (haskell +lsp)
+              haskellPackages.ormolu # :lang haskell :editor format
+              haskellPackages.cabal-fmt # :lang haskell :editor format
+              haskellPackages.cabal-install # :lang haskell
+              haskellPackages.hoogle # :lang haskell
+              html-language-server # :lang (web +lsp)
+              html-tidy # :lang web
+              jre # :lang plantuml
+              json-language-server # :lang (json +lsp)
+              nix-language-server # :lang (nix +lsp)
+              nixfmt # :lang nix :editor format
+              nodePackages.js-beautify # :lang web
+              nodePackages.prettier # :editor format
+              nodePackages.stylelint # :lang web
+              nodejs # :tools debugger
+              pandoc # :lang org markdown latex
+              pinentry-emacs # doom!
+              pre-commit # :tools magit
+              ripgrep # doom!
+              rust-analyzer # :lang (rust +lsp)
+              rustfmt # :lang rust
+              shellcheck # :lang sh
+              shfmt # :lang sh :editor format
+              sqlite # :lang (org +roam2) :tools lookup
+              texlab # lang (tex +lsp)
+              texlive.combined.scheme-full # :lang org tex
+              unzip # :tools debugger
+              wordnet # :tools (lookup +dictionary +offline)
+              yaml-language-server # :lang (yaml +lsp)
+              zls # :lang (zig +lsp)
+              zstd # :emacs undo
+            ]
+            ++ (
+              # :tools debugger
+              if (this.system != "aarch64-darwin")
+              then [gdb]
+              else [lldb]
+            );
         in ''
           ;; This will integrate packages which are required by various modules
           ;; without polluting the user's profile.
diff --git a/modules/nixfiles/emacs/doom/init.el b/modules/nixfiles/emacs/doom/init.el
index 4d7dd66..1016f40 100644
--- a/modules/nixfiles/emacs/doom/init.el
+++ b/modules/nixfiles/emacs/doom/init.el
@@ -93,7 +93,6 @@
        json
        (kotlin +lsp +tree-sitter)
        (latex +lsp +tree-sittter)
-       (lua +lsp +tree-sitter)
        (markdown +lsp +tree-sitter)
        (nix +lsp)
        (org +pandoc +roam2)
diff --git a/modules/nixfiles/firefox/default.nix b/modules/nixfiles/firefox/default.nix
index 8b51db7..7038773 100644
--- a/modules/nixfiles/firefox/default.nix
+++ b/modules/nixfiles/firefox/default.nix
@@ -63,12 +63,21 @@ in {
 
           isDefault = true;
 
-          # A way to change the look of the Firefox itself.
           userChrome = mkCssWithRoot ./userChrome.css;
 
-          # A way to remove annoyances and visual bloat from many webpages.
           userContent = mkCssWithRoot ./userContent.css;
 
+          extensions = with pkgs.nur.repos.rycee.firefox-addons; [
+            bitwarden
+            consent-o-matic
+            darkreader
+            localcdn
+            noscript
+            privacy-redirect
+            ublock-origin
+            violentmonkey
+          ];
+
           # https://github.com/arkenfox/user.js/blob/master/user.js
           arkenfox = {
             enable = true;
@@ -225,6 +234,9 @@ in {
             "browser.backspace_action" = 0;
             "browser.bookmarks.max_backups" = 1;
             "browser.disableResetPrompt" = true;
+            "browser.download.autohideButton" = false;
+            "browser.newtabpage.activity-stream.feeds.system.topsites" = false;
+            "browser.newtabpage.activity-stream.feeds.topsites" = false;
             "browser.newtabpage.introShown" = true;
             "browser.onboarding.enabled" = false;
             "browser.search.update" = false;
@@ -232,7 +244,10 @@ in {
             "browser.startup.homepage_welcome_url.additional" = "";
             "browser.tabs.closeWindowWithLastTab" = true;
             "browser.tabs.firefox-view" = false;
-            "browser.tabs.inTitlebar" = 1;
+            "browser.tabs.inTitlebar" =
+              if config.nixfiles.modules.kde.enable
+              then 1
+              else 0;
             "browser.tabs.warnOnClose" = false;
             "browser.tabs.warnOnCloseOtherTabs" = false;
             "browser.tabs.warnOnOpen" = false;
@@ -243,7 +258,6 @@ in {
             "extensions.screenshots.disabled" = true;
             "extensions.update.autoUpdateDefault" = false;
             "extensions.update.enabled" = false;
-            "font.name-list.emoji" = "emoji";
             "full-screen-api.warning.delay" = 0;
             "full-screen-api.warning.timeout" = 0;
             "general.autoScroll" = true;
@@ -259,17 +273,6 @@ in {
             "toolkit.legacyUserProfileCustomizations.stylesheets" = true;
           };
         };
-
-        extensions = with pkgs.nur.repos.rycee.firefox-addons; [
-          bitwarden
-          consent-o-matic
-          darkreader
-          localcdn
-          noscript
-          privacy-redirect
-          ublock-origin
-          violentmonkey
-        ];
       };
     };
   };
diff --git a/modules/nixfiles/firefox/userChrome.css b/modules/nixfiles/firefox/userChrome.css
index 5300d17..58e450e 100644
--- a/modules/nixfiles/firefox/userChrome.css
+++ b/modules/nixfiles/firefox/userChrome.css
@@ -1,124 +1,210 @@
 @-moz-document url(chrome://browser/content/browser.xul), url(chrome://browser/content/browser.xhtml)
 {
-    :root {
-        --toolbarbutton-border-radius: 0 !important;
-        --tab-border-radius: 0 !important;
-        --tab-block-margin: 0 !important;
-        --arrowpanel-border-radius: 0 !important;
-    }
-
-    #PersonalToolbar toolbarbutton:not(:hover),
-    #bookmarks-toolbar-button:not(:hover) {
-        filter: grayscale(1) !important;
-    }
-
+    /* :root { */
+    /*     /\* */
+    /*      * Helper colours. */
+    /*      *\/ */
+    /*     --background: var(--black) !important; */
+    /*     --foreground: var(--white) !important; */
+    /*     --background-alt: var(--bright-black) !important; */
+    /*     --foreground-alt: var(--bright-white) !important; */
+
+    /*     /\* */
+    /*      * Various root values that can be redefined. */
+    /*      *\/ */
+    /*     --arrowpanel-border-radius: 0 !important; */
+    /*     --autocomplete-popup-highlight-background: var(--background) !important; */
+    /*     --autocomplete-popup-highlight-color: var(--foreground) !important; */
+    /*     --backbutton-background: transparent !important; */
+    /*     --backbutton-border-color: transparent !important; */
+    /*     --tab-block-margin: 0 !important; */
+    /*     --tab-border-radius: 0 !important; */
+    /*     --tabs-border-color: transparent !important; */
+    /*     --tabs-top-border-width: 0 !important; */
+    /*     --toolbar-field-focus-border-color: var(--background) !important; */
+    /*     --toolbar-non-lwt-bgcolor: var(--background) !important; */
+    /*     --toolbar-non-lwt-bgimage: none !important; */
+    /*     --toolbar-non-lwt-textcolor: var(--foreground) !important; */
+    /*     --toolbarbutton-border-radius: 0 !important; */
+    /* } */
+
+    /*
+     ***
+     * Tabbar
+     ***
+     */
+
+    /*
+     * Apply colours and fonts.
+     */
+    /* .tabbrowser-tab { */
+    /*     color: var(--background-alt) !important; */
+    /*     font-family: var(--sans-serif-font-family) !important; */
+    /*     font-size: var(--sans-serif-font-size) !important; */
+    /* } */
+    /* .tabbrowser-tab[visuallyselected="true"] { */
+    /*     background: var(--background) !important; */
+    /*     color: var(--foreground) !important; */
+    /* } */
+
+    /*
+     * Not sure why is this shit even exists...
+     */
     .titlebar-spacer {
         display: none !important;
     }
 
+    /*
+     * Disable borders and margins.
+     */
+    #tabbrowser-tabs {
+        border-inline-start: 0 !important;
+        /* padding-inline-start: 0 !important; */
+        margin-inline-start: 0 !important;
+    }
+    #tabbrowser-tabs[haspinnedtabs]:not([positionpinnedtabs])
+        > #tabbrowser-arrowscrollbox
+        > .tabbrowser-tab[first-visible-unpinned-tab] {
+        margin-inline-start: none !important;
+    }
     .tabbrowser-tab::after,
     .tabbrowser-tab::before {
         border: none !important;
     }
 
-    #urlbar[pageproxystate="valid"] > #identity-box.verifiedIdentity,
-    #urlbar[pageproxystate="valid"] > #identity-box.chromeUI,
-    #urlbar[pageproxystate="valid"] > #identity-box.extensionPage,
-    #urlbar-display-box {
-        border: none !important;
-    }
-
+    /*
+     * Make tabs backgroundless.
+     */
+    /* .tab-background, */
+    /* .tab-line { */
+    /*     display: none !important; */
+    /* } */
+
+    /*
+     * Stretch tabs to the max by default.
+     */
+    .tabbrowser-tab[fadein]:not([pinned="true"]) {
+        max-width: 100% !important;
+    }
+
+    /*
+     * Fix favicon location.
+     */
+    /* .tab-icon-image { */
+    /*     margin-inline-end: 10px !important; */
+    /*     margin-top: 0px !important; */
+    /* } */
+
+    /*
+     * "C-t" exists.
+     */
+    /* #tabs-newtab-button, */
+    /* #TabsToolbar #new-tab-button { */
+    /*     display: none !important; */
+    /* } */
+
+    /*
+     * "C-w" exists.
+     */
     .tab-close-button {
         display: none !important;
     }
 
-    #tabbrowser-tabs:not([movingtab])
-        > #tabbrowser-arrowscrollbox
-        > .tabbrowser-tab
-        > .tab-stack
-        > .tab-background[multiselected="true"],
-    #tabbrowser-tabs:not([movingtab])
-        > #tabbrowser-arrowscrollbox
-        > .tabbrowser-tab
-        > .tab-stack
-        > .tab-background[selected="true"] {
-        background-image: none !important;
+    /*
+     ***
+     * Navbar & urlbar.
+     ***
+     */
+
+    /*
+     * Remove useless buttons.
+     */
+    /* #forward-button, */
+    /* #back-button, */
+    /* #reload-button, */
+    /* #stop-button { */
+    /*     display: none !important; */
+    /* } */
+
+    /*
+     * Remove padding between urlbar and side elements.
+     */
+    #customizableui-special-spring1,
+    #customizableui-special-spring2 {
+        display: none !important;
     }
 
-    #nav-bar:not([tabs-hidden="true"]) {
-        box-shadow: none;
-    }
+    /* #urlbar { */
+    /*     background: var(--background) !important; */
+    /*     color: var(--forground) !important; */
+    /*     font-family: var(--sans-serif-font-family) !important; */
+    /*     font-size: var(--sans-serif-font-size) !important; */
+    /*     border-color: transparent !important; */
+    /* } */
 
-    #tabbrowser-tabs[haspinnedtabs]:not([positionpinnedtabs])
-        > #tabbrowser-arrowscrollbox
-        > .tabbrowser-tab[first-visible-unpinned-tab] {
-        margin-inline-start: 0 !important;
-    }
+    /* #urlbar:not(:-moz-lwtheme):not([focused="true"]) > #urlbar-background, */
+    /* #searchbar:not(:-moz-lwtheme):not(:focus-within) { */
+    /*     border: none !important; */
+    /* } */
 
-    .tab-background {
-        border-right: 0px solid var(--brightBlack) !important;
-        margin-left: -4px !important;
-    }
+    /* #urlbar *|*.textbox-input::-moz-placeholder { */
+    /*     color: transparent !important; */
+    /* } */
 
-    .tabbrowser-tab:is([visuallyselected="true"], [multiselected])
-        > .tab-stack
-        > .tab-background {
-        box-shadow: none !important;
-    }
+    /* .urlbar-icon:hover:not([disabled]), */
+    /* .urlbar-icon-wrapper:hover:not([disabled]) { */
+    /*     background-color: var(--background-alt) !important; */
+    /* } */
 
-    .tabbrowser-tab[last-visible-tab="true"] {
-        padding-inline-end: 0 !important;
-    }
+    /* #urlbar-background { */
+    /*     background: transparent !important; */
+    /* } */
 
-    #tabs-newtab-button {
-        padding-left: 0 !important;
-    }
+    /* .urlbarView-tags, */
+    /* .urlbarView-url, */
+    /* .urlbarView-title:not(:empty) ~ .urlbarView-action { */
+    /*     font-size: var(--sans-serif-font-size) !important; */
+    /* } */
 
-    #urlbar-input-container {
-        border: 3px solid var(--brightBlack) !important;
+    .urlbarView-row[label="Firefox Suggest"] {
+        margin-block-start: 0 !important;
     }
-
-    #urlbar[focused="true"] > #urlbar-background {
-        box-shadow: none !important;
+    .urlbarView-row[label="Firefox Suggest"]::before {
+        display: none !important;
     }
 
-    #navigator-toolbox {
-        border: none !important;
-    }
+    /*
+     ***
+     * Misc.
+     ***
+     */
 
-    .bookmark-item .toolbarbutton-icon {
-        display: none;
+    /*
+     * Call indicator that some "designer" decided to make floating and
+     * impossible to hide.
+     */
+    #webrtcIndicator {
+        display: none !important;
     }
 
-    toolbarbutton.bookmark-item:not(.subviewbutton) {
-        min-width: 1.6em;
+    /*
+     * Disable some context menu entries.
+     */
+    #context-navigation {
+        display: none !important;
     }
 
-    #forward-button,
-    #back-button,
-    #context-bookmarklink,
-    #context-inspect-a11y,
-    #context-navigation,
-    #context-openlinkinusercontext-menu,
-    #context-pocket,
-    #context-print-selection,
-    #context-savelink,
-    #context-savelinktopocket,
-    #context-savepage,
-    #context-searchselect,
-    #context-selectall,
-    #context-sendimage,
-    #context-sendlinktodevice,
-    #context-sendlinktodevice,
-    #context-sendpagetodevice,
-    #context-viewsource,
-    #context_bookmarkTab,
-    #context_closeTabOptions,
-    #context_moveTabOptions,
-    #context_reopenInContainer,
-    #context_selectAllTabs,
-    #context_sendTabToDevice,
-    #webrtcIndicator {
+    /*
+     * Disable all animations.
+     */
+    /* * { */
+    /*     transition: none !important; */
+    /* } */
+
+    /*
+     * Remove dumb websites that Mozilla is forced to include.
+     */
+    .search-one-offs {
         display: none !important;
     }
 }
diff --git a/modules/nixfiles/firefox/userContent.css b/modules/nixfiles/firefox/userContent.css
index 04c4c5a..2de8cde 100644
--- a/modules/nixfiles/firefox/userContent.css
+++ b/modules/nixfiles/firefox/userContent.css
@@ -24,6 +24,16 @@
     }
 }
 
+@-moz-document regexp("https?://music\.yandex\.ru.*")
+{
+    .bar-below.bar-below_plus,
+    .footer,
+    .notify,
+    .teaser {
+        display: none !important;
+    }
+}
+
 @-moz-document regexp("https?://(.*.)?gitlab(\..*)?\.(com|org).*")
 {
     body {
@@ -41,7 +51,6 @@
 {
     #org-repo-pin-select-menu,
     #sponsor-button,
-    .btn.ml-2,
     .dropdown-divider,
     .footer,
     .octicon.octicon-info,
@@ -149,7 +158,7 @@
     }
 }
 
-@-moz-document regexp("https?://habr\.com/(ru|en)/(article|company/.*/blog|post)/.*")
+@-moz-document regexp("https?://habr\.com/(ru|en)/(article|company/.*/news|blog|post)/.*")
 {
     .Vue-Toastification__container,
     .tm-article-presenter__footer,
@@ -288,20 +297,15 @@
     }
 }
 
-@-moz-document regexp("https?://music\.yandex\.ru.*")
-{
-    .bar-below.bar-below_plus,
-    .footer,
-    .teaser {
-        display: none !important;
-    }
-}
-
 @-moz-document regexp("https?://(.*\.)?wikipedia\.org/wiki/.*")
 {
     #footer,
     #mp-topbanner,
-    #siteNotice {
+    #siteNotice,
+    #siteSub,
+    .mw-footer-container,
+    .mw-header,
+    .vector-page-toolbar {
         display: none !important;
     }
 
@@ -310,23 +314,10 @@
         font-family: var(--sans-serif-font-family) !important;
         font-size: var(--sans-serif-font-size) !important;
     }
-}
-
-@-moz-document regexp("https?://wikiless\.org/wiki/.*")
-{
-    #footer,
-    #mw-navigation,
-    #mw-page-base {
-        display: none !important;
-    }
 
-    .mw-body {
-        margin-left: auto !important;
-    }
-
-    html,
-    body {
-        font-family: var(--sans-serif-font-family) !important;
-        font-size: var(--sans-serif-font-size) !important;
+    .k-player,
+    body.mediawiki,
+    #dialogEngineContainer #dialogEngineDialog {
+        background: inherit !important;
     }
 }
diff --git a/modules/nixfiles/nmap.nix b/modules/nixfiles/nmap.nix
index 65877be..73f948c 100644
--- a/modules/nixfiles/nmap.nix
+++ b/modules/nixfiles/nmap.nix
@@ -20,24 +20,7 @@ in {
 
         packages = with pkgs; [nmap nmap-formatter];
 
-        activation.regenerateNmapScriptDatabase = with pkgs; ''
-          # TODO Add an update timestamp and pull files only when they are old.
-          # declare -a vulscandbs=(
-          #   "cve"
-          #   "exploitdb"
-          #   "openvas"
-          #   "osvdb"
-          #   "scipvuldb"
-          #   "securityfocus"
-          #   "securitytracker"
-          #   "xforce"
-          # )
-          # for i in "''${vulscandbs[@]}"; do
-          #   ${curl}/bin/curl \
-          #     -o "$HOME/.nmap/scripts/vulscan/$i.csv" \
-          #     "https://www.computec.ch/projekte/vulscan/download/$i.csv"
-          # done
-
+        activation.regenerateNmapScripts = with pkgs; ''
           ${nmap}/bin/nmap --script-updatedb
         '';
       };
@@ -54,6 +37,48 @@ in {
           _complete_alias nmap-vulscan _nmap nmap
         '';
       };
+
+      systemd.user = {
+        services.update-nmap-vulscan-lists = {
+          Service = {
+            ExecStart = let
+              pkg = with pkgs;
+                writeShellApplication {
+                  name = "update-nmap-vulscan-lists";
+                  runtimeInputs = [curl];
+                  text = ''
+                    declare -a vulscandbs=(
+                      "cve"
+                      "exploitdb"
+                      "openvas"
+                      "osvdb"
+                      "scipvuldb"
+                      "securityfocus"
+                      "securitytracker"
+                      "xforce"
+                    )
+                    for i in "''${vulscandbs[@]}"; do
+                      ${curl}/bin/curl \
+                        -o "${config.my.home}/.nmap/scripts/vulscan/$i.csv" \
+                        "https://www.computec.ch/projekte/vulscan/download/$i.csv"
+                    done
+                  '';
+                };
+            in "${pkg}/bin/update-nmap-vulscan-lists";
+          };
+        };
+
+        timers.update-nmap-vulscan-lists = {
+          # TODO Figure out how to check for network-online.target for user
+          # timers.
+          Timer = {
+            OnCalendar = "daily";
+            Persistent = true;
+            Unit = "update-nmap-vulscan-lists.service";
+          };
+          Install.WantedBy = ["timers.target"];
+        };
+      };
     };
   };
 }
diff --git a/modules/nixfiles/profiles/default.nix b/modules/nixfiles/profiles/default.nix
index 7d5ee8e..06ddaf4 100644
--- a/modules/nixfiles/profiles/default.nix
+++ b/modules/nixfiles/profiles/default.nix
@@ -77,7 +77,7 @@ in {
       vim.enable = true;
     };
 
-    time.timeZone = mkDefault "Europe/Moscow";
+    time.timeZone = "Europe/Moscow";
 
     environment.systemPackages = with pkgs; [
       ddrescue
diff --git a/modules/nixfiles/profiles/dev/containers.nix b/modules/nixfiles/profiles/dev/containers.nix
index 7ec6768..9119140 100644
--- a/modules/nixfiles/profiles/dev/containers.nix
+++ b/modules/nixfiles/profiles/dev/containers.nix
@@ -28,21 +28,31 @@ in {
         };
 
         packages = with pkgs; [
+          argocd
           chart-testing
+          clusterctl
           cmctl
           datree
+          fluxcd
           helm
+          istioctl
+          kubeconform
           kubectl
+          kubectl-doctor
+          kubectl-images
+          kubectl-tree
           kubectx
           kubelogin
+          kubent
           kubescape
+          kubeseal
           kubespy
-          lima
           minikube
           skaffold
           skopeo
           stern
           telepresence
+          terraform
           werf
         ];
       };
diff --git a/modules/nixfiles/vim/rc.vim b/modules/nixfiles/vim/rc.vim
index c53b2d2..1657c6d 100644
--- a/modules/nixfiles/vim/rc.vim
+++ b/modules/nixfiles/vim/rc.vim
@@ -8,7 +8,7 @@ let g:netrw_dirhistmax = 0
 
 set autoread
 set backspace=indent,eol,start
-set clipboard=unnamed,unnamedplus
+
 set diffopt+=iwhite
 set hidden
 set history=256
@@ -98,6 +98,10 @@ set tabstop=4
 
 autocmd BufEnter *.* :set colorcolumn=
 
+if has('unnamedplus')
+    set clipboard^=unnamedplus
+endif
+
 if &t_Co == 8 && $TERM !~# '^Eterm'
     set t_Co=16
 endif
diff --git a/modules/nixos/bluetooth.nix b/modules/nixos/bluetooth.nix
index cf92179..76131bf 100644
--- a/modules/nixos/bluetooth.nix
+++ b/modules/nixos/bluetooth.nix
@@ -16,14 +16,9 @@ in {
     hardware.bluetooth = {
       enable = true;
       settings.General.FastConnectable = true;
-    };
-
-    environment = {
-      etc."bluetooth/input.conf".text = generators.toINI {} {
-        General = {
-          IdleTimeout = 15;
-          UserspaceHID = true;
-        };
+      input.General = {
+        IdleTimeout = 15;
+        UserspaceHID = true;
       };
     };
   };
diff --git a/modules/nixos/grafana.nix b/modules/nixos/grafana.nix
index a614502..0b2e210 100644
--- a/modules/nixos/grafana.nix
+++ b/modules/nixos/grafana.nix
@@ -39,7 +39,7 @@ in {
           group = "grafana";
         };
         grafana-smtp-password = {
-          file = "${inputs.self}/secrets/grafana-smtp-password";
+          file = "${inputs.self}/secrets/smtp-password";
           owner = "grafana";
           group = "grafana";
         };
@@ -98,8 +98,8 @@ in {
               auto_assign_org_role = "Viewer";
             };
             security = with config.secrets; {
-              secret_key = grafana-key.path;
-              admin_password = grafana-admin-password.path;
+              secret_key = "$__file{${grafana-key.path}}";
+              admin_password = "$__file{${grafana-admin-password.path}}";
             };
             analytics.reporting_enable = false;
           };
diff --git a/modules/nixos/kde.nix b/modules/nixos/kde.nix
index a430294..66fabbd 100644
--- a/modules/nixos/kde.nix
+++ b/modules/nixos/kde.nix
@@ -30,7 +30,6 @@ in {
         enable = true;
         excludePackages = with pkgs.plasma5Packages; [
           elisa
-          gwenview
           khelpcenter
           okular
           print-manager
diff --git a/modules/nixos/matrix/dendrite.nix b/modules/nixos/matrix/dendrite.nix
index 0fad5f2..6b662b2 100644
--- a/modules/nixos/matrix/dendrite.nix
+++ b/modules/nixos/matrix/dendrite.nix
@@ -11,6 +11,12 @@ in {
   options.nixfiles.modules.matrix.dendrite = {
     enable = mkEnableOption "Dendrite Matrix server";
 
+    port = mkOption {
+      description = "Port.";
+      type = with types; port;
+      default = 8008;
+    };
+
     domain = mkOption {
       type = types.str;
       default = config.networking.domain;
@@ -68,90 +74,129 @@ in {
         };
       };
 
-      services = {
-        dendrite = {
-          enable = true;
-          httpPort = 8008;
-          environmentFile = config.secrets.dendrite-environment-file.path;
-          settings = {
-            version = 2;
-            global = {
-              server_name = cfg.domain;
-              private_key = config.secrets.dendrite-private-key.path;
-              database = {
-                connection_string = "postgresql://${db}@/${db}?host=/run/postgresql";
-                max_open_conns = 64;
-                max_idle_connections = 8;
+      services.postgresql = {
+        ensureDatabases = [db];
+        ensureUsers = [
+          {
+            name = db;
+            ensurePermissions."DATABASE \"${db}\"" = "ALL";
+          }
+        ];
+      };
+
+      systemd.services.dendrite = {
+        description = "Dendrite Matrix homeserver";
+        requires = ["network.target"];
+        wantedBy = ["multi-user.target"];
+        serviceConfig = let
+          needsPrivileges = cfg.port < 1024;
+          capabilities = [""] ++ optionals needsPrivileges ["CAP_NET_BIND_SERVICE"];
+        in {
+          Restart = "on-failure";
+          ExecStartPre = let
+            settings = {
+              version = 2;
+              global = {
+                server_name = cfg.domain;
+                private_key = config.secrets.dendrite-private-key.path;
+                database = {
+                  connection_string = "postgresql://${db}@/${db}?host=/run/postgresql";
+                  max_open_conns = 64;
+                  max_idle_connections = 8;
+                };
+                cache = {
+                  max_size_estimated = "1gb";
+                  max_age = "1h";
+                };
+                trusted_third_party_id_servers = [
+                  "matrix.org"
+                  "nixos.org"
+                  "vector.im"
+                ];
+                presence = {
+                  enable_inbound = false;
+                  enable_outbound = false;
+                };
               };
-              cache = {
-                max_size_estimated = "1gb";
-                max_age = "1h";
+              client_api = {
+                registration_disabled = true;
+                guests_disabled = true;
+                registration_shared_secret = "$REGISTRATION_SHARED_SECRET";
               };
-              trusted_third_party_id_servers = [
-                "matrix.org"
-                "nixos.org"
-                "vector.im"
-              ];
-              presence = {
-                enable_inbound = false;
-                enable_outbound = false;
+              media_api = {
+                base_path = "/var/lib/dendrite/media_store";
+                max_file_size_bytes = 0;
+                dynamic_thumbnails = true;
+                max_thumbnail_generators = 8;
+                thumbnail_sizes = [
+                  {
+                    width = 32;
+                    height = 32;
+                    method = "crop";
+                  }
+                  {
+                    width = 96;
+                    height = 96;
+                    method = "crop";
+                  }
+                  {
+                    width = 640;
+                    height = 480;
+                    method = "scale";
+                  }
+                ];
               };
-            };
-            client_api = {
-              registration_disabled = true;
-              guests_disabled = true;
-              registration_shared_secret = "$REGISTRATION_SHARED_SECRET";
-            };
-            media_api = {
-              max_file_size_bytes = 0;
-              dynamic_thumbnails = true;
-              max_thumbnail_generators = 8;
-              thumbnail_sizes = [
+              logging = [
                 {
-                  width = 32;
-                  height = 32;
-                  method = "crop";
-                }
-                {
-                  width = 96;
-                  height = 96;
-                  method = "crop";
-                }
-                {
-                  width = 640;
-                  height = 480;
-                  method = "scale";
+                  type = "std";
+                  level = "warn";
                 }
               ];
             };
-            logging = [
-              {
-                type = "std";
-                level = "warn";
-              }
+          in
+            concatStringsSep " " [
+              "${pkgs.envsubst}/bin/envsubst"
+              "-i ${(pkgs.formats.yaml {}).generate "dendrite.yaml" settings}"
+              "-o /run/dendrite/dendrite.yaml"
             ];
-          };
-        };
-
-        postgresql = {
-          ensureDatabases = [db];
-          ensureUsers = [
-            {
-              name = db;
-              ensurePermissions."DATABASE \"${db}\"" = "ALL";
-            }
+          ExecStart = concatStringsSep " " [
+            "${pkgs.dendrite}/bin/dendrite-monolith-server"
+            "--config /run/dendrite/dendrite.yaml"
+            "--http-bind-address 127.0.0.1:${toString cfg.port}"
           ];
+          ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID";
+          EnvironmentFile = config.secrets.dendrite-environment-file.path;
+          DynamicUser = true;
+          StateDirectory = "dendrite";
+          RuntimeDirectory = "dendrite";
+          RuntimeDirectoryMode = "0700";
+          AmbientCapabilities = capabilities;
+          CapabilityBoundingSet = capabilities;
+          UMask = "0077";
+          LockPersonality = true;
+          MemoryDenyWriteExecute = true;
+          NoNewPrivileges = true;
+          PrivateDevices = true;
+          PrivateTmp = true;
+          PrivateUsers = !needsPrivileges;
+          ProtectClock = true;
+          ProtectControlGroups = true;
+          ProtectHome = true;
+          ProtectHostname = true;
+          ProtectKernelLogs = true;
+          ProtectKernelModules = true;
+          ProtectKernelTunables = true;
+          ProtectSystem = "strict";
+          ProtectProc = "noaccess";
+          ProcSubset = "pid";
+          RemoveIPC = true;
+          RestrictAddressFamilies = ["AF_UNIX" "AF_INET" "AF_INET6"];
+          RestrictNamespaces = true;
+          RestrictRealtime = true;
+          RestrictSUIDSGID = true;
+          SystemCallArchitectures = "native";
+          SystemCallFilter = ["@system-service" "~@privileged"];
         };
       };
-
-      systemd.services.dendrite.serviceConfig.ExecStart =
-        mkForce
-        (concatStringsSep " " [
-          "${pkgs.dendrite}/bin/dendrite-monolith-server"
-          "--config /run/dendrite/dendrite.yaml"
-          "--http-bind-address 127.0.0.1:${
-            toString config.services.dendrite.httpPort
-          }"
-        ]);
     };
 }
diff --git a/modules/nixos/monitoring/default.nix b/modules/nixos/monitoring/default.nix
index 4ff4c50..57a0d09 100644
--- a/modules/nixos/monitoring/default.nix
+++ b/modules/nixos/monitoring/default.nix
@@ -38,6 +38,13 @@ in {
             access = "proxy";
             url = "https://${loki.domain}";
           }
+          {
+            name = "Alertmanager";
+            type = "alertmanager";
+            access = "proxy";
+            jsonData.implementation = "prometheus";
+            url = "https://${alertmanager.domain}";
+          }
         ];
 
         # https://grafana.com/docs/grafana/latest/administration/provisioning/#dashboards
diff --git a/modules/nixos/openssh.nix b/modules/nixos/openssh.nix
index 9a131d7..c7a144e 100644
--- a/modules/nixos/openssh.nix
+++ b/modules/nixos/openssh.nix
@@ -18,16 +18,16 @@ in {
   };
 
   config = mkIf cfg.server.enable {
-    # TODO Enable on a fresh system.
-    # ark = {
-    #   files = [
-    #     "/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"
-    #   ];
-    #   directories = ["/etc/ssh/authorized_keys.d"];
-    # };
+    # FIXME This is mounted after the activation script is launched.
+    ark = {
+      files = [
+        "/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"
+      ];
+      # directories = ["/etc/ssh/authorized_keys.d"];
+    };
 
     programs.mosh.enable = true;
 
@@ -36,7 +36,6 @@ in {
         enable = true;
         ports = [cfg.server.port];
         settings = {
-          AllowUsers = my.username;
           ClientAliveCountMax = 3;
           ClientAliveInterval = 60;
           KbdInteractiveAuthentication = false;
diff --git a/modules/nixos/profiles/headless.nix b/modules/nixos/profiles/headless.nix
index 9faf531..efe4d03 100644
--- a/modules/nixos/profiles/headless.nix
+++ b/modules/nixos/profiles/headless.nix
@@ -19,7 +19,10 @@ in {
       promtail.enable = true;
     };
 
-    # Pin version to prevent any surprises.
+    # Pin version to prevent any surprises. Try keeping this up-to-date[1] with
+    # the latest LTS release + hardened patches (just in case).
+    #
+    # [1]: https://kernel.org
     boot.kernelPackages = pkgs.linuxPackages_5_15_hardened;
 
     nix = {

Consider giving Nix/NixOS a try! <3