diff --git a/.gitignore b/.gitignore index 2a47a91..73105bb 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,13 @@ -result/ +# Nix build outputs result +result-* .direnv/ -.pre-commit-config.yaml +oci-trantor/ +tailscale-tailnet/ +cloudflare-baduhaidev + +# Personal notes and temporary files +todo.md +notes.md +scratch/ +tmp/ diff --git a/deploy.nix b/deploy.nix new file mode 100644 index 0000000..187c92f --- /dev/null +++ b/deploy.nix @@ -0,0 +1,48 @@ +{ inputs, self, ... }: +{ + flake.deploy = { + remoteBuild = true; + nodes = { + alexandria = { + hostname = "alexandria"; + profiles.system = { + sshUser = "user"; + path = inputs.deploy-rs.lib.x86_64-linux.activate.nixos self.nixosConfigurations.alexandria; + user = "root"; + }; + }; + + trantor = { + hostname = "trantor"; + profiles.system = { + sshUser = "user"; + path = inputs.deploy-rs.lib.aarch64-linux.activate.nixos self.nixosConfigurations.trantor; + user = "root"; + }; + }; + + io = { + hostname = "io"; + profiles = { + system = { + sshUser = "user"; + path = inputs.deploy-rs.lib.x86_64-linux.activate.nixos self.nixosConfigurations.io; + user = "root"; + remoteBuild = false; + }; + user = { + sshUser = "user"; + path = inputs.deploy-rs.lib.x86_64-linux.activate.home-manager self.homeConfigurations."user@io"; + user = "user"; + remoteBuild = false; + }; + }; + }; + }; + }; + perSystem = + { system, ... }: + { + checks = inputs.deploy-rs.lib.${system}.deployChecks self.deploy; + }; +} diff --git a/devShells.nix b/devShells.nix index 254d604..f7e9627 100644 --- a/devShells.nix +++ b/devShells.nix @@ -1,11 +1,13 @@ -{ ... }: +{ inputs, ... }: { perSystem = - { pkgs, ... }: + { pkgs, system, ... }: { devShells.default = pkgs.mkShell { packages = with pkgs; [ + inputs.agenix.packages.${system}.default + deploy-rs nil nixfmt-rfc-style ]; diff --git a/flake.lock b/flake.lock index b19b2ca..27c3580 100644 --- a/flake.lock +++ b/flake.lock @@ -10,11 +10,11 @@ "systems": "systems" }, "locked": { - "lastModified": 1754433428, - "narHash": "sha256-NA/FT2hVhKDftbHSwVnoRTFhes62+7dxZbxj5Gxvghs=", + "lastModified": 1761656077, + "narHash": "sha256-lsNWuj4Z+pE7s0bd2OKicOFq9bK86JE0ZGeKJbNqb94=", "owner": "ryantm", "repo": "agenix", - "rev": "9edb1787864c4f59ae5074ad498b6272b3ec308d", + "rev": "9ba0d85de3eaa7afeab493fed622008b6e4924f5", "type": "github" }, "original": { @@ -23,6 +23,96 @@ "type": "github" } }, + "base16": { + "inputs": { + "fromYaml": "fromYaml" + }, + "locked": { + "lastModified": 1755819240, + "narHash": "sha256-qcMhnL7aGAuFuutH4rq9fvAhCpJWVHLcHVZLtPctPlo=", + "owner": "SenchoPens", + "repo": "base16.nix", + "rev": "75ed5e5e3fce37df22e49125181fa37899c3ccd6", + "type": "github" + }, + "original": { + "owner": "SenchoPens", + "repo": "base16.nix", + "type": "github" + } + }, + "base16-fish": { + "flake": false, + "locked": { + "lastModified": 1754405784, + "narHash": "sha256-l9xHIy+85FN+bEo6yquq2IjD1rSg9fjfjpyGP1W8YXo=", + "owner": "tomyun", + "repo": "base16-fish", + "rev": "23ae20a0093dca0d7b39d76ba2401af0ccf9c561", + "type": "github" + }, + "original": { + "owner": "tomyun", + "repo": "base16-fish", + "rev": "23ae20a0093dca0d7b39d76ba2401af0ccf9c561", + "type": "github" + } + }, + "base16-helix": { + "flake": false, + "locked": { + "lastModified": 1752979451, + "narHash": "sha256-0CQM+FkYy0fOO/sMGhOoNL80ftsAzYCg9VhIrodqusM=", + "owner": "tinted-theming", + "repo": "base16-helix", + "rev": "27cf1e66e50abc622fb76a3019012dc07c678fac", + "type": "github" + }, + "original": { + "owner": "tinted-theming", + "repo": "base16-helix", + "type": "github" + } + }, + "base16-vim": { + "flake": false, + "locked": { + "lastModified": 1732806396, + "narHash": "sha256-e0bpPySdJf0F68Ndanwm+KWHgQiZ0s7liLhvJSWDNsA=", + "owner": "tinted-theming", + "repo": "base16-vim", + "rev": "577fe8125d74ff456cf942c733a85d769afe58b7", + "type": "github" + }, + "original": { + "owner": "tinted-theming", + "repo": "base16-vim", + "rev": "577fe8125d74ff456cf942c733a85d769afe58b7", + "type": "github" + } + }, + "blueprint": { + "inputs": { + "nixpkgs": [ + "nix-ai-tools", + "nixpkgs" + ], + "systems": "systems_3" + }, + "locked": { + "lastModified": 1763308703, + "narHash": "sha256-O9Y+Wer8wOh+N+4kcCK5p/VLrXyX+ktk0/s3HdZvJzk=", + "owner": "numtide", + "repo": "blueprint", + "rev": "5a9bba070f801d63e2af3c9ef00b86b212429f4f", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "blueprint", + "type": "github" + } + }, "darwin": { "inputs": { "nixpkgs": [ @@ -45,100 +135,84 @@ "type": "github" } }, - "dgop": { + "deploy-rs": { "inputs": { - "nixpkgs": [ - "dms", - "nixpkgs" - ] + "flake-compat": "flake-compat", + "nixpkgs": "nixpkgs", + "utils": "utils" }, "locked": { - "lastModified": 1760238269, - "narHash": "sha256-7CeGZM/Z/5Qt3AYByCRohGYGR1MRuXYzTTbkV/JxyAs=", - "owner": "AvengeMedia", - "repo": "dgop", - "rev": "95acdfce2d323e28fa8f5a4f345160962034f2b5", + "lastModified": 1756719547, + "narHash": "sha256-N9gBKUmjwRKPxAafXEk1EGadfk2qDZPBQp4vXWPHINQ=", + "owner": "serokell", + "repo": "deploy-rs", + "rev": "125ae9e3ecf62fb2c0fd4f2d894eb971f1ecaed2", "type": "github" }, "original": { - "owner": "AvengeMedia", - "repo": "dgop", + "owner": "serokell", + "repo": "deploy-rs", "type": "github" } }, "disko": { "inputs": { - "nixpkgs": [ - "nixpkgs-stable" - ] + "nixpkgs": "nixpkgs_2" }, "locked": { - "lastModified": 1736864502, - "narHash": "sha256-ItkIZyebGvNH2dK9jVGzJHGPtb6BSWLN8Gmef16NeY0=", + "lastModified": 1761899396, + "narHash": "sha256-XOpKBp6HLzzMCbzW50TEuXN35zN5WGQREC7n34DcNMM=", "owner": "nix-community", "repo": "disko", - "rev": "0141aabed359f063de7413f80d906e1d98c0c123", + "rev": "6f4cf5abbe318e4cd1e879506f6eeafd83f7b998", "type": "github" }, "original": { "owner": "nix-community", - "ref": "v1.11.0", "repo": "disko", "type": "github" } }, - "dms": { - "inputs": { - "dgop": "dgop", - "dms-cli": "dms-cli", - "nixpkgs": [ - "nixpkgs" - ], - "quickshell": "quickshell" - }, + "firefox-gnome-theme": { + "flake": false, "locked": { - "lastModified": 1760401338, - "narHash": "sha256-aN4qiI9R4ByEucFE/zvJFF8Y456nDe1IXCKu0hvEP+U=", - "owner": "AvengeMedia", - "repo": "DankMaterialShell", - "rev": "07fe2ca4072eb987c8090f388d4979f5006cef52", + "lastModified": 1758112371, + "narHash": "sha256-lizRM2pj6PHrR25yimjyFn04OS4wcdbc38DCdBVa2rk=", + "owner": "rafaelmardojai", + "repo": "firefox-gnome-theme", + "rev": "0909cfe4a2af8d358ad13b20246a350e14c2473d", "type": "github" }, "original": { - "owner": "AvengeMedia", - "repo": "DankMaterialShell", - "type": "github" - } - }, - "dms-cli": { - "inputs": { - "nixpkgs": [ - "dms", - "nixpkgs" - ] - }, - "locked": { - "lastModified": 1760241259, - "narHash": "sha256-DlLGn+4M6tIafoDsHr2WhHG2hrHrC24S2IL3+KAvjEU=", - "owner": "AvengeMedia", - "repo": "danklinux", - "rev": "dae4c3ff4ce0feb930361c399747edb29d081775", - "type": "github" - }, - "original": { - "owner": "AvengeMedia", - "repo": "danklinux", + "owner": "rafaelmardojai", + "repo": "firefox-gnome-theme", "type": "github" } }, "flake-compat": { "flake": false, "locked": { - "lastModified": 1747046372, - "narHash": "sha256-CIVLLkVgvHYbgI2UpXvIIBJ12HWgX+fjA8Xf8PUmqCY=", + "lastModified": 1733328505, + "narHash": "sha256-NeCCThCEP3eCl2l/+27kNNK7QrwZB1IJCrXfrbv5oqU=", "owner": "edolstra", "repo": "flake-compat", - "rev": "9100a0f413b0c601e0533d1d94ffd501ce2e7885", + "rev": "ff81ac966bb2cae68946d5ed5fc4994f96d0ffec", + "type": "github" + }, + "original": { + "owner": "edolstra", + "repo": "flake-compat", + "type": "github" + } + }, + "flake-compat_2": { + "flake": false, + "locked": { + "lastModified": 1761588595, + "narHash": "sha256-XKUZz9zewJNUj46b4AJdiRZJAvSZ0Dqj2BNfXvFlJC4=", + "owner": "edolstra", + "repo": "flake-compat", + "rev": "f387cd2afec9419c8ee37694406ca490c3f34ee5", "type": "github" }, "original": { @@ -152,11 +226,53 @@ "nixpkgs-lib": "nixpkgs-lib" }, "locked": { - "lastModified": 1759362264, - "narHash": "sha256-wfG0S7pltlYyZTM+qqlhJ7GMw2fTF4mLKCIVhLii/4M=", + "lastModified": 1762040540, + "narHash": "sha256-z5PlZ47j50VNF3R+IMS9LmzI5fYRGY/Z5O5tol1c9I4=", "owner": "hercules-ci", "repo": "flake-parts", - "rev": "758cf7296bee11f1706a574c77d072b8a7baa881", + "rev": "0010412d62a25d959151790968765a70c436598b", + "type": "github" + }, + "original": { + "owner": "hercules-ci", + "repo": "flake-parts", + "type": "github" + } + }, + "flake-parts_2": { + "inputs": { + "nixpkgs-lib": [ + "stylix", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1756770412, + "narHash": "sha256-+uWLQZccFHwqpGqr2Yt5VsW/PbeJVTn9Dk6SHWhNRPw=", + "owner": "hercules-ci", + "repo": "flake-parts", + "rev": "4524271976b625a4a605beefd893f270620fd751", + "type": "github" + }, + "original": { + "owner": "hercules-ci", + "repo": "flake-parts", + "type": "github" + } + }, + "flake-parts_3": { + "inputs": { + "nixpkgs-lib": [ + "terranix", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1736143030, + "narHash": "sha256-+hu54pAoLDEZT9pjHlqL9DNzWz0NbUn8NEAHP7PQPzU=", + "owner": "hercules-ci", + "repo": "flake-parts", + "rev": "b905f6fc23a9051a6e1b741e1438dbfc0634c6de", "type": "github" }, "original": { @@ -167,7 +283,7 @@ }, "flake-utils": { "inputs": { - "systems": "systems_2" + "systems": "systems_4" }, "locked": { "lastModified": 1731533236, @@ -183,6 +299,57 @@ "type": "github" } }, + "flake-utils_2": { + "inputs": { + "systems": "systems_8" + }, + "locked": { + "lastModified": 1731533236, + "narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "11707dc2f618dd54ca8739b309ec4fc024de578b", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, + "fromYaml": { + "flake": false, + "locked": { + "lastModified": 1731966426, + "narHash": "sha256-lq95WydhbUTWig/JpqiB7oViTcHFP8Lv41IGtayokA8=", + "owner": "SenchoPens", + "repo": "fromYaml", + "rev": "106af9e2f715e2d828df706c386a685698f3223b", + "type": "github" + }, + "original": { + "owner": "SenchoPens", + "repo": "fromYaml", + "type": "github" + } + }, + "gnome-shell": { + "flake": false, + "locked": { + "lastModified": 1748186689, + "narHash": "sha256-UaD7Y9f8iuLBMGHXeJlRu6U1Ggw5B9JnkFs3enZlap0=", + "owner": "GNOME", + "repo": "gnome-shell", + "rev": "8c88f917db0f1f0d80fa55206c863d3746fa18d0", + "type": "github" + }, + "original": { + "owner": "GNOME", + "ref": "48.2", + "repo": "gnome-shell", + "type": "github" + } + }, "home-manager": { "inputs": { "nixpkgs": [ @@ -204,27 +371,6 @@ "type": "github" } }, - "home-manager-stable": { - "inputs": { - "nixpkgs": [ - "nixpkgs-stable" - ] - }, - "locked": { - "lastModified": 1758463745, - "narHash": "sha256-uhzsV0Q0I9j2y/rfweWeGif5AWe0MGrgZ/3TjpDYdGA=", - "owner": "nix-community", - "repo": "home-manager", - "rev": "3b955f5f0a942f9f60cdc9cacb7844335d0f21c3", - "type": "github" - }, - "original": { - "owner": "nix-community", - "ref": "release-25.05", - "repo": "home-manager", - "type": "github" - } - }, "home-manager_2": { "inputs": { "nixpkgs": [ @@ -232,11 +378,11 @@ ] }, "locked": { - "lastModified": 1760033152, - "narHash": "sha256-e2g07P6SBJrYdRWw5JEJgh8ssccr+jigYR9p4GS0tME=", + "lastModified": 1762178366, + "narHash": "sha256-I+8yE5HVR2SFcHnW0771psQ/zn0qVzsKHY/gUM0nEVM=", "owner": "nix-community", "repo": "home-manager", - "rev": "5d61767c8dee7f9c66991335795dbca9e801c25a", + "rev": "8c824254b1ed9e797f6235fc3c62f365893c561a", "type": "github" }, "original": { @@ -246,6 +392,27 @@ "type": "github" } }, + "home-manager_3": { + "inputs": { + "nixpkgs": [ + "zen-browser", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1752603129, + "narHash": "sha256-S+wmHhwNQ5Ru689L2Gu8n1OD6s9eU9n9mD827JNR+kw=", + "owner": "nix-community", + "repo": "home-manager", + "rev": "e8c19a3cec2814c754f031ab3ae7316b64da085b", + "type": "github" + }, + "original": { + "owner": "nix-community", + "repo": "home-manager", + "type": "github" + } + }, "impermanence": { "locked": { "lastModified": 1737831083, @@ -261,6 +428,102 @@ "type": "github" } }, + "niri": { + "inputs": { + "nixpkgs": "nixpkgs_3", + "rust-overlay": "rust-overlay" + }, + "locked": { + "lastModified": 1760963745, + "narHash": "sha256-FVf9YFw2wQnMAxvMxEk+vFakXhPQUSapDpGmlLzAxjg=", + "owner": "baduhai", + "repo": "niri", + "rev": "dd3e3d1009991ecd87ab7253c9e7696acf2bc943", + "type": "github" + }, + "original": { + "owner": "baduhai", + "ref": "auto-center-when-space-available", + "repo": "niri", + "type": "github" + } + }, + "niri-flake": { + "inputs": { + "niri-stable": "niri-stable", + "niri-unstable": "niri-unstable", + "nixpkgs": "nixpkgs_4", + "nixpkgs-stable": "nixpkgs-stable", + "xwayland-satellite-stable": "xwayland-satellite-stable", + "xwayland-satellite-unstable": "xwayland-satellite-unstable" + }, + "locked": { + "lastModified": 1762152856, + "narHash": "sha256-U3SDbk7tIwLChpvb3FL66o8V0byaQ2RGMiy/3oLdxTI=", + "owner": "sodiboo", + "repo": "niri-flake", + "rev": "df17789929ac80f4157b15724450db6a303a6dc9", + "type": "github" + }, + "original": { + "owner": "sodiboo", + "repo": "niri-flake", + "type": "github" + } + }, + "niri-stable": { + "flake": false, + "locked": { + "lastModified": 1756556321, + "narHash": "sha256-RLD89dfjN0RVO86C/Mot0T7aduCygPGaYbog566F0Qo=", + "owner": "YaLTeR", + "repo": "niri", + "rev": "01be0e65f4eb91a9cd624ac0b76aaeab765c7294", + "type": "github" + }, + "original": { + "owner": "YaLTeR", + "ref": "v25.08", + "repo": "niri", + "type": "github" + } + }, + "niri-unstable": { + "flake": false, + "locked": { + "lastModified": 1762146685, + "narHash": "sha256-anRlNG6t7esBbF1+ALDeathVBSclA0PEL52Vo0WnN5g=", + "owner": "YaLTeR", + "repo": "niri", + "rev": "a2ca2b3c866bc781b12c334a9f949b3db6d7c943", + "type": "github" + }, + "original": { + "owner": "YaLTeR", + "repo": "niri", + "type": "github" + } + }, + "nix-ai-tools": { + "inputs": { + "blueprint": "blueprint", + "nixpkgs": "nixpkgs_5", + "treefmt-nix": "treefmt-nix" + }, + "locked": { + "lastModified": 1763412165, + "narHash": "sha256-n6bChFrCf2/uHzTsZdABUt1+Ua3n0jinNfamHd5DmBA=", + "owner": "numtide", + "repo": "nix-ai-tools", + "rev": "a2dfa932ed37e5b6224b39b4982c85cd8ebcca14", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "nix-ai-tools", + "type": "github" + } + }, "nix-flatpak": { "locked": { "lastModified": 1754777568, @@ -277,11 +540,31 @@ "type": "github" } }, + "nix-index-database": { + "inputs": { + "nixpkgs": [ + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1762055842, + "narHash": "sha256-Pu1v3mlFhRzZiSxVHb2/i/f5yeYyRNqr0RvEUJ4UgHo=", + "owner": "nix-community", + "repo": "nix-index-database", + "rev": "359ff6333a7b0b60819d4c20ed05a3a1f726771f", + "type": "github" + }, + "original": { + "owner": "nix-community", + "repo": "nix-index-database", + "type": "github" + } + }, "nix-options-doc": { "inputs": { "flake-utils": "flake-utils", - "nixpkgs": "nixpkgs", - "rust-overlay": "rust-overlay" + "nixpkgs": "nixpkgs_6", + "rust-overlay": "rust-overlay_2" }, "locked": { "lastModified": 1742115705, @@ -300,16 +583,16 @@ }, "nixos-cli": { "inputs": { - "flake-compat": "flake-compat", + "flake-compat": "flake-compat_2", "nix-options-doc": "nix-options-doc", - "nixpkgs": "nixpkgs_2" + "nixpkgs": "nixpkgs_7" }, "locked": { - "lastModified": 1759846470, - "narHash": "sha256-cFA87F149mDeogKjty5Kbk6Qy/RhMBr1fM3qEFbdTIg=", + "lastModified": 1761970410, + "narHash": "sha256-IUm2nkbKlDkG94ruTmIYLERpBn6gXydm3scZIKzpcKs=", "owner": "nix-community", "repo": "nixos-cli", - "rev": "437b586743c3d06b0a72893097395b10e70a2b7b", + "rev": "5c259f72ae1eaa00b99354d81130d8fddb7f9a7a", "type": "github" }, "original": { @@ -319,6 +602,165 @@ } }, "nixpkgs": { + "locked": { + "lastModified": 1743014863, + "narHash": "sha256-jAIUqsiN2r3hCuHji80U7NNEafpIMBXiwKlSrjWMlpg=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "bd3bac8bfb542dbde7ffffb6987a1a1f9d41699f", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixpkgs-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs-lib": { + "locked": { + "lastModified": 1761765539, + "narHash": "sha256-b0yj6kfvO8ApcSE+QmA6mUfu8IYG6/uU28OFn4PaC8M=", + "owner": "nix-community", + "repo": "nixpkgs.lib", + "rev": "719359f4562934ae99f5443f20aa06c2ffff91fc", + "type": "github" + }, + "original": { + "owner": "nix-community", + "repo": "nixpkgs.lib", + "type": "github" + } + }, + "nixpkgs-stable": { + "locked": { + "lastModified": 1761999846, + "narHash": "sha256-IYlYnp4O4dzEpL77BD/lj5NnJy2J8qbHkNSFiPBCbqo=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "3de8f8d73e35724bf9abef41f1bdbedda1e14a31", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixos-25.05", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs-stable_2": { + "locked": { + "lastModified": 1761999846, + "narHash": "sha256-IYlYnp4O4dzEpL77BD/lj5NnJy2J8qbHkNSFiPBCbqo=", + "owner": "nixos", + "repo": "nixpkgs", + "rev": "3de8f8d73e35724bf9abef41f1bdbedda1e14a31", + "type": "github" + }, + "original": { + "owner": "nixos", + "ref": "nixos-25.05", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs_10": { + "locked": { + "lastModified": 1762111121, + "narHash": "sha256-4vhDuZ7OZaZmKKrnDpxLZZpGIJvAeMtK6FKLJYUtAdw=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "b3d51a0365f6695e7dd5cdf3e180604530ed33b4", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixos-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs_11": { + "locked": { + "lastModified": 1755615617, + "narHash": "sha256-HMwfAJBdrr8wXAkbGhtcby1zGFvs+StOp19xNsbqdOg=", + "owner": "nixos", + "repo": "nixpkgs", + "rev": "20075955deac2583bb12f07151c2df830ef346b4", + "type": "github" + }, + "original": { + "owner": "nixos", + "ref": "nixos-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs_2": { + "locked": { + "lastModified": 1752596105, + "narHash": "sha256-lFNVsu/mHLq3q11MuGkMhUUoSXEdQjCHvpReaGP1S2k=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "dab3a6e781554f965bde3def0aa2fda4eb8f1708", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixpkgs-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs_3": { + "locked": { + "lastModified": 1757967192, + "narHash": "sha256-/aA9A/OBmnuOMgwfzdsXRusqzUpd8rQnQY8jtrHK+To=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "0d7c15863b251a7a50265e57c1dca1a7add2e291", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixpkgs-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs_4": { + "locked": { + "lastModified": 1761907660, + "narHash": "sha256-kJ8lIZsiPOmbkJypG+B5sReDXSD1KGu2VEPNqhRa/ew=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "2fb006b87f04c4d3bdf08cfdbc7fab9c13d94a15", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixos-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs_5": { + "locked": { + "lastModified": 1763312402, + "narHash": "sha256-3YJkOBrFpmcusnh7i8GXXEyh7qZG/8F5z5+717550Hk=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "85a6c4a07faa12aaccd81b36ba9bfc2bec974fa1", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixpkgs-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs_6": { "locked": { "lastModified": 1740695751, "narHash": "sha256-D+R+kFxy1KsheiIzkkx/6L63wEHBYX21OIwlFV8JvDs=", @@ -334,44 +776,13 @@ "type": "github" } }, - "nixpkgs-lib": { + "nixpkgs_7": { "locked": { - "lastModified": 1754788789, - "narHash": "sha256-x2rJ+Ovzq0sCMpgfgGaaqgBSwY+LST+WbZ6TytnT9Rk=", - "owner": "nix-community", - "repo": "nixpkgs.lib", - "rev": "a73b9c743612e4244d865a2fdee11865283c04e6", - "type": "github" - }, - "original": { - "owner": "nix-community", - "repo": "nixpkgs.lib", - "type": "github" - } - }, - "nixpkgs-stable": { - "locked": { - "lastModified": 1759735786, - "narHash": "sha256-a0+h02lyP2KwSNrZz4wLJTu9ikujNsTWIC874Bv7IJ0=", - "owner": "nixos", - "repo": "nixpkgs", - "rev": "20c4598c84a671783f741e02bf05cbfaf4907cff", - "type": "github" - }, - "original": { - "owner": "nixos", - "ref": "nixos-25.05", - "repo": "nixpkgs", - "type": "github" - } - }, - "nixpkgs_2": { - "locked": { - "lastModified": 1759070547, - "narHash": "sha256-JVZl8NaVRYb0+381nl7LvPE+A774/dRpif01FKLrYFQ=", + "lastModified": 1761880412, + "narHash": "sha256-QoJjGd4NstnyOG4mm4KXF+weBzA2AH/7gn1Pmpfcb0A=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "647e5c14cbd5067f44ac86b74f014962df460840", + "rev": "a7fc11be66bdfb5cdde611ee5ce381c183da8386", "type": "github" }, "original": { @@ -381,13 +792,13 @@ "type": "github" } }, - "nixpkgs_3": { + "nixpkgs_8": { "locked": { - "lastModified": 1759831965, - "narHash": "sha256-vgPm2xjOmKdZ0xKA6yLXPJpjOtQPHfaZDRtH+47XEBo=", + "lastModified": 1761907660, + "narHash": "sha256-kJ8lIZsiPOmbkJypG+B5sReDXSD1KGu2VEPNqhRa/ew=", "owner": "nixos", "repo": "nixpkgs", - "rev": "c9b6fb798541223bbb396d287d16f43520250518", + "rev": "2fb006b87f04c4d3bdf08cfdbc7fab9c13d94a15", "type": "github" }, "original": { @@ -397,43 +808,135 @@ "type": "github" } }, - "quickshell": { + "nixpkgs_9": { + "locked": { + "lastModified": 1758690382, + "narHash": "sha256-NY3kSorgqE5LMm1LqNwGne3ZLMF2/ILgLpFr1fS4X3o=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "e643668fd71b949c53f8626614b21ff71a07379d", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixos-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "noctalia": { "inputs": { "nixpkgs": [ - "dms", + "nixpkgs" + ], + "quickshell": "quickshell", + "systems": "systems_5" + }, + "locked": { + "lastModified": 1762156721, + "narHash": "sha256-gHfzrTDSnNC5yRJwkZfP55fPHUc8DuB4OQEIBSQSs18=", + "owner": "noctalia-dev", + "repo": "noctalia-shell", + "rev": "5ca5aa602f58a8e0e73fedbef351f1cdf8cbe981", + "type": "github" + }, + "original": { + "owner": "noctalia-dev", + "repo": "noctalia-shell", + "type": "github" + } + }, + "nur": { + "inputs": { + "flake-parts": [ + "stylix", + "flake-parts" + ], + "nixpkgs": [ + "stylix", "nixpkgs" ] }, "locked": { - "lastModified": 1760228179, - "narHash": "sha256-4Z6k7lv3Zcgk3K+4h60LpqB9wCkR+utkYERU735U068=", + "lastModified": 1758998580, + "narHash": "sha256-VLx0z396gDCGSiowLMFz5XRO/XuNV+4EnDYjdJhHvUk=", + "owner": "nix-community", + "repo": "NUR", + "rev": "ba8d9c98f5f4630bcb0e815ab456afd90c930728", + "type": "github" + }, + "original": { + "owner": "nix-community", + "repo": "NUR", + "type": "github" + } + }, + "quickshell": { + "inputs": { + "nixpkgs": [ + "noctalia", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1761821581, + "narHash": "sha256-nLuc6jA7z+H/6bHPEBSOYPbz7RtvNCZiTKmYItJuBmM=", "ref": "refs/heads/master", - "rev": "c9d3ffb6043c5bf3f3009202bad7e0e5132c4a25", - "revCount": 693, + "rev": "db1777c20b936a86528c1095cbcb1ebd92801402", + "revCount": 699, "type": "git", - "url": "https://git.outfoxxed.me/quickshell/quickshell" + "url": "https://git.outfoxxed.me/outfoxxed/quickshell" }, "original": { "type": "git", - "url": "https://git.outfoxxed.me/quickshell/quickshell" + "url": "https://git.outfoxxed.me/outfoxxed/quickshell" } }, "root": { "inputs": { "agenix": "agenix", + "deploy-rs": "deploy-rs", "disko": "disko", - "dms": "dms", "flake-parts": "flake-parts", "home-manager": "home-manager_2", - "home-manager-stable": "home-manager-stable", "impermanence": "impermanence", + "niri": "niri", + "niri-flake": "niri-flake", + "nix-ai-tools": "nix-ai-tools", "nix-flatpak": "nix-flatpak", + "nix-index-database": "nix-index-database", "nixos-cli": "nixos-cli", - "nixpkgs": "nixpkgs_3", - "nixpkgs-stable": "nixpkgs-stable" + "nixpkgs": "nixpkgs_8", + "nixpkgs-stable": "nixpkgs-stable_2", + "noctalia": "noctalia", + "stylix": "stylix", + "terranix": "terranix", + "vicinae": "vicinae", + "zen-browser": "zen-browser" } }, "rust-overlay": { + "inputs": { + "nixpkgs": [ + "niri", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1757989933, + "narHash": "sha256-9cpKYWWPCFhgwQTww8S94rTXgg8Q8ydFv9fXM6I8xQM=", + "owner": "oxalica", + "repo": "rust-overlay", + "rev": "8249aa3442fb9b45e615a35f39eca2fe5510d7c3", + "type": "github" + }, + "original": { + "owner": "oxalica", + "repo": "rust-overlay", + "type": "github" + } + }, + "rust-overlay_2": { "inputs": { "nixpkgs": [ "nixos-cli", @@ -455,6 +958,38 @@ "type": "github" } }, + "stylix": { + "inputs": { + "base16": "base16", + "base16-fish": "base16-fish", + "base16-helix": "base16-helix", + "base16-vim": "base16-vim", + "firefox-gnome-theme": "firefox-gnome-theme", + "flake-parts": "flake-parts_2", + "gnome-shell": "gnome-shell", + "nixpkgs": "nixpkgs_9", + "nur": "nur", + "systems": "systems_6", + "tinted-foot": "tinted-foot", + "tinted-kitty": "tinted-kitty", + "tinted-schemes": "tinted-schemes", + "tinted-tmux": "tinted-tmux", + "tinted-zed": "tinted-zed" + }, + "locked": { + "lastModified": 1762101397, + "narHash": "sha256-wGiL2K3kAyBBmIZpJEskaSIgyzzpg0zwfvri+Sy6/CI=", + "owner": "danth", + "repo": "stylix", + "rev": "8c0640d5722a02178c8ee80a62c5f019cab4b3c1", + "type": "github" + }, + "original": { + "owner": "danth", + "repo": "stylix", + "type": "github" + } + }, "systems": { "locked": { "lastModified": 1681028828, @@ -484,6 +1019,309 @@ "repo": "default", "type": "github" } + }, + "systems_3": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } + }, + "systems_4": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } + }, + "systems_5": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } + }, + "systems_6": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } + }, + "systems_7": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } + }, + "systems_8": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } + }, + "terranix": { + "inputs": { + "flake-parts": "flake-parts_3", + "nixpkgs": [ + "nixpkgs" + ], + "systems": "systems_7" + }, + "locked": { + "lastModified": 1762161791, + "narHash": "sha256-J1L1yP29NVBJO04LA/JGM6kwhnjeNhEsX0tLFnuN3FI=", + "owner": "terranix", + "repo": "terranix", + "rev": "a79a47b4617dfb92184e2e5b8f5aa6fc06c659c8", + "type": "github" + }, + "original": { + "owner": "terranix", + "repo": "terranix", + "type": "github" + } + }, + "tinted-foot": { + "flake": false, + "locked": { + "lastModified": 1726913040, + "narHash": "sha256-+eDZPkw7efMNUf3/Pv0EmsidqdwNJ1TaOum6k7lngDQ=", + "owner": "tinted-theming", + "repo": "tinted-foot", + "rev": "fd1b924b6c45c3e4465e8a849e67ea82933fcbe4", + "type": "github" + }, + "original": { + "owner": "tinted-theming", + "repo": "tinted-foot", + "rev": "fd1b924b6c45c3e4465e8a849e67ea82933fcbe4", + "type": "github" + } + }, + "tinted-kitty": { + "flake": false, + "locked": { + "lastModified": 1735730497, + "narHash": "sha256-4KtB+FiUzIeK/4aHCKce3V9HwRvYaxX+F1edUrfgzb8=", + "owner": "tinted-theming", + "repo": "tinted-kitty", + "rev": "de6f888497f2c6b2279361bfc790f164bfd0f3fa", + "type": "github" + }, + "original": { + "owner": "tinted-theming", + "repo": "tinted-kitty", + "type": "github" + } + }, + "tinted-schemes": { + "flake": false, + "locked": { + "lastModified": 1757716333, + "narHash": "sha256-d4km8W7w2zCUEmPAPUoLk1NlYrGODuVa3P7St+UrqkM=", + "owner": "tinted-theming", + "repo": "schemes", + "rev": "317a5e10c35825a6c905d912e480dfe8e71c7559", + "type": "github" + }, + "original": { + "owner": "tinted-theming", + "repo": "schemes", + "type": "github" + } + }, + "tinted-tmux": { + "flake": false, + "locked": { + "lastModified": 1757811970, + "narHash": "sha256-n5ZJgmzGZXOD9pZdAl1OnBu3PIqD+X3vEBUGbTi4JiI=", + "owner": "tinted-theming", + "repo": "tinted-tmux", + "rev": "d217ba31c846006e9e0ae70775b0ee0f00aa6b1e", + "type": "github" + }, + "original": { + "owner": "tinted-theming", + "repo": "tinted-tmux", + "type": "github" + } + }, + "tinted-zed": { + "flake": false, + "locked": { + "lastModified": 1757811247, + "narHash": "sha256-4EFOUyLj85NRL3OacHoLGEo0wjiRJzfsXtR4CZWAn6w=", + "owner": "tinted-theming", + "repo": "base16-zed", + "rev": "824fe0aacf82b3c26690d14e8d2cedd56e18404e", + "type": "github" + }, + "original": { + "owner": "tinted-theming", + "repo": "base16-zed", + "type": "github" + } + }, + "treefmt-nix": { + "inputs": { + "nixpkgs": [ + "nix-ai-tools", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1762938485, + "narHash": "sha256-AlEObg0syDl+Spi4LsZIBrjw+snSVU4T8MOeuZJUJjM=", + "owner": "numtide", + "repo": "treefmt-nix", + "rev": "5b4ee75aeefd1e2d5a1cc43cf6ba65eba75e83e4", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "treefmt-nix", + "type": "github" + } + }, + "utils": { + "inputs": { + "systems": "systems_2" + }, + "locked": { + "lastModified": 1731533236, + "narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "11707dc2f618dd54ca8739b309ec4fc024de578b", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, + "vicinae": { + "inputs": { + "flake-utils": "flake-utils_2", + "nixpkgs": "nixpkgs_10" + }, + "locked": { + "lastModified": 1762709887, + "narHash": "sha256-8BoGGsWfkS/2ODBSCYd5HJNFGuLY8fFl27rXmWClXQw=", + "owner": "vicinaehq", + "repo": "vicinae", + "rev": "54722e36137d8273ef0a5db37776fb8302c79238", + "type": "github" + }, + "original": { + "owner": "vicinaehq", + "repo": "vicinae", + "type": "github" + } + }, + "xwayland-satellite-stable": { + "flake": false, + "locked": { + "lastModified": 1755491097, + "narHash": "sha256-m+9tUfsmBeF2Gn4HWa6vSITZ4Gz1eA1F5Kh62B0N4oE=", + "owner": "Supreeeme", + "repo": "xwayland-satellite", + "rev": "388d291e82ffbc73be18169d39470f340707edaa", + "type": "github" + }, + "original": { + "owner": "Supreeeme", + "ref": "v0.7", + "repo": "xwayland-satellite", + "type": "github" + } + }, + "xwayland-satellite-unstable": { + "flake": false, + "locked": { + "lastModified": 1761622056, + "narHash": "sha256-fBrUszJXmB4MY+wf3QsCnqWHcz7u7fLq0QMAWCltIQg=", + "owner": "Supreeeme", + "repo": "xwayland-satellite", + "rev": "0728d59ff6463a502e001fb090f6eb92dbc04756", + "type": "github" + }, + "original": { + "owner": "Supreeeme", + "repo": "xwayland-satellite", + "type": "github" + } + }, + "zen-browser": { + "inputs": { + "home-manager": "home-manager_3", + "nixpkgs": "nixpkgs_11" + }, + "locked": { + "lastModified": 1762131860, + "narHash": "sha256-sIPhzkDrfe6ptthZiwoxQyO6rKd9PgJnl+LOyythQkI=", + "owner": "0xc000022070", + "repo": "zen-browser-flake", + "rev": "10e69cb268b1d3dc91135e72f5462b2acfbcc3aa", + "type": "github" + }, + "original": { + "owner": "0xc000022070", + "repo": "zen-browser-flake", + "type": "github" + } } }, "root": "root", diff --git a/flake.nix b/flake.nix index 0d826a1..c5c3880 100644 --- a/flake.nix +++ b/flake.nix @@ -2,40 +2,57 @@ description = "My nix hosts"; inputs = { + flake-parts.url = "github:hercules-ci/flake-parts"; + nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable"; nixpkgs-stable.url = "github:nixos/nixpkgs/nixos-25.05"; - flake-parts.url = "github:hercules-ci/flake-parts"; - home-manager = { url = "github:nix-community/home-manager/master"; inputs.nixpkgs.follows = "nixpkgs"; }; - home-manager-stable = { - url = "github:nix-community/home-manager/release-25.05"; - inputs.nixpkgs.follows = "nixpkgs-stable"; - }; agenix = { url = "github:ryantm/agenix"; inputs.nixpkgs.follows = "nixpkgs-stable"; }; - disko = { - url = "github:nix-community/disko?ref=v1.11.0"; - inputs.nixpkgs.follows = "nixpkgs-stable"; - }; + disko.url = "github:nix-community/disko"; - dms = { - url = "github:AvengeMedia/DankMaterialShell"; + noctalia = { + url = "github:noctalia-dev/noctalia-shell"; inputs.nixpkgs.follows = "nixpkgs"; }; + stylix.url = "github:danth/stylix"; + nixos-cli.url = "github:nix-community/nixos-cli"; nix-flatpak.url = "github:gmodena/nix-flatpak/main"; + zen-browser.url = "github:0xc000022070/zen-browser-flake"; + impermanence.url = "github:nix-community/impermanence"; + + deploy-rs.url = "github:serokell/deploy-rs"; + + niri-flake.url = "github:sodiboo/niri-flake"; + + niri.url = "github:baduhai/niri/auto-center-when-space-available"; + + nix-index-database = { + url = "github:nix-community/nix-index-database"; + inputs.nixpkgs.follows = "nixpkgs"; + }; + + terranix = { + url = "github:terranix/terranix"; + inputs.nixpkgs.follows = "nixpkgs"; + }; + + nix-ai-tools.url = "github:numtide/nix-ai-tools"; + + vicinae.url = "github:vicinaehq/vicinae"; }; outputs = @@ -47,11 +64,14 @@ ]; imports = [ + ./deploy.nix ./devShells.nix ./homeConfigurations.nix ./nixosConfigurations.nix + ./nixosModules.nix ./overlays.nix ./packages.nix + ./terranixConfigurations.nix ]; }; } diff --git a/homeConfigurations.nix b/homeConfigurations.nix index 112783f..296abfa 100644 --- a/homeConfigurations.nix +++ b/homeConfigurations.nix @@ -1,33 +1,41 @@ { inputs, ... }: + let lib = inputs.nixpkgs.lib; utils = import ./utils.nix { inherit inputs lib; }; - inherit (utils) mkUser; + inherit (utils) mkHome; in + { flake.homeConfigurations = { - "user@rotterdam" = mkUser { + "user@rotterdam" = mkHome { username = "user"; + hostname = "rotterdam"; tags = [ - "btop" "desktop" + "btop" + "comma" "direnv" "gaming" "helix" "obs-studio" "starship" + "stylix" "tmux" ]; }; - "user@io" = mkUser { + "user@io" = mkHome { username = "user"; + hostname = "io"; tags = [ - "btop" "desktop" + "btop" + "comma" "direnv" "helix" "starship" + "stylix" "tmux" ]; }; diff --git a/hosts/alexandria/firewall.nix b/hosts/alexandria/firewall.nix deleted file mode 100644 index f6fded2..0000000 --- a/hosts/alexandria/firewall.nix +++ /dev/null @@ -1,11 +0,0 @@ -{ ... }: - -{ - networking.firewall = { - allowedTCPPorts = [ - 80 - 443 - ]; - allowedUDPPorts = [ ]; - }; -} diff --git a/hosts/alexandria/forgejo.nix b/hosts/alexandria/forgejo.nix deleted file mode 100644 index 909d1d1..0000000 --- a/hosts/alexandria/forgejo.nix +++ /dev/null @@ -1,35 +0,0 @@ -{ - config, - lib, - inputs, - ... -}: -let - utils = import ../../utils.nix { inherit inputs lib; }; - inherit (utils) mkNginxVHosts; -in -{ - services.forgejo = { - enable = true; - repositoryRoot = "/data/forgejo"; - settings = { - session.COOKIE_SECURE = true; - server = { - PROTOCOL = "http+unix"; - DOMAIN = "git.baduhai.dev"; - ROOT_URL = "https://git.baduhai.dev"; - OFFLINE_MODE = true; # disable use of CDNs - SSH_DOMAIN = "baduhai.dev"; - }; - log.LEVEL = "Warn"; - mailer.ENABLED = false; - actions.ENABLED = false; - }; - }; - - services.nginx.virtualHosts = mkNginxVHosts { - acmeHost = "baduhai.dev"; - domains."git.baduhai.dev".locations."/".proxyPass = - "http://unix:${config.services.forgejo.settings.server.HTTP_ADDR}:/"; - }; -} diff --git a/hosts/alexandria/jellyfin.nix b/hosts/alexandria/jellyfin.nix index 9555c89..6ceac09 100644 --- a/hosts/alexandria/jellyfin.nix +++ b/hosts/alexandria/jellyfin.nix @@ -10,7 +10,6 @@ in }; services.nginx.virtualHosts = mkNginxVHosts { - acmeHost = "baduhai.dev"; domains."jellyfin.baduhai.dev".locations."/".proxyPass = "http://127.0.0.1:8096/"; }; } diff --git a/hosts/alexandria/kanidm.nix b/hosts/alexandria/kanidm.nix new file mode 100644 index 0000000..eaaa9b9 --- /dev/null +++ b/hosts/alexandria/kanidm.nix @@ -0,0 +1,83 @@ +{ + config, + lib, + inputs, + pkgs, + ... +}: + +let + utils = import ../../utils.nix { inherit inputs lib; }; + inherit (utils) mkNginxVHosts; + kanidmCertDir = "/var/lib/kanidm/certs"; +in + +{ + services.kanidm = { + enableServer = true; + enableClient = true; + package = pkgs.kanidm; + + serverSettings = { + domain = "auth.baduhai.dev"; + origin = "https://auth.baduhai.dev"; + bindaddress = "127.0.0.1:8443"; + ldapbindaddress = "127.0.0.1:636"; + trust_x_forward_for = true; + # Use self-signed certificates for internal TLS + tls_chain = "${kanidmCertDir}/cert.pem"; + tls_key = "${kanidmCertDir}/key.pem"; + }; + + clientSettings = { + uri = "https://auth.baduhai.dev"; + }; + }; + + services.nginx.virtualHosts = mkNginxVHosts { + domains."auth.baduhai.dev" = { + locations."/" = { + proxyPass = "https://127.0.0.1:8443"; + extraConfig = '' + proxy_ssl_verify off; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_set_header Host $host; + ''; + }; + }; + }; + + networking.firewall.allowedTCPPorts = [ 636 ]; + + # Generate self-signed certificates for kanidm's internal TLS + systemd.services.kanidm-generate-certs = { + description = "Generate self-signed TLS certificates for Kanidm"; + wantedBy = [ "multi-user.target" ]; + before = [ "kanidm.service" ]; + serviceConfig = { + Type = "oneshot"; + RemainAfterExit = true; + }; + script = '' + mkdir -p ${kanidmCertDir} + if [ ! -f ${kanidmCertDir}/key.pem ]; then + ${pkgs.openssl}/bin/openssl req -x509 -newkey rsa:4096 \ + -keyout ${kanidmCertDir}/key.pem \ + -out ${kanidmCertDir}/cert.pem \ + -days 3650 -nodes \ + -subj "/CN=localhost" \ + -addext "subjectAltName=DNS:localhost,IP:127.0.0.1" + chown -R kanidm:kanidm ${kanidmCertDir} + chmod 600 ${kanidmCertDir}/key.pem + chmod 644 ${kanidmCertDir}/cert.pem + fi + ''; + }; + + # Ensure certificate generation runs before kanidm starts + systemd.services.kanidm = { + after = [ "kanidm-generate-certs.service" ]; + wants = [ "kanidm-generate-certs.service" ]; + }; +} diff --git a/hosts/alexandria/librespeed.nix b/hosts/alexandria/librespeed.nix deleted file mode 100644 index 79353bd..0000000 --- a/hosts/alexandria/librespeed.nix +++ /dev/null @@ -1,22 +0,0 @@ -{ lib, inputs, ... }: -let - utils = import ../../utils.nix { inherit inputs lib; }; - inherit (utils) mkNginxVHosts; -in -{ - virtualisation.oci-containers.containers."librespeed" = { - image = "lscr.io/linuxserver/librespeed:latest"; - environment = { - TZ = "America/Bahia"; - }; - extraOptions = [ - "--pull=newer" - "--label=io.containers.autoupdate=registry" - ]; - }; - - services.nginx.virtualHosts = mkNginxVHosts { - acmeHost = "baduhai.dev"; - domains."speedtest.baduhai.dev".locations."/".proxyPass = "http://librespeed:80/"; - }; -} diff --git a/hosts/alexandria/nextcloud.nix b/hosts/alexandria/nextcloud.nix new file mode 100644 index 0000000..c449cce --- /dev/null +++ b/hosts/alexandria/nextcloud.nix @@ -0,0 +1,97 @@ +{ + lib, + config, + pkgs, + inputs, + ... +}: + +let + utils = import ../../utils.nix { inherit inputs lib; }; + inherit (utils) mkNginxVHosts; +in + +{ + services = { + nextcloud = { + enable = true; + package = pkgs.nextcloud32; + datadir = "/data/nextcloud"; + hostName = "cloud.baduhai.dev"; + configureRedis = true; + https = true; + secretFile = config.age.secrets."nextcloud-secrets.json".path; + database.createLocally = true; + maxUploadSize = "16G"; + extraApps = { + inherit (config.services.nextcloud.package.packages.apps) + calendar + contacts + notes + tasks + user_oidc + ; + }; + extraAppsEnable = true; + caching = { + apcu = true; + redis = true; + }; + settings = { + trusted_proxies = [ "127.0.0.1" ]; + default_phone_region = "BR"; + maintenance_window_start = "4"; + allow_local_remote_servers = true; + enabledPreviewProviders = [ + "OC\\Preview\\BMP" + "OC\\Preview\\EMF" + "OC\\Preview\\Font" + "OC\\Preview\\GIF" + "OC\\Preview\\HEIC" + "OC\\Preview\\Illustrator" + "OC\\Preview\\JPEG" + "OC\\Preview\\Krita" + "OC\\Preview\\MarkDown" + "OC\\Preview\\Movie" + "OC\\Preview\\MP3" + "OC\\Preview\\MSOffice2003" + "OC\\Preview\\MSOffice2007" + "OC\\Preview\\MSOfficeDoc" + "OC\\Preview\\OpenDocument" + "OC\\Preview\\PDF" + "OC\\Preview\\Photoshop" + "OC\\Preview\\PNG" + "OC\\Preview\\Postscript" + "OC\\Preview\\SVG" + "OC\\Preview\\TIFF" + "OC\\Preview\\TXT" + "OC\\Preview\\XBitmap" + ]; + }; + config = { + dbtype = "pgsql"; + adminpassFile = config.age.secrets.nextcloud-adminpass.path; + }; + phpOptions = { + "opcache.interned_strings_buffer" = "16"; + }; + }; + + nginx.virtualHosts = mkNginxVHosts { + domains."cloud.baduhai.dev" = { }; + }; + }; + + age.secrets = { + "nextcloud-secrets.json" = { + file = ../../secrets/nextcloud-secrets.json.age; + owner = "nextcloud"; + group = "nextcloud"; + }; + nextcloud-adminpass = { + file = ../../secrets/nextcloud-adminpass.age; + owner = "nextcloud"; + group = "nextcloud"; + }; + }; +} diff --git a/hosts/alexandria/nginx.nix b/hosts/alexandria/nginx.nix index 192dbda..274f645 100644 --- a/hosts/alexandria/nginx.nix +++ b/hosts/alexandria/nginx.nix @@ -4,10 +4,20 @@ inputs, ... }: + let utils = import ../../utils.nix { inherit inputs lib; }; - inherit (utils) mkNginxVHosts; + inherit (utils) mkNginxVHosts services; + + # Get all unique domains from shared services that have LAN IPs (served by this host) + localDomains = lib.unique (map (s: s.domain) (lib.filter (s: s.host == "alexandria") services)); + + # Generate ACME cert configs for all local domains + acmeCerts = lib.genAttrs localDomains (domain: { + group = "nginx"; + }); in + { security.acme = { acceptTerms = true; @@ -17,15 +27,7 @@ in dnsProvider = "cloudflare"; credentialsFile = config.age.secrets.cloudflare.path; }; - certs."baduhai.dev" = { - extraDomainNames = [ "*.baduhai.dev" ]; - }; - }; - - age.secrets.cloudflare = { - file = ../../secrets/cloudflare.age; - owner = "nginx"; - group = "nginx"; + certs = acmeCerts; }; services.nginx = { @@ -34,11 +36,24 @@ in recommendedOptimisation = true; recommendedProxySettings = true; recommendedTlsSettings = true; - virtualHosts = mkNginxVHosts { - acmeHost = "baduhai.dev"; - domains."_".locations."/".return = "444"; + virtualHosts = { + "_" = { + default = true; + locations."/".return = "444"; + }; }; }; users.users.nginx.extraGroups = [ "acme" ]; + + networking.firewall.allowedTCPPorts = [ + 80 + 443 + ]; + + age.secrets.cloudflare = { + file = ../../secrets/cloudflare.age; + owner = "nginx"; + group = "nginx"; + }; } diff --git a/hosts/alexandria/unbound.nix b/hosts/alexandria/unbound.nix new file mode 100644 index 0000000..31363aa --- /dev/null +++ b/hosts/alexandria/unbound.nix @@ -0,0 +1,58 @@ +{ inputs, lib, ... }: + +let + utils = import ../../utils.nix { inherit inputs lib; }; +in + +{ + services.unbound = { + enable = true; + enableRootTrustAnchor = true; + settings = { + server = { + interface = [ + "0.0.0.0" + "::" + ]; + access-control = [ + "127.0.0.0/8 allow" + "192.168.0.0/16 allow" + "::1/128 allow" + ]; + + num-threads = 2; + msg-cache-size = "50m"; + rrset-cache-size = "100m"; + cache-min-ttl = 300; + cache-max-ttl = 86400; + prefetch = true; + prefetch-key = true; + hide-identity = true; + hide-version = true; + so-rcvbuf = "1m"; + so-sndbuf = "1m"; + + # LAN-only DNS records + local-zone = ''"baduhai.dev." transparent''; + local-data = map (e: ''"${e.domain}. IN A ${e.lanIP}"'') + (lib.filter (e: e ? lanIP) utils.services); + }; + + forward-zone = [ + { + name = "."; + forward-addr = [ + "1.1.1.1@853#cloudflare-dns.com" + "1.0.0.1@853#cloudflare-dns.com" + ]; + forward-tls-upstream = true; + } + ]; + }; + }; + + networking.firewall = { + allowedTCPPorts = [ 53 ]; + allowedUDPPorts = [ 53 ]; + }; +} diff --git a/hosts/alexandria/vaultwarden.nix b/hosts/alexandria/vaultwarden.nix index 21f7d46..2335ee0 100644 --- a/hosts/alexandria/vaultwarden.nix +++ b/hosts/alexandria/vaultwarden.nix @@ -14,13 +14,13 @@ in config = { DOMAIN = "https://pass.baduhai.dev"; SIGNUPS_ALLOWED = false; - ROCKET_ADDRESS = "/run/vaultwarden/vaultwarden.sock"; + ROCKET_ADDRESS = "127.0.0.1"; + ROCKET_PORT = 58222; }; }; services.nginx.virtualHosts = mkNginxVHosts { - acmeHost = "baduhai.dev"; domains."pass.baduhai.dev".locations."/".proxyPass = - "http://unix:${config.services.vaultwarden.config.ROCKET_ADDRESS}:/"; + "http://${config.services.vaultwarden.config.ROCKET_ADDRESS}:${toString config.services.vaultwarden.config.ROCKET_PORT}/"; }; } diff --git a/hosts/io/disko.nix b/hosts/io/disko.nix index edb1418..4e6c9d5 100644 --- a/hosts/io/disko.nix +++ b/hosts/io/disko.nix @@ -3,75 +3,71 @@ { imports = [ inputs.disko.nixosModules.default ]; - disko.devices = { - disk = { - main = { - type = "disk"; - device = "/dev/disk/by-id/mmc-hDEaP3_0x1041b689"; - content = { - type = "gpt"; - partitions = { - ESP = { - priority = 1; - name = "ESP"; - start = "1MiB"; - end = "1GiB"; - type = "EF00"; - content = { - type = "filesystem"; - format = "vfat"; - mountpoint = "/boot/efi"; - mountOptions = [ - "noatime" - "fmask=0077" - "dmask=0077" - ]; - }; - }; - cryptroot = { - priority = 2; - name = "root"; - size = "100%"; - content = { - type = "luks"; - name = "cryptroot"; - content = { - type = "btrfs"; - extraArgs = [ "-f" ]; - subvolumes = { - "@root" = { - mountpoint = "/"; - mountOptions = [ - "noatime" - "compress=zstd" - "subvol=@root" - ]; - }; - "@home" = { - mountpoint = "/home"; - mountOptions = [ - "noatime" - "compress=zstd" - "subvol=@home" - ]; - }; - "@nix" = { - mountpoint = "/nix"; - mountOptions = [ - "noatime" - "compress=zstd" - "subvol=@nix" - ]; - }; - "@persistent" = { - mountpoint = "/persistent"; - mountOptions = [ - "noatime" - "compress=zstd" - "subvol=@persistent" - ]; - }; - }; + disko.devices.disk.main = { + type = "disk"; + device = "/dev/disk/by-id/mmc-hDEaP3_0x1041b689"; + content = { + type = "gpt"; + partitions = { + ESP = { + priority = 1; + name = "ESP"; + start = "1MiB"; + end = "1GiB"; + type = "EF00"; + content = { + type = "filesystem"; + format = "vfat"; + mountpoint = "/boot/efi"; + mountOptions = [ + "noatime" + "fmask=0077" + "dmask=0077" + ]; + }; + }; + cryptroot = { + priority = 2; + name = "root"; + size = "100%"; + content = { + type = "luks"; + name = "cryptroot"; + content = { + type = "btrfs"; + extraArgs = [ "-f" ]; + subvolumes = { + "@root" = { + mountpoint = "/"; + mountOptions = [ + "noatime" + "compress=zstd" + "subvol=@root" + ]; + }; + "@home" = { + mountpoint = "/home"; + mountOptions = [ + "noatime" + "compress=zstd" + "subvol=@home" + ]; + }; + "@nix" = { + mountpoint = "/nix"; + mountOptions = [ + "noatime" + "compress=zstd" + "subvol=@nix" + ]; + }; + "@persistent" = { + mountpoint = "/persistent"; + mountOptions = [ + "noatime" + "compress=zstd" + "subvol=@persistent" + ]; }; }; }; diff --git a/hosts/io/hardware-configuration.nix b/hosts/io/hardware-configuration.nix index 56f0d0d..8e4dae4 100644 --- a/hosts/io/hardware-configuration.nix +++ b/hosts/io/hardware-configuration.nix @@ -2,6 +2,7 @@ config, lib, modulesPath, + inputs, ... }: diff --git a/hosts/io/services.nix b/hosts/io/services.nix index 3703ba3..df41a6f 100644 --- a/hosts/io/services.nix +++ b/hosts/io/services.nix @@ -48,6 +48,8 @@ }; }; }; + upower.enable = true; + power-profiles-daemon.enable = true; }; # TODO: remove once gmodena/nix-flatpak/issues/45 fixed diff --git a/hosts/modules/ai.nix b/hosts/modules/ai.nix new file mode 100644 index 0000000..e2dd9d2 --- /dev/null +++ b/hosts/modules/ai.nix @@ -0,0 +1,10 @@ +{ inputs, pkgs, ... }: + +{ + environment.systemPackages = with inputs.nix-ai-tools.packages.${pkgs.system}; [ + claude-desktop + claude-code + claudebox + opencode + ]; +} diff --git a/hosts/modules/common/locale.nix b/hosts/modules/common/locale.nix index 7e07d85..1171a32 100644 --- a/hosts/modules/common/locale.nix +++ b/hosts/modules/common/locale.nix @@ -7,6 +7,7 @@ defaultLocale = "en_US.UTF-8"; extraLocaleSettings = { LC_ADDRESS = "pt_BR.utf8"; + LC_COLLATE = "pt_BR.utf8"; LC_IDENTIFICATION = "pt_BR.utf8"; LC_MEASUREMENT = "pt_BR.utf8"; LC_MONETARY = "pt_BR.utf8"; diff --git a/hosts/modules/common/nix.nix b/hosts/modules/common/nix.nix index ff0b474..5ef9c4c 100644 --- a/hosts/modules/common/nix.nix +++ b/hosts/modules/common/nix.nix @@ -26,13 +26,11 @@ buildDocs = false; }; - services = { - nixos-cli = { - enable = true; - config = { - use_nvd = true; - ignore_dirty_tree = true; - }; + services.nixos-cli = { + enable = true; + config = { + use_nvd = true; + ignore_dirty_tree = true; }; }; diff --git a/hosts/modules/common/openssh.nix b/hosts/modules/common/openssh.nix index 07108ce..df70bdd 100644 --- a/hosts/modules/common/openssh.nix +++ b/hosts/modules/common/openssh.nix @@ -4,5 +4,8 @@ services.openssh = { enable = true; settings.PermitRootLogin = "no"; + extraConfig = '' + PrintLastLog no + ''; }; } diff --git a/hosts/modules/common/programs.nix b/hosts/modules/common/programs.nix index 9820149..fd10953 100644 --- a/hosts/modules/common/programs.nix +++ b/hosts/modules/common/programs.nix @@ -7,6 +7,8 @@ git ### System Utilities ### btop + fastfetch + helix nixos-firewall-tool nvd sysz @@ -17,13 +19,22 @@ shellAliases = { cat = "${lib.getExe pkgs.bat} --paging=never --style=plain"; ls = "${lib.getExe pkgs.eza} --icons --group-directories-first"; - neofetch = "${lib.getExe pkgs.fastfetch}"; tree = "ls --tree"; }; }; programs = { command-not-found.enable = false; - fish.enable = true; + fish = { + enable = true; + interactiveShellInit = '' + set fish_greeting + if set -q SSH_CONNECTION + export TERM=xterm-256color + clear + fastfetch + end + ''; + }; }; } diff --git a/hosts/modules/common/users.nix b/hosts/modules/common/users.nix index 076eb99..7dd6490 100644 --- a/hosts/modules/common/users.nix +++ b/hosts/modules/common/users.nix @@ -10,8 +10,9 @@ "wheel" ]; openssh.authorizedKeys.keys = [ - "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIA1v3+q3EaruiiStWjubEJWvtejam/r41uoOpCdwJtLL user@rotterdam" + "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAICQPkAyy+Du9Omc2WtnUF2TV8jFAF4H6mJi2D4IZ1nzg user@himalia" "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIO3Y0PVpGfJHonqDS7qoCFhqzUvqGq9I9sax+F9e/5cs user@io" + "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIA1v3+q3EaruiiStWjubEJWvtejam/r41uoOpCdwJtLL user@rotterdam" ]; hashedPassword = "$6$Pj7v/CpstyuWQQV0$cNujVDhfMBdwlGVEnnd8t71.kZPixbo0u25cd.874iaqLTH4V5fa1f98V5zGapjQCz5JyZmsR94xi00sUrntT0"; }; @@ -20,10 +21,4 @@ hashedPassword = "!"; }; }; - programs.fish = { - enable = true; - interactiveShellInit = '' - set fish_greeting - ''; - }; } diff --git a/hosts/modules/desktop/desktop.nix b/hosts/modules/desktop/desktop.nix index 2afd7ea..03ec04b 100644 --- a/hosts/modules/desktop/desktop.nix +++ b/hosts/modules/desktop/desktop.nix @@ -1,79 +1,63 @@ { + config, inputs, lib, pkgs, ... }: -let - kwrite = pkgs.symlinkJoin { - name = "kwrite"; - paths = [ pkgs.kdePackages.kate ]; - postBuild = '' - rm -rf $out/bin/kate \ - $out/bin/.kate-wrapped \ - $out/share/applications/org.kde.kate.desktop \ - $out/share/man \ - $out/share/icons/hicolor/*/apps/kate.png \ - $out/share/icons/hicolor/scalable/apps/kate.svg \ - $out/share/appdata/org.kde.kate.appdata.xml - ''; - }; -in { - imports = [ inputs.nix-flatpak.nixosModules.nix-flatpak ]; + imports = [ + inputs.niri-flake.nixosModules.niri + inputs.nix-flatpak.nixosModules.nix-flatpak + ]; environment = { sessionVariables = { KDEHOME = "$XDG_CONFIG_HOME/kde4"; # Stops kde from placing a .kde4 folder in the home dir NIXOS_OZONE_WL = "1"; # Forces chromium and most electron apps to run in wayland }; - systemPackages = - with pkgs; - [ - ### Web ### - bitwarden-desktop - brave - tor-browser - qbittorrent - vesktop - ### Office & Productivity ### - aspell - aspellDicts.de - aspellDicts.en - aspellDicts.en-computers - aspellDicts.pt_BR - kwrite - libreoffice-qt - onlyoffice-desktopeditors - rnote - ### Graphics & Design ### - gimp - inkscape - plasticity - ### System Utilities ### - adwaita-icon-theme - colloid-gtk-theme - junction - kara - kde-rounded-corners - libfido2 - mission-center - p7zip - rclone - toggleaudiosink - unrar - ### Media ### - mpv - obs-studio - qview - ] - ++ (with pkgs.kdePackages; [ - ark - dolphin - dolphin-plugins - kolourpaint - ]); + systemPackages = with pkgs; [ + ### Web ### + bitwarden-desktop + fragments + nextcloud-client + tor-browser + vesktop + inputs.zen-browser.packages."${system}".default + ### Office & Productivity ### + aspell + aspellDicts.de + aspellDicts.en + aspellDicts.en-computers + aspellDicts.pt_BR + libreoffice + onlyoffice-desktopeditors + papers + presenterm + rnote + ### Graphics & Design ### + gimp + inkscape + plasticity + ### System Utilities ### + adwaita-icon-theme + ghostty + gnome-disk-utility + junction + libfido2 + mission-center + nautilus + p7zip + rclone + toggleaudiosink + unrar + ### Media ### + decibels + loupe + obs-studio + showtime + ]; }; services = { @@ -89,11 +73,13 @@ in enable = true; settings = { default_session = { - command = "${lib.getExe pkgs.greetd.tuigreet} --time --remember --asterisks --cmd ${lib.getExe pkgs.niri}"; + command = "${lib.getExe pkgs.tuigreet} --user-menu --time --remember --asterisks --cmd ${config.programs.niri.package}/bin/niri-session"; user = "greeter"; }; + } + // lib.optionalAttrs (config.networking.hostName == "io") { initial_session = { - command = "${lib.getExe pkgs.niri}"; + command = "${config.programs.niri.package}/bin/niri-session"; user = "user"; }; }; @@ -101,8 +87,6 @@ in flatpak = { enable = true; packages = [ - ### Internet Browsers & Communication ### - "app.zen_browser.zen" ### Graphics & Design ### "com.boxy_svg.BoxySVG" rec { @@ -120,6 +104,7 @@ in uninstallUnmanaged = true; update.auto.enable = true; }; + gvfs.enable = true; }; security.rtkit.enable = true; # Needed for pipewire to acquire realtime priority @@ -133,16 +118,23 @@ in }; programs = { - niri.enable = true; + niri = { + enable = true; + package = inputs.niri.packages.${pkgs.system}.niri; + }; + kdeconnect = { + enable = true; + package = pkgs.valent; + }; dconf.enable = true; - kdeconnect.enable = true; - partition-manager.enable = true; appimage = { enable = true; binfmt = true; }; }; + niri-flake.cache.enable = false; + fonts = { fontDir.enable = true; packages = with pkgs; [ @@ -154,4 +146,18 @@ in roboto ]; }; + + xdg.portal = { + extraPortals = with pkgs; [ + xdg-desktop-portal-gnome + xdg-desktop-portal-gtk + ]; + config = { + common.default = "*"; + niri.default = [ + "gtk" + "gnome" + ]; + }; + }; } diff --git a/hosts/modules/dev.nix b/hosts/modules/dev.nix index 82908f2..c4cca78 100644 --- a/hosts/modules/dev.nix +++ b/hosts/modules/dev.nix @@ -3,7 +3,6 @@ { environment.systemPackages = with pkgs; [ bat - claude-code lazygit fd fzf diff --git a/hosts/modules/ephemeral.nix b/hosts/modules/ephemeral.nix new file mode 100644 index 0000000..cad5f41 --- /dev/null +++ b/hosts/modules/ephemeral.nix @@ -0,0 +1,41 @@ +{ config, inputs, ... }: + +{ + imports = [ + inputs.impermanence.nixosModules.impermanence + inputs.self.nixosModules.ephemeral + ]; + + ephemeral = { + enable = true; + rootDevice = + if config.networking.hostName == "trantor" then + "/dev/disk/by-id/scsi-360b207ed25d84372a95d1ecf842f8e20-part2" + else + "/dev/mapper/cryptroot"; + rootSubvolume = "@root"; + }; + + environment.persistence.main = { + persistentStoragePath = "/persistent"; + files = [ + "/etc/machine-id" + "/etc/ssh/ssh_host_ed25519_key" + "/etc/ssh/ssh_host_ed25519_key.pub" + "/etc/ssh/ssh_host_rsa_key" + "/etc/ssh/ssh_host_rsa_key.pub" + ]; + directories = [ + "/etc/NetworkManager/system-connections" + "/etc/nixos" + "/var/lib/bluetooth" + "/var/lib/flatpak" + "/var/lib/lxd" + "/var/lib/nixos" + "/var/lib/systemd/coredump" + "/var/lib/systemd/timers" + "/var/lib/tailscale" + "/var/log" + ]; + }; +} diff --git a/hosts/modules/ephermal.nix b/hosts/modules/ephermal.nix deleted file mode 100644 index adaf5af..0000000 --- a/hosts/modules/ephermal.nix +++ /dev/null @@ -1,72 +0,0 @@ -{ inputs, ... }: - -{ - imports = [ inputs.impermanence.nixosModules.impermanence ]; - - boot.initrd.systemd.services.recreate-root = { - description = "Rolling over and creating new filesystem root"; - requires = [ "initrd-root-device.target" ]; - after = [ - "local-fs-pre.target" - "initrd-root-device.target" - ]; - requiredBy = [ "initrd-root-fs.target" ]; - before = [ "sysroot.mount" ]; - unitConfig = { - AssertPathExists = "/etc/initrd-release"; - DefaultDependencies = false; - }; - serviceConfig = { - Type = "oneshot"; - RemainAfterExit = true; - }; - script = '' - mkdir /btrfs_tmp - mount /dev/mapper/cryptroot /btrfs_tmp - - if [[ -e /btrfs_tmp/@root ]]; then - mkdir -p /btrfs_tmp/old_roots - timestamp=$(date --date="@$(stat -c %Y /btrfs_tmp/@root)" "+%Y-%m-%-d_%H:%M:%S") - mv /btrfs_tmp/@root "/btrfs_tmp/old_roots/$timestamp" - fi - - delete_subvolume_recursively() { - IFS=$'\n' - for i in $(btrfs subvolume list -o "$1" | cut -f 9- -d ' '); do - delete_subvolume_recursively "/btrfs_tmp/$i" - done - btrfs subvolume delete "$1" - } - - for i in $(find /btrfs_tmp/old_roots/ -maxdepth 1 -mtime +30); do - delete_subvolume_recursively "$i" - done - - btrfs subvolume create /btrfs_tmp/@root - umount /btrfs_tmp - ''; - }; - - environment.persistence.main = { - persistentStoragePath = "/persistent"; - files = [ - "/etc/machine-id" - "/etc/ssh/ssh_host_ed25519_key" - "/etc/ssh/ssh_host_ed25519_key.pub" - "/etc/ssh/ssh_host_rsa_key" - "/etc/ssh/ssh_host_rsa_key.pub" - ]; - directories = [ - "/etc/NetworkManager/system-connections" - "/etc/nixos" - "/var/lib/bluetooth" - "/var/lib/flatpak" - "/var/lib/lxd" - "/var/lib/nixos" - "/var/lib/systemd/coredump" - "/var/lib/systemd/timers" - "/var/lib/tailscale" - "/var/log" - ]; - }; -} diff --git a/hosts/modules/gaming.nix b/hosts/modules/gaming.nix index cf6217f..5aef14e 100644 --- a/hosts/modules/gaming.nix +++ b/hosts/modules/gaming.nix @@ -6,7 +6,6 @@ heroic mangohud prismlauncher - protonup steam-run ]; diff --git a/hosts/trantor/boot.nix b/hosts/trantor/boot.nix index a031ce9..0498818 100644 --- a/hosts/trantor/boot.nix +++ b/hosts/trantor/boot.nix @@ -1,6 +1,6 @@ { boot = { - loader.efi.efiSysMountPoint = "/boot"; initrd.systemd.enable = true; + loader.efi.efiSysMountPoint = "/boot/efi"; }; } diff --git a/hosts/trantor/disko.nix b/hosts/trantor/disko.nix index a70383e..0e47058 100644 --- a/hosts/trantor/disko.nix +++ b/hosts/trantor/disko.nix @@ -3,29 +3,57 @@ { imports = [ inputs.disko.nixosModules.default ]; - disko.devices = { - disk = { - main = { - type = "disk"; - device = "/dev/disk/by-id/scsi-3605e4addb4c640319c8c03436205530b"; - content = { - type = "gpt"; - partitions = { - boot = { - size = "512M"; - type = "EF00"; - content = { - type = "filesystem"; - format = "vfat"; - mountpoint = "/boot"; - }; - }; - root = { - size = "100%"; - content = { - type = "filesystem"; - format = "ext4"; + disko.devices.disk.main = { + type = "disk"; + device = "/dev/disk/by-id/scsi-360b207ed25d84372a95d1ecf842f8e20"; + content = { + type = "gpt"; + partitions = { + ESP = { + priority = 1; + name = "ESP"; + start = "1MiB"; + end = "512MiB"; + type = "EF00"; + content = { + type = "filesystem"; + format = "vfat"; + mountpoint = "/boot/efi"; + mountOptions = [ + "noatime" + "fmask=0077" + "dmask=0077" + ]; + }; + }; + root = { + priority = 2; + name = "root"; + size = "100%"; + content = { + type = "btrfs"; + extraArgs = [ "-f" ]; + subvolumes = { + "@root" = { mountpoint = "/"; + mountOptions = [ + "noatime" + "compress=zstd" + ]; + }; + "@nix" = { + mountpoint = "/nix"; + mountOptions = [ + "noatime" + "compress=zstd" + ]; + }; + "@persistent" = { + mountpoint = "/persistent"; + mountOptions = [ + "noatime" + "compress=zstd" + ]; }; }; }; diff --git a/hosts/trantor/fail2ban.nix b/hosts/trantor/fail2ban.nix new file mode 100644 index 0000000..bc05139 --- /dev/null +++ b/hosts/trantor/fail2ban.nix @@ -0,0 +1,23 @@ +{ config, pkgs, ... }: + +{ + services.fail2ban = { + enable = true; + maxretry = 5; + ignoreIP = [ + "127.0.0.0/8" + "::1" + "10.0.0.0/8" + "172.16.0.0/12" + "192.168.0.0/16" + "100.64.0.0/10" + ]; + bantime = "1h"; + bantime-increment = { + enable = true; + multipliers = "1 2 4 8 16 32 64"; + maxtime = "10000h"; + overalljails = true; + }; + }; +} diff --git a/hosts/trantor/forgejo.nix b/hosts/trantor/forgejo.nix new file mode 100644 index 0000000..fdfa64a --- /dev/null +++ b/hosts/trantor/forgejo.nix @@ -0,0 +1,72 @@ +{ + config, + lib, + inputs, + ... +}: + +let + utils = import ../../utils.nix { inherit inputs lib; }; + inherit (utils) mkNginxVHosts; +in + +{ + services = { + forgejo = { + enable = true; + settings = { + session.COOKIE_SECURE = true; + server = { + PROTOCOL = "http+unix"; + DOMAIN = "git.baduhai.dev"; + ROOT_URL = "https://git.baduhai.dev"; + OFFLINE_MODE = true; # disable use of CDNs + SSH_DOMAIN = "git.baduhai.dev"; + }; + log.LEVEL = "Warn"; + mailer.ENABLED = false; + actions.ENABLED = false; + service.DISABLE_REGISTRATION = true; + oauth2_client = { + ENABLE_AUTO_REGISTRATION = true; + UPDATE_AVATAR = true; + ACCOUNT_LINKING = "login"; + USERNAME = "preferred_username"; + }; + }; + }; + nginx.virtualHosts = mkNginxVHosts { + domains."git.baduhai.dev".locations."/".proxyPass = + "http://unix:${config.services.forgejo.settings.server.HTTP_ADDR}:/"; + }; + fail2ban.jails.forgejo = { + settings = { + enabled = true; + filter = "forgejo"; + maxretry = 3; + findtime = "10m"; + bantime = "1h"; + }; + }; + }; + + environment = { + etc."fail2ban/filter.d/forgejo.conf".text = '' + [Definition] + failregex = .*(Failed authentication attempt|invalid credentials|Attempted access of unknown user).* from + ignoreregex = + journalmatch = _SYSTEMD_UNIT=forgejo.service + ''; + + persistence.main.directories = [ + { + directory = config.services.forgejo.stateDir; + inherit (config.services.forgejo) user group; + mode = "0700"; + } + ]; + }; + + # Disable PrivateMounts to allow LoadCredential to work with bind-mounted directories + systemd.services.forgejo.serviceConfig.PrivateMounts = lib.mkForce false; +} diff --git a/hosts/trantor/hardware-configuration.nix b/hosts/trantor/hardware-configuration.nix index d5cc31f..039129e 100644 --- a/hosts/trantor/hardware-configuration.nix +++ b/hosts/trantor/hardware-configuration.nix @@ -7,19 +7,12 @@ { imports = [ (modulesPath + "/profiles/qemu-guest.nix") ]; - boot = { - kernelModules = [ ]; - extraModulePackages = [ ]; - initrd = { - availableKernelModules = [ - "xhci_pci" - "virtio_pci" - "virtio_scsi" - "usbhid" - ]; - kernelModules = [ ]; - }; - }; + boot.initrd.availableKernelModules = [ + "xhci_pci" + "virtio_pci" + "virtio_scsi" + "usbhid" + ]; networking.useDHCP = lib.mkDefault true; diff --git a/hosts/trantor/nginx.nix b/hosts/trantor/nginx.nix new file mode 100644 index 0000000..56eed7c --- /dev/null +++ b/hosts/trantor/nginx.nix @@ -0,0 +1,61 @@ +{ + config, + lib, + inputs, + ... +}: + +let + utils = import ../../utils.nix { inherit inputs lib; }; + inherit (utils) mkNginxVHosts services; + + # Get all unique domains from shared services on trantor (host = "trantor") + localDomains = lib.unique ( + map (s: s.domain) (lib.filter (s: s.host == "trantor") services) + ); + + # Generate ACME cert configs for all local domains + acmeCerts = lib.genAttrs localDomains (domain: { + group = "nginx"; + }); +in + +{ + security.acme = { + acceptTerms = true; + defaults = { + email = "baduhai@proton.me"; + dnsResolver = "1.1.1.1:53"; + dnsProvider = "cloudflare"; + credentialsFile = config.age.secrets.cloudflare.path; + }; + certs = acmeCerts; + }; + + services.nginx = { + enable = true; + recommendedGzipSettings = true; + recommendedOptimisation = true; + recommendedProxySettings = true; + recommendedTlsSettings = true; + virtualHosts = { + "_" = { + default = true; + locations."/".return = "444"; + }; + }; + }; + + users.users.nginx.extraGroups = [ "acme" ]; + + networking.firewall.allowedTCPPorts = [ + 80 + 443 + ]; + + age.secrets.cloudflare = { + file = ../../secrets/cloudflare.age; + owner = "nginx"; + group = "nginx"; + }; +} diff --git a/hosts/trantor/openssh.nix b/hosts/trantor/openssh.nix new file mode 100644 index 0000000..704b3df --- /dev/null +++ b/hosts/trantor/openssh.nix @@ -0,0 +1,23 @@ +{ ... }: + +{ + services = { + openssh = { + settings = { + PasswordAuthentication = false; + KbdInteractiveAuthentication = false; + }; + }; + fail2ban.jails.sshd = { + settings = { + enabled = true; + port = "ssh"; + filter = "sshd"; + logpath = "/var/log/auth.log"; + maxretry = 3; + findtime = "10m"; + bantime = "1h"; + }; + }; + }; +} diff --git a/hosts/trantor/unbound.nix b/hosts/trantor/unbound.nix new file mode 100644 index 0000000..46808c6 --- /dev/null +++ b/hosts/trantor/unbound.nix @@ -0,0 +1,58 @@ +{ inputs, lib, ... }: + +let + utils = import ../../utils.nix { inherit inputs lib; }; +in + +{ + services.unbound = { + enable = true; + enableRootTrustAnchor = true; + settings = { + server = { + interface = [ + "0.0.0.0" + "::" + ]; + access-control = [ + "127.0.0.0/8 allow" + "100.64.0.0/10 allow" # Tailscale CGNAT range + "::1/128 allow" + "fd7a:115c:a1e0::/48 allow" # Tailscale IPv6 + ]; + + num-threads = 2; + msg-cache-size = "50m"; + rrset-cache-size = "100m"; + cache-min-ttl = 300; + cache-max-ttl = 86400; + prefetch = true; + prefetch-key = true; + hide-identity = true; + hide-version = true; + so-rcvbuf = "1m"; + so-sndbuf = "1m"; + + # Tailnet DNS records from shared services + local-zone = ''"baduhai.dev." transparent''; + local-data = map (e: ''"${e.domain}. IN A ${e.tailscaleIP}"'') utils.services; + }; + + forward-zone = [ + { + name = "."; + forward-addr = [ + "1.1.1.1@853#cloudflare-dns.com" + "1.0.0.1@853#cloudflare-dns.com" + ]; + forward-tls-upstream = true; + } + ]; + }; + }; + + networking.firewall = { + allowedTCPPorts = [ 53 ]; + allowedUDPPorts = [ 53 ]; + }; +} diff --git a/modules/ephemeral.nix b/modules/ephemeral.nix new file mode 100644 index 0000000..7403aac --- /dev/null +++ b/modules/ephemeral.nix @@ -0,0 +1,84 @@ +{ lib, config, ... }: + +let + cfg = config.ephemeral; +in +{ + options.ephemeral = { + enable = lib.mkEnableOption "ephemeral root with automatic rollback"; + + rootDevice = lib.mkOption { + type = lib.types.str; + example = "/dev/mapper/cryptroot"; + description = "Device path for the root btrfs filesystem"; + }; + + rootSubvolume = lib.mkOption { + type = lib.types.str; + example = "@root"; + description = "Name of the root btrfs subvolume"; + }; + + oldRootRetentionDays = lib.mkOption { + type = lib.types.int; + default = 30; + description = "Number of days to keep old root snapshots before deletion"; + }; + }; + + config = lib.mkIf cfg.enable { + boot.initrd.systemd.services.recreate-root = { + description = "Rolling over and creating new filesystem root"; + requires = [ "initrd-root-device.target" ]; + after = [ + "local-fs-pre.target" + "initrd-root-device.target" + ]; + requiredBy = [ "initrd-root-fs.target" ]; + before = [ "sysroot.mount" ]; + unitConfig = { + AssertPathExists = "/etc/initrd-release"; + DefaultDependencies = false; + }; + serviceConfig = { + Type = "oneshot"; + RemainAfterExit = true; + }; + script = '' + set -euo pipefail + + mkdir /btrfs_tmp + if ! mount ${cfg.rootDevice} /btrfs_tmp; then + echo "ERROR: Failed to mount ${cfg.rootDevice}" + exit 1 + fi + + if [[ -e /btrfs_tmp/${cfg.rootSubvolume} ]]; then + mkdir -p /btrfs_tmp/old_roots + timestamp=$(date --date="@$(stat -c %Y /btrfs_tmp/${cfg.rootSubvolume})" "+%Y-%m-%-d_%H:%M:%S") + mv /btrfs_tmp/${cfg.rootSubvolume} "/btrfs_tmp/old_roots/$timestamp" + fi + + delete_subvolume_recursively() { + IFS=$'\n' + for i in $(btrfs subvolume list -o "$1" | cut -f 9- -d ' '); do + delete_subvolume_recursively "/btrfs_tmp/$i" + done + btrfs subvolume delete "$1" + } + + for i in $(find /btrfs_tmp/old_roots/ -maxdepth 1 -mtime +${toString cfg.oldRootRetentionDays}); do + delete_subvolume_recursively "$i" + done + + if ! btrfs subvolume create /btrfs_tmp/${cfg.rootSubvolume}; then + echo "ERROR: Failed to create subvolume ${cfg.rootSubvolume}" + umount /btrfs_tmp + exit 1 + fi + + umount /btrfs_tmp + ''; + }; + }; +} diff --git a/nixosConfigurations.nix b/nixosConfigurations.nix index f32f422..c4969c1 100644 --- a/nixosConfigurations.nix +++ b/nixosConfigurations.nix @@ -10,9 +10,10 @@ in hostname = "rotterdam"; tags = [ "desktop" + "ai" "bluetooth" "dev" - "ephermal" + "ephemeral" "fwupd" "gaming" "libvirtd" @@ -25,9 +26,10 @@ in hostname = "io"; tags = [ "desktop" + "ai" "bluetooth" "dev" - "ephermal" + "ephemeral" "networkmanager" "podman" ]; @@ -36,8 +38,8 @@ in alexandria = mkHost { hostname = "alexandria"; tags = [ + # "server" TODO: uncomment when 25.11 is out. "fwupd" - "podman" ]; }; @@ -45,6 +47,8 @@ in hostname = "trantor"; system = "aarch64-linux"; tags = [ + "server" + "ephemeral" ]; }; }; diff --git a/nixosModules.nix b/nixosModules.nix new file mode 100644 index 0000000..5fd416b --- /dev/null +++ b/nixosModules.nix @@ -0,0 +1,7 @@ +{ ... }: + +{ + flake.nixosModules = { + ephemeral = import ./modules/ephemeral.nix; + }; +} diff --git a/overlays.nix b/overlays.nix index a5ba76c..eab4edf 100644 --- a/overlays.nix +++ b/overlays.nix @@ -3,8 +3,11 @@ { flake.overlays = { default = final: prev: { - toggleaudiosink = inputs.self.packages.${final.system}.toggleaudiosink; + base16-schemes = inputs.self.packages.${final.system}.base16-schemes; + fastfetch = inputs.self.packages.${final.system}.fastfetch; hm-cli = inputs.self.packages.${final.system}.hm-cli; + kwrite = inputs.self.packages.${final.system}.kwrite; + toggleaudiosink = inputs.self.packages.${final.system}.toggleaudiosink; }; }; } diff --git a/packages.nix b/packages.nix index e83ad26..46979f8 100644 --- a/packages.nix +++ b/packages.nix @@ -5,8 +5,11 @@ { pkgs, system, ... }: { packages = { - toggleaudiosink = pkgs.callPackage ./packages/toggleaudiosink.nix { }; + base16-schemes = pkgs.callPackage ./packages/base16-schemes.nix { }; + fastfetch = pkgs.callPackage ./packages/fastfetch.nix { }; hm-cli = pkgs.callPackage ./packages/hm-cli.nix { }; + kwrite = pkgs.callPackage ./packages/kwrite.nix { }; + toggleaudiosink = pkgs.callPackage ./packages/toggleaudiosink.nix { }; }; }; } diff --git a/packages/base16-schemes.nix b/packages/base16-schemes.nix new file mode 100644 index 0000000..ffd6c04 --- /dev/null +++ b/packages/base16-schemes.nix @@ -0,0 +1,32 @@ +{ + lib, + stdenv, + fetchFromGitHub, +}: +stdenv.mkDerivation (finalAttrs: { + pname = "base16-schemes"; + version = "0-unstable-2025-06-04"; + + src = fetchFromGitHub { + owner = "tinted-theming"; + repo = "schemes"; + rev = "317a5e10c35825a6c905d912e480dfe8e71c7559"; + hash = "sha256-d4km8W7w2zCUEmPAPUoLk1NlYrGODuVa3P7St+UrqkM="; + }; + + installPhase = '' + runHook preInstall + + mkdir -p $out/share/themes/ + install base16/*.yaml $out/share/themes/ + + runHook postInstall + ''; + + meta = { + description = "All the color schemes for use in base16 packages"; + homepage = "https://github.com/tinted-theming/schemes"; + maintainers = [ lib.maintainers.DamienCassou ]; + license = lib.licenses.mit; + }; +}) diff --git a/packages/fastfetch.nix b/packages/fastfetch.nix new file mode 100644 index 0000000..fa8e0ea --- /dev/null +++ b/packages/fastfetch.nix @@ -0,0 +1,81 @@ +{ + lib, + pkgs ? import { }, +}: + +let + fastfetch-logo = pkgs.fetchurl { + url = "https://discourse.nixos.org/uploads/default/original/3X/3/6/36954e6d6aa32c8b00f50ca43f142d898c1ff535.png"; + hash = "sha256-aLHz8jSAFocrn+Pb4vRq0wtkYFJpBpZRevd+VoZC/PQ="; + }; + + fastfetch-config = pkgs.writeText "fastfetch-config.json" ( + builtins.toJSON { + "$schema" = "https://github.com/fastfetch-cli/fastfetch/raw/dev/doc/json_schema.json"; + modules = [ + "title" + "separator" + { + type = "os"; + keyWidth = 9; + } + { + type = "kernel"; + keyWidth = 9; + } + { + type = "uptime"; + keyWidth = 9; + } + { + type = "shell"; + keyWidth = 9; + } + "break" + { + type = "cpu"; + keyWidth = 11; + } + { + type = "memory"; + keyWidth = 11; + } + { + type = "swap"; + keyWidth = 11; + } + { + type = "disk"; + folders = "/"; + keyWidth = 11; + } + { + type = "command"; + key = "Systemd"; + keyWidth = 11; + text = "echo \"$(systemctl list-units --state=failed --no-legend | wc -l) failed units, $(systemctl list-jobs --no-legend | wc -l) queued jobs\""; + } + "break" + { + type = "command"; + key = "Public IP"; + keyWidth = 15; + text = "curl -s -4 ifconfig.me 2>/dev/null || echo 'N/A'"; + } + { + type = "command"; + key = "Tailscale IP"; + keyWidth = 15; + text = "tailscale ip -4 2>/dev/null || echo 'N/A'"; + } + { + type = "command"; + key = "Local IP"; + keyWidth = 15; + text = "ip -4 addr show scope global | grep inet | head -n1 | awk '{print $2}' | cut -d/ -f1"; + } + ]; + } + ); +in +pkgs.writeShellScriptBin "fastfetch" ''exec ${lib.getExe pkgs.fastfetch} --config ${fastfetch-config} --logo-type kitty --logo ${fastfetch-logo} --logo-padding-right 1 --logo-width 36 "$@" '' diff --git a/packages/hm-cli.nix b/packages/hm-cli.nix index ef3ec30..f6034ea 100644 --- a/packages/hm-cli.nix +++ b/packages/hm-cli.nix @@ -23,9 +23,9 @@ pkgs.writeShellScriptBin "hm" '' Environment Variables: HM_PATH Override default flake path (~/.config/home-manager) - Currently set to "$(echo $HM_PATH)" + Currently set to "''${HM_PATH:-}" HM_USER Override default user output ("$(whoami)@$(hostname)") - Currently set to "$(echo $HM_USER)" + Currently set to "''${HM_USER:-}" EOF } @@ -36,7 +36,7 @@ pkgs.writeShellScriptBin "hm" '' case "$1" in apply) - "$HM" switch --flake "$FLAKE_PATH#$FLAKE_OUTPUT" + "$HM" switch --flake "$FLAKE_PATH#$FLAKE_OUTPUT" -b bkp ;; generation) if [[ $# -lt 2 ]]; then @@ -58,17 +58,21 @@ pkgs.writeShellScriptBin "hm" '' "$HM" remove-generations "$@" ;; rollback) - "$HM" generations | \ + PREV_GEN=$("$HM" generations | \ sed -n 's/^[[:space:]]*id \([0-9]\+\).*/\1/p' | \ - head -n 2 | tail -n 1 | \ - xargs -I {} "$HM" switch --flake "$FLAKE_PATH" --switch-generation {} + head -n 2 | tail -n 1) + if [[ -z "$PREV_GEN" ]]; then + echo "Error: could not determine previous generation (possibly only one generation exists)" + exit 1 + fi + "$HM" switch --flake "$FLAKE_PATH" --switch-generation "$PREV_GEN" -b bkp ;; switch) if [[ $# -ne 3 ]]; then echo "Error: switch requires exactly one generation ID" exit 1 fi - "$HM" switch --flake "$FLAKE_PATH" --switch-generation "$3" + "$HM" switch --flake "$FLAKE_PATH" --switch-generation "$3" -b bkp ;; cleanup) CURRENT_GEN=$("$HM" generations | sed -n 's/^.*id \([0-9]\+\) .* (current)$/\1/p') diff --git a/packages/kwrite.nix b/packages/kwrite.nix new file mode 100644 index 0000000..14ebce1 --- /dev/null +++ b/packages/kwrite.nix @@ -0,0 +1,15 @@ +{ pkgs }: + +pkgs.symlinkJoin { + name = "kwrite"; + paths = [ pkgs.kdePackages.kate ]; + postBuild = '' + rm -rf $out/bin/kate \ + $out/bin/.kate-wrapped \ + $out/share/applications/org.kde.kate.desktop \ + $out/share/man \ + $out/share/icons/hicolor/*/apps/kate.png \ + $out/share/icons/hicolor/scalable/apps/kate.svg \ + $out/share/appdata/org.kde.kate.appdata.xml + ''; +} diff --git a/readme.md b/readme.md index 9f3af1e..a2b815f 100644 --- a/readme.md +++ b/readme.md @@ -1,8 +1,87 @@ -All my personal Nix and NixOS hosts, in a flake. +# Nix Configuration -|Host|Description|System Version| -|:---|:---:|---:| -|alexandria|Personal server/NAS|NixOS 25.05| -|io|Mobile workstation|NixOS Unstable| -|rotterdam|Workstation|NixOS Unstable| -|trantor|Oracle Cloud VPS|NixOS 25.05| +My personal Nix configuration for multiple NixOS hosts, home-manager users, miscellaneous resources... too many things to list. If I could put my life in a flake I would. + +## Hosts + +### Desktop Systems +- **rotterdam** - Main desktop workstation (x86_64) + - Features: Desktop, AI tools, Bluetooth, Dev environment, Gaming, Virtualization (libvirtd), Podman + - Storage: Ephemeral root with LUKS encryption + +- **io** - Laptop workstation (x86_64) + - Features: Desktop, AI tools, Bluetooth, Dev environment, Podman + - Storage: Ephemeral root with LUKS encryption + +### Servers +- **alexandria** - Home server (x86_64) + - Hosts: Nextcloud, Vaultwarden, Jellyfin, Kanidm + +- **trantor** - Cloud server (aarch64) + - Hosts: Forgejo + - Cloud provider: Oracle Cloud Infrastructure + - Storage: Ephemeral root with btrfs + +## Home Manager Configurations + +- **user@rotterdam** - Full desktop setup with gaming, OBS, and complete development environment +- **user@io** - Lightweight desktop setup + +Both configurations include: +- btop, direnv, helix, starship, tmux +- Stylix theme management +- Fish shell with custom configurations + +## Terranix Configurations + +Infrastructure as code using Terranix (NixOS + Terraform/OpenTofu): + +- **oci-trantor** - Oracle Cloud Infrastructure provisioning for Trantor server +- **cloudflare-baduhaidev** - DNS and CDN configuration for baduhai.dev domain +- **tailscale-tailnet** - Tailscale network ACL and device management + +## Services + +All services are accessible via custom domains under baduhai.dev: + +- **Kanidm** (auth.baduhai.dev) - Identity and access management +- **Vaultwarden** (pass.baduhai.dev) - Password manager +- **Forgejo** (git.baduhai.dev) - Git forge (publicly accessible) +- **Nextcloud** (cloud.baduhai.dev) - File sync and collaboration +- **Jellyfin** (jellyfin.baduhai.dev) - Media server + +Services are accessible via: +- LAN for alexandria-hosted services +- Tailscale VPN for all services +- Public internet for Forgejo only + +## Notable Features + +### Ephemeral Root +Rotterdam, io, and trantor use an ephemeral root filesystem that resets on every boot: +- Root filesystem is automatically rolled back using btrfs snapshots +- Old snapshots retained for 30 days +- Persistent data stored in dedicated subvolumes +- Implements truly stateless systems + +### Custom DNS Architecture +- Unbound DNS servers on both alexandria and trantor +- Service routing based on visibility flags (public/LAN/Tailscale) +- Split-horizon DNS for optimal access paths + +### Security +- LUKS full-disk encryption on desktop systems +- Fail2ban on public-facing servers +- agenix for secrets management +- Tailscale for secure remote access + +### Desktop Environment +- Custom Niri window manager (Wayland compositor) +- Using forked version with auto-centering feature +- Stylix for consistent theming + +### Development Setup +- Nix flakes for reproducible builds +- deploy-rs for automated deployments +- Podman for containerization +- Complete AI tooling integration diff --git a/secrets/cloudflare.age b/secrets/cloudflare.age index 11cfac6..028e964 100644 --- a/secrets/cloudflare.age +++ b/secrets/cloudflare.age @@ -1,15 +1,11 @@ age-encryption.org/v1 --> ssh-ed25519 Kfdnog HMpl/3mb59SsUvkDXXxO+odBNSc1dZS1nQtC8/BPlGI -4fPk0YtGxOoqXDfTN9kQlH0Pg2iaJXUZE5es6f317L4 --> ssh-ed25519 SP9f6A p1kh6UOFJ4xwulLY9IpbNZIJ7JSouR27j6HgK/XRegM -rJCzN+RCdQgo/xCkAmcdN6GfXsoQhpmE1HuGwYs/2CI --> ssh-ed25519 8YSAiw cCbMOE3PMa3bzGGQSeQZuq074iwt4p4HLDu8uiHhWRY -U6wR/DuBdMKfbmQfUZ8XLdTBxNsUMR2lOueYucR5+bY --> ssh-ed25519 7cojTQ iLDzC79YtZcrqldzCyIFHrpsEapOXYD5AXuNoQ+3ulI -v2NiE3pA+J8Po+PqTTUU9XYKy37AIyj5KWdlh7FOPG8 --> ssh-ed25519 J6tVTA Jw1pSpF1J2Ud46BDhdRCPErgUeim8uwWxiB1E3BiJB8 -hGdGFi46iqKJN0QviG1xRNf2kwlls0rM5k3LkAiw8jY --> ssh-ed25519 Kl5yTQ yXnKCsJNjTSQYiPuv6dAF6raB3EFcg2oag1cBVkdvwk -0hwjrZpclTrFWtr5JqAbwXImYzZwTJOJPkhNnlHmPeo ---- k97ZU6FfTWVqBwNcrF9QeEbnqnuQUQ9pR1qM/Sgjh7A -#L-q﹋hr&*hNbqܦHŠG=@uaku|Er^BOo}:5ju$%".A1qP\2C R_ S=(%sި \ No newline at end of file +-> ssh-ed25519 Kfdnog IHXv4c5we36dCUsB1v8uEF23tIRlDQ/8WR1hX4GQ+Uc +Cwccw64BYBdSZUdkSqKESIU7E17cLNtiAZZ3Y1xV87A +-> ssh-ed25519 8YSAiw Ce3vdMG111ubjcFgd3+q2Qw2+7dsoUz7SiudtuLDr0Y +JUodwFsKfOTZXxFyRrEk/4gxJ4goPkwvYeThi893M0U +-> ssh-ed25519 J6tVTA bExFuITTGXkTvhW25nushN7zT/PJGDoezsqu7fLKemI +4a90v0F4wgcZeqWBQ/EpqOZ9OCgT7qruwVvlGZeFmN8 +-> ssh-ed25519 Qt3Q+A j1oo46pNh1+yPEtxpgj+QPQPf5m82jL0DHGMacY8UFA +vy52Hl1WLTdKNA8+4p7A48Sg9+QkMXbECf/uxVMCLYk +--- 429vzgFnmFbEqDMwdvC0/EYDJlKU64YEGgE0AqPqlBs +b/!8O3Df/&kNQhurt%&]ucjH]_5@D$>N8Ϧ >9:CvѦ69W'X]X^ƻ$}|c/ ߸={uɳs \ No newline at end of file diff --git a/secrets/forgejo-root-password.age b/secrets/forgejo-root-password.age new file mode 100644 index 0000000..90be612 Binary files /dev/null and b/secrets/forgejo-root-password.age differ diff --git a/secrets/nextcloud-adminpass.age b/secrets/nextcloud-adminpass.age new file mode 100644 index 0000000..b4a29fa Binary files /dev/null and b/secrets/nextcloud-adminpass.age differ diff --git a/secrets/nextcloud-secrets.json.age b/secrets/nextcloud-secrets.json.age new file mode 100644 index 0000000..02d170d Binary files /dev/null and b/secrets/nextcloud-secrets.json.age differ diff --git a/secrets/secrets.nix b/secrets/secrets.nix index ba71b7a..a90cd74 100644 --- a/secrets/secrets.nix +++ b/secrets/secrets.nix @@ -1,29 +1,35 @@ let - io-user = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIO3Y0PVpGfJHonqDS7qoCFhqzUvqGq9I9sax+F9e/5cs"; - io-host = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIKCIrKJk5zWzWEHvLMPMK8T3PyeBjsCsqzxPN+OrXfhA"; - io = [ - io-user - io-host - ]; + io-user = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIO3Y0PVpGfJHonqDS7qoCFhqzUvqGq9I9sax+F9e/5cs user@io"; + io = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIKCIrKJk5zWzWEHvLMPMK8T3PyeBjsCsqzxPN+OrXfhA root@io"; - rotterdam-user = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIA1v3+q3EaruiiStWjubEJWvtejam/r41uoOpCdwJtLL"; - rotterdam-host = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIIjXcqQqlu03x2VVTdWOyxtKRszXAKX0AxTkGvF1oeJL"; - rotterdam = [ - rotterdam-user - rotterdam-host - ]; + rotterdam-user = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIA1v3+q3EaruiiStWjubEJWvtejam/r41uoOpCdwJtLL user@rotterdam"; + rotterdam = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIIjXcqQqlu03x2VVTdWOyxtKRszXAKX0AxTkGvF1oeJL root@rotterdam"; - alexandria-host = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIK95QueW+jp1ZmF299Xr3XkgHJ6dL7aZVsfWxqbOKVKA"; - alexandria = [ alexandria-host ]; + alexandria = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIK95QueW+jp1ZmF299Xr3XkgHJ6dL7aZVsfWxqbOKVKA root@alexandria"; - trantor-host = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAINkGuGLZPnYJbCGY4BhJ9uTupp6ruuR1NZ7FEYEaLPA7"; - trantor = [ trantor-host ]; - - desktops = io ++ rotterdam; - servers = alexandria ++ trantor; - all-hosts = desktops ++ servers; + trantor = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIIh/2u5pr/iPVeavlsor5hbTtsgUfP1JpzZVco2YQAo3 root@trantor"; in + { - "cloudflare.age".publicKeys = all-hosts; - "webdav.age".publicKeys = all-hosts; + "cloudflare.age".publicKeys = [ + io-user + rotterdam-user + alexandria + trantor + ]; + "nextcloud-adminpass.age".publicKeys = [ + io-user + rotterdam-user + alexandria + ]; + "nextcloud-secrets.json.age".publicKeys = [ + io-user + rotterdam-user + alexandria + ]; + "forgejo-root-password.age".publicKeys = [ + io-user + rotterdam-user + trantor + ]; } diff --git a/secrets/webdav.age b/secrets/webdav.age deleted file mode 100644 index 93bd850..0000000 --- a/secrets/webdav.age +++ /dev/null @@ -1,15 +0,0 @@ -age-encryption.org/v1 --> ssh-ed25519 Kfdnog 9oKx6Oz/J/QJ0mmgoLX5AUx0sFdxnPVnjF42bElPSXA -BJ6h4lHGDsf1Npc4bwkvz5htGRT/x/b2bs9WFM2W/pc --> ssh-ed25519 SP9f6A T5t4apynXLYN/4YEvaHRCI28rrKzet4r6LrbAye5VGk -BsXkZYBxG9zcfLYCd9H0+LW078oCDyYx9zG+DPfE7bA --> ssh-ed25519 8YSAiw RY0YR30qyJPvhy7eTJLoj2JXpH9qHP43fJaHilJykXM -E5/P0Egz/LKwEhYLYd5Cnrat47gnYn93yDSeYgLi934 --> ssh-ed25519 7cojTQ qTCTw7CjilThFLmXYph4YhVBhnk1DpnFCGwgioo/XB0 -N31nZ8nInQuddLD3b0bxI5Es/pTvTQD8nz0f/AZtNFg --> ssh-ed25519 J6tVTA 7OawDsWwtVxu76ZgF0dFclMr19sBNdtu7H+Tr7Pd+SQ -hhVKcscIKIH1WChhRo/RYqUWy1rgs/EKnlHr9uY7QrQ --> ssh-ed25519 Kl5yTQ +i2Q3uNHw1jAVH76NHy4QbjCc6sBBYjsbr7w4mLaHW4 -JOJ02zU0+IxlbXMBsW4UrvzvLUbifdzABBNL+bc0bBs ---- W40oEFdBUKbi0teNTc6B1sX0ReHDvkIJcBm1dlROnk8 -zҼCn箱e7{{N6az"EHB/BYbD \ No newline at end of file diff --git a/shared/services.nix b/shared/services.nix new file mode 100644 index 0000000..44f9208 --- /dev/null +++ b/shared/services.nix @@ -0,0 +1,48 @@ +# Shared service definitions for cross-host configuration +# Used by: +# - alexandria: DNS server (LAN) + service hosting (vaultwarden, nextcloud, jellyfin, kanidm) +# - trantor: DNS server (Tailnet) + service hosting (forgejo) +{ + services = [ + { + name = "kanidm"; + domain = "auth.baduhai.dev"; + host = "alexandria"; + lanIP = "192.168.15.142"; + tailscaleIP = "100.76.19.50"; + port = 8443; + } + { + name = "vaultwarden"; + domain = "pass.baduhai.dev"; + host = "alexandria"; + lanIP = "192.168.15.142"; + tailscaleIP = "100.76.19.50"; + port = 8222; + } + { + name = "forgejo"; + domain = "git.baduhai.dev"; + host = "trantor"; + public = true; + tailscaleIP = "100.108.5.90"; + port = 3000; + } + { + name = "nextcloud"; + domain = "cloud.baduhai.dev"; + host = "alexandria"; + lanIP = "192.168.15.142"; + tailscaleIP = "100.76.19.50"; + port = 443; + } + { + name = "jellyfin"; + domain = "jellyfin.baduhai.dev"; + host = "alexandria"; + lanIP = "192.168.15.142"; + tailscaleIP = "100.76.19.50"; + port = 8096; + } + ]; +} diff --git a/terranix/cloudflare/baduhai.dev.nix b/terranix/cloudflare/baduhai.dev.nix new file mode 100644 index 0000000..1b456f3 --- /dev/null +++ b/terranix/cloudflare/baduhai.dev.nix @@ -0,0 +1,86 @@ +# Required environment variables: +# CLOUDFLARE_API_TOKEN - API token with "Edit zone DNS" permissions +# AWS_ACCESS_KEY_ID - Cloudflare R2 access key for state storage +# AWS_SECRET_ACCESS_KEY - Cloudflare R2 secret key for state storage + +{ config, lib, ... }: + +let + inherit (import ../../shared/services.nix) services; + + # Helper to extract subdomain from full domain (e.g., "git.baduhai.dev" -> "git") + getSubdomain = domain: lib.head (lib.splitString "." domain); + + # Generate DNS records for services + # Public services point to trantor's public IP + # Private services point to their tailscale IP + mkServiceRecords = lib.listToAttrs ( + lib.imap0 ( + i: svc: + let + subdomain = getSubdomain svc.domain; + targetIP = + if svc.public or false then + config.data.terraform_remote_state.trantor "outputs.instance_public_ip" + else + svc.tailscaleIP; + in + { + name = "service_${toString i}"; + value = { + zone_id = config.variable.zone_id.default; + name = subdomain; + type = "A"; + content = targetIP; + proxied = false; + ttl = 3600; + }; + } + ) services + ); +in + +{ + terraform.required_providers.cloudflare = { + source = "cloudflare/cloudflare"; + version = "~> 5.0"; + }; + + terraform.backend.s3 = { + bucket = "terraform-state"; + key = "cloudflare/baduhai.dev.tfstate"; + region = "auto"; + endpoint = "https://fcdf920bde00c3d013ee541f984da70e.r2.cloudflarestorage.com"; + skip_credentials_validation = true; + skip_metadata_api_check = true; + skip_region_validation = true; + skip_requesting_account_id = true; + use_path_style = true; + }; + + variable = { + zone_id = { + default = "c63a8332fdddc4a8e5612ddc54557044"; + type = "string"; + }; + }; + + data = { + terraform_remote_state.trantor = { + backend = "s3"; + config = { + bucket = "terraform-state"; + key = "oci/trantor.tfstate"; + region = "auto"; + endpoint = "https://fcdf920bde00c3d013ee541f984da70e.r2.cloudflarestorage.com"; + skip_credentials_validation = true; + skip_metadata_api_check = true; + skip_region_validation = true; + skip_requesting_account_id = true; + use_path_style = true; + }; + }; + }; + + resource.cloudflare_dns_record = mkServiceRecords; +} diff --git a/terranix/cloudflare/kernelpanic.space.nix b/terranix/cloudflare/kernelpanic.space.nix new file mode 100644 index 0000000..e69de29 diff --git a/terranix/oci/terminus.nix b/terranix/oci/terminus.nix new file mode 100644 index 0000000..e69de29 diff --git a/terranix/oci/trantor.nix b/terranix/oci/trantor.nix new file mode 100644 index 0000000..170ad04 --- /dev/null +++ b/terranix/oci/trantor.nix @@ -0,0 +1,258 @@ +# Required environment variables: +# instead of OCI variables, ~/.oci/config may also be used +# OCI_TENANCY_OCID - Oracle tenancy OCID (or use TF_VAR_* to override variables) +# OCI_USER_OCID - Oracle user OCID +# OCI_FINGERPRINT - API key fingerprint +# OCI_PRIVATE_KEY_PATH - Path to OCI API private key +# AWS variables are required +# AWS_ACCESS_KEY_ID - Cloudflare R2 access key for state storage +# AWS_SECRET_ACCESS_KEY - Cloudflare R2 secret key for state storage + +{ config, ... }: + +{ + terraform.required_providers.oci = { + source = "oracle/oci"; + version = "~> 7.0"; + }; + + provider.oci.region = "sa-saopaulo-1"; + + terraform.backend.s3 = { + bucket = "terraform-state"; + key = "oci/trantor.tfstate"; + region = "auto"; + endpoint = "https://fcdf920bde00c3d013ee541f984da70e.r2.cloudflarestorage.com"; + skip_credentials_validation = true; + skip_metadata_api_check = true; + skip_region_validation = true; + skip_requesting_account_id = true; + use_path_style = true; + }; + + variable = { + tenancy_ocid = { + default = "ocid1.tenancy.oc1..aaaaaaaap3vfdz4piygqza6e6zqunbcuso43ddqfo3ydmpmnomidyghh7rvq"; + type = "string"; + }; + + compartment_name = { + default = "trantor"; + type = "string"; + }; + + vcn_cidr = { + default = "10.0.0.0/24"; + type = "string"; + }; + + instance_name = { + default = "trantor"; + type = "string"; + }; + + ssh_public_keys = { + default = [ + "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAICQPkAyy+Du9Omc2WtnUF2TV8jFAF4H6mJi2D4IZ1nzg user@himalia" + "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIO3Y0PVpGfJHonqDS7qoCFhqzUvqGq9I9sax+F9e/5cs user@io" + "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIA1v3+q3EaruiiStWjubEJWvtejam/r41uoOpCdwJtLL user@rotterdam" + ]; + type = "list(string)"; + }; + }; + + data = { + oci_identity_availability_domains.ads = { + compartment_id = config.variable.tenancy_ocid.default; + }; + + oci_core_images.ubuntu_arm = { + compartment_id = config.variable.tenancy_ocid.default; + operating_system = "Canonical Ubuntu"; + operating_system_version = "24.04"; + shape = "VM.Standard.A1.Flex"; + sort_by = "TIMECREATED"; + sort_order = "DESC"; + }; + }; + + resource = { + oci_identity_compartment.trantor = { + compartment_id = config.variable.tenancy_ocid.default; + description = "trantor infrastructure compartment"; + name = config.variable.compartment_name.default; + }; + + oci_core_vcn.vcn = { + compartment_id = config.resource.oci_identity_compartment.trantor "id"; + cidr_blocks = [ config.variable.vcn_cidr.default ]; + display_name = "trantor-vcn"; + dns_label = "trantor"; + }; + + oci_core_internet_gateway.ig = { + compartment_id = config.resource.oci_identity_compartment.trantor "id"; + vcn_id = config.resource.oci_core_vcn.vcn "id"; + display_name = "trantor-ig"; + enabled = true; + }; + + oci_core_route_table.rt = { + compartment_id = config.resource.oci_identity_compartment.trantor "id"; + vcn_id = config.resource.oci_core_vcn.vcn "id"; + display_name = "trantor-rt"; + + route_rules = [ + { + network_entity_id = config.resource.oci_core_internet_gateway.ig "id"; + destination = "0.0.0.0/0"; + destination_type = "CIDR_BLOCK"; + } + ]; + }; + + oci_core_security_list.sl = { + compartment_id = config.resource.oci_identity_compartment.trantor "id"; + vcn_id = config.resource.oci_core_vcn.vcn "id"; + display_name = "trantor-sl"; + + egress_security_rules = [ + { + destination = "0.0.0.0/0"; + protocol = "all"; + stateless = false; + } + ]; + + ingress_security_rules = [ + { + protocol = "6"; # TCP + source = "0.0.0.0/0"; + stateless = false; + tcp_options = { + min = 22; + max = 22; + }; + } + { + protocol = "6"; # TCP + source = "0.0.0.0/0"; + stateless = false; + tcp_options = { + min = 80; + max = 80; + }; + } + { + protocol = "6"; # TCP + source = "0.0.0.0/0"; + stateless = false; + tcp_options = { + min = 443; + max = 443; + }; + } + { + protocol = "6"; # TCP + source = "0.0.0.0/0"; + stateless = false; + tcp_options = { + min = 25565; + max = 25565; + }; + } + { + protocol = "6"; # TCP + source = "0.0.0.0/0"; + stateless = false; + tcp_options = { + min = 19132; + max = 19133; + }; + } + { + protocol = "17"; # UDP + source = "0.0.0.0/0"; + stateless = false; + udp_options = { + min = 19132; + max = 19133; + }; + } + ]; + }; + + oci_core_subnet.subnet = { + compartment_id = config.resource.oci_identity_compartment.trantor "id"; + vcn_id = config.resource.oci_core_vcn.vcn "id"; + cidr_block = config.variable.vcn_cidr.default; + display_name = "trantor-subnet"; + dns_label = "subnet"; + route_table_id = config.resource.oci_core_route_table.rt "id"; + security_list_ids = [ (config.resource.oci_core_security_list.sl "id") ]; + prohibit_public_ip_on_vnic = false; + }; + + oci_core_instance.trantor = { + availability_domain = config.data.oci_identity_availability_domains.ads "availability_domains[0].name"; + compartment_id = config.resource.oci_identity_compartment.trantor "id"; + display_name = config.variable.instance_name.default; + shape = "VM.Standard.A1.Flex"; + + shape_config = { + ocpus = 2; + memory_in_gbs = 12; + }; + + source_details = { + source_type = "image"; + source_id = config.data.oci_core_images.ubuntu_arm "images[0].id"; + boot_volume_size_in_gbs = 100; + }; + + create_vnic_details = { + subnet_id = config.resource.oci_core_subnet.subnet "id"; + display_name = "trantor-vnic"; + assign_public_ip = true; + hostname_label = config.variable.instance_name.default; + }; + + metadata = { + ssh_authorized_keys = builtins.concatStringsSep "\n" config.variable.ssh_public_keys.default; + }; + + preserve_boot_volume = false; + }; + + oci_budget_budget.trantor_budget = { + compartment_id = config.variable.tenancy_ocid.default; + targets = [ (config.resource.oci_identity_compartment.trantor "id") ]; + amount = 1; + reset_period = "MONTHLY"; + display_name = "trantor-budget"; + description = "Monthly budget for trantor compartment"; + target_type = "COMPARTMENT"; + }; + + oci_budget_alert_rule.daily_spend_alert = { + budget_id = config.resource.oci_budget_budget.trantor_budget "id"; + type = "ACTUAL"; + threshold = 5; + threshold_type = "PERCENTAGE"; + display_name = "daily-spend-alert"; + recipients = "baduhai@proton.me"; + description = "Alert when daily spending exceeds $0.05"; + message = "Daily spending has exceeded $0.05 in the trantor compartment"; + }; + }; + + output = { + compartment_id = { + value = config.resource.oci_identity_compartment.trantor "id"; + }; + + instance_public_ip = { + value = config.resource.oci_core_instance.trantor "public_ip"; + }; + }; +} diff --git a/terranix/tailscale/tailnet.nix b/terranix/tailscale/tailnet.nix new file mode 100644 index 0000000..929e79b --- /dev/null +++ b/terranix/tailscale/tailnet.nix @@ -0,0 +1,43 @@ +# Required environment variables: +# TAILSCALE_API_KEY - Tailscale API key with appropriate permissions +# TAILSCALE_TAILNET - Your tailnet name (e.g., "user@example.com" or "example.org.github") +# AWS_ACCESS_KEY_ID - Cloudflare R2 access key for state storage +# AWS_SECRET_ACCESS_KEY - Cloudflare R2 secret key for state storage + +{ config, ... }: + +{ + terraform.required_providers.tailscale = { + source = "tailscale/tailscale"; + version = "~> 0.17"; + }; + + terraform.backend.s3 = { + bucket = "terraform-state"; + key = "tailscale/tailnet.tfstate"; + region = "auto"; + endpoint = "https://fcdf920bde00c3d013ee541f984da70e.r2.cloudflarestorage.com"; + skip_credentials_validation = true; + skip_metadata_api_check = true; + skip_region_validation = true; + skip_requesting_account_id = true; + use_path_style = true; + }; + + variable = { + trantor_tailscale_ip = { + default = "100.108.5.90"; + type = "string"; + }; + }; + + resource = { + tailscale_dns_nameservers.global = { + nameservers = [ + config.variable.trantor_tailscale_ip.default + "1.1.1.1" + "1.0.0.1" + ]; + }; + }; +} diff --git a/terranixConfigurations.nix b/terranixConfigurations.nix new file mode 100644 index 0000000..12c90d1 --- /dev/null +++ b/terranixConfigurations.nix @@ -0,0 +1,27 @@ +{ inputs, ... }: + +{ + imports = [ + inputs.terranix.flakeModule + ]; + + perSystem = + { pkgs, ... }: + + { + terranix.terranixConfigurations = { + oci-trantor = { + modules = [ ./terranix/oci/trantor.nix ]; + terraformWrapper.package = pkgs.opentofu; + }; + cloudflare-baduhaidev = { + modules = [ ./terranix/cloudflare/baduhai.dev.nix ]; + terraformWrapper.package = pkgs.opentofu; + }; + tailscale-tailnet = { + modules = [ ./terranix/tailscale/tailnet.nix ]; + terraformWrapper.package = pkgs.opentofu; + }; + }; + }; +} diff --git a/users/modules/comma.nix b/users/modules/comma.nix new file mode 100644 index 0000000..0aad530 --- /dev/null +++ b/users/modules/comma.nix @@ -0,0 +1,7 @@ +{ inputs, ... }: + +{ + imports = [ inputs.nix-index-database.homeModules.nix-index ]; + + programs.nix-index-database.comma.enable = true; +} diff --git a/users/modules/common/fish.nix b/users/modules/common/fish.nix index 8de52c3..c753297 100644 --- a/users/modules/common/fish.nix +++ b/users/modules/common/fish.nix @@ -3,7 +3,10 @@ { programs.fish = { enable = true; - interactiveShellInit = "${lib.getExe pkgs.nix-your-shell} fish | source"; + interactiveShellInit = '' + set fish_greeting + ${lib.getExe pkgs.nix-your-shell} fish | source + ''; loginShellInit = "${lib.getExe pkgs.nix-your-shell} fish | source"; plugins = [ { @@ -15,24 +18,15 @@ sha256 = "sha256-A8ydBX4LORk+nutjHurqNNWFmW6LIiBPQcxS3x4nbeQ="; }; } - { - name = "sponge"; - src = pkgs.fetchFromGitHub { - owner = "meaningful-ooo"; - repo = "sponge"; - rev = "384299545104d5256648cee9d8b117aaa9a6d7be"; - sha256 = "sha256-MdcZUDRtNJdiyo2l9o5ma7nAX84xEJbGFhAVhK+Zm1w="; - }; - } { name = "z"; src = pkgs.fetchFromGitHub { owner = "jethrokuan"; repo = "z"; - rev = "85f863f20f24faf675827fb00f3a4e15c7838d76"; - sha256 = "sha256-+FUBM7CodtZrYKqU542fQD+ZDGrd2438trKM0tIESs0="; + rev = "067e867debee59aee231e789fc4631f80fa5788e"; + sha256 = "sha256-emmjTsqt8bdI5qpx1bAzhVACkg0MNB/uffaRjjeuFxU="; }; } ]; }; -} \ No newline at end of file +} diff --git a/users/modules/desktop.nix b/users/modules/desktop.nix deleted file mode 100644 index 1873cc7..0000000 --- a/users/modules/desktop.nix +++ /dev/null @@ -1,56 +0,0 @@ -{ inputs, pkgs, ... }: - -{ - imports = [ inputs.dms.homeModules.dankMaterialShell.default ]; - - fonts.fontconfig.enable = true; - - programs = { - dankMaterialShell = { - enable = true; - enableVPN = false; - }; - - rio = { - enable = true; - settings = { - theme = "catppuccin-mocha"; - fonts = { - family = "FiraCode Nerd Font"; - size = 16.0; - emoji.family = "Noto Color Emoji"; - }; - confirm-before-quit = false; - window = { - width = 1121; - height = 633; - }; - }; - }; - - password-store = { - enable = true; - package = pkgs.pass-wayland; - }; - }; - - xdg.portal = { - enable = true; - xdgOpenUsePortal = true; - extraPortals = with pkgs; [ - kdePackages.xdg-desktop-portal-kde - xdg-desktop-portal-gtk - xdg-desktop-portal-gnome - ]; - }; - - gtk = { - enable = true; - gtk3.extraConfig = { - gtk-decoration-layout = "appmenu:"; - }; - gtk4.extraConfig = { - gtk-decoration-layout = "appmenu:"; - }; - }; -} diff --git a/users/modules/desktop/desktop.nix b/users/modules/desktop/desktop.nix new file mode 100644 index 0000000..6940e1f --- /dev/null +++ b/users/modules/desktop/desktop.nix @@ -0,0 +1,132 @@ +{ + inputs, + pkgs, + ... +}: + +{ + imports = [ inputs.vicinae.homeManagerModules.default ]; + + fonts.fontconfig.enable = true; + + home.packages = with pkgs; [ xwayland-satellite ]; + + services.vicinae = { + enable = true; + autoStart = true; + }; + + programs = { + + ghostty = { + enable = true; + settings = { + cursor-style = "block"; + shell-integration-features = "no-cursor"; + cursor-style-blink = false; + custom-shader = "${builtins.fetchurl { + url = "https://raw.githubusercontent.com/hackr-sh/ghostty-shaders/cb6eb4b0d1a3101c869c62e458b25a826f9dcde3/cursor_blaze.glsl"; + sha256 = "sha256:0g2lgqjdrn3c51glry7x2z30y7ml0y61arl5ykmf4yj0p85s5f41"; + }}"; + bell-features = ""; + gtk-titlebar-style = "tabs"; + keybind = [ "shift+enter=text:\\x1b\\r" ]; + }; + }; + + password-store = { + enable = true; + package = pkgs.pass-wayland; + }; + }; + + xdg = { + enable = true; + userDirs.enable = true; + mimeApps = { + enable = true; + defaultApplications = { + "text/html" = [ + "re.sonny.Junction.desktop" + "zen-browser.desktop" + "torbrowser.desktop" + ]; + "x-scheme-handler/http" = [ + "re.sonny.Junction.desktop" + "zen-browser.desktop" + "torbrowser.desktop" + ]; + "x-scheme-handler/https" = [ + "re.sonny.Junction.desktop" + "zen-browser.desktop" + "torbrowser.desktop" + ]; + "x-scheme-handler/about" = [ + "re.sonny.Junction.desktop" + "zen-browser.desktop" + "torbrowser.desktop" + ]; + "x-scheme-handler/unknown" = [ + "re.sonny.Junction.desktop" + "zen-browser.desktop" + "torbrowser.desktop" + ]; + "image/jpeg" = "org.gnome.Loupe.desktop"; + "image/png" = "org.gnome.Loupe.desktop"; + "image/gif" = "org.gnome.Loupe.desktop"; + "image/webp" = "org.gnome.Loupe.desktop"; + "image/bmp" = "org.gnome.Loupe.desktop"; + "image/svg+xml" = "org.gnome.Loupe.desktop"; + "image/tiff" = "org.gnome.Loupe.desktop"; + "video/mp4" = "io.bassi.Showtime.desktop"; + "video/x-matroska" = "io.bassi.Showtime.desktop"; + "video/webm" = "io.bassi.Showtime.desktop"; + "video/mpeg" = "io.bassi.Showtime.desktop"; + "video/x-msvideo" = "io.bassi.Showtime.desktop"; + "video/quicktime" = "io.bassi.Showtime.desktop"; + "video/x-flv" = "io.bassi.Showtime.desktop"; + "audio/mpeg" = "io.bassi.Showtime.desktop"; + "audio/flac" = "io.bassi.Showtime.desktop"; + "audio/ogg" = "io.bassi.Showtime.desktop"; + "audio/wav" = "io.bassi.Showtime.desktop"; + "audio/mp4" = "io.bassi.Showtime.desktop"; + "audio/x-opus+ogg" = "io.bassi.Showtime.desktop"; + "application/pdf" = [ + "org.gnome.Papers.desktop" + "zen-browser.desktop" + ]; + "text/plain" = "Helix.desktop"; + "text/markdown" = "Helix.desktop"; + "text/x-log" = "Helix.desktop"; + "application/x-shellscript" = "Helix.desktop"; + "application/vnd.openxmlformats-officedocument.wordprocessingml.document" = + "onlyoffice-desktopeditors.desktop"; # DOCX + "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" = + "onlyoffice-desktopeditors.desktop"; # XLSX + "application/vnd.openxmlformats-officedocument.presentationml.presentation" = + "onlyoffice-desktopeditors.desktop"; # PPTX + "application/vnd.oasis.opendocument.text" = "onlyoffice-desktopeditors.desktop"; # ODT + "application/vnd.oasis.opendocument.spreadsheet" = "onlyoffice-desktopeditors.desktop"; # ODS + "application/vnd.oasis.opendocument.presentation" = "onlyoffice-desktopeditors.desktop"; # ODP + "application/msword" = "onlyoffice-desktopeditors.desktop"; # DOC + "application/vnd.ms-excel" = "onlyoffice-desktopeditors.desktop"; # XLS + "application/vnd.ms-powerpoint" = "onlyoffice-desktopeditors.desktop"; # PPT + "application/zip" = "org.gnome.FileRoller.desktop"; + "application/x-tar" = "org.gnome.FileRoller.desktop"; + "application/x-compressed-tar" = "org.gnome.FileRoller.desktop"; + "application/x-bzip-compressed-tar" = "org.gnome.FileRoller.desktop"; + "application/x-xz-compressed-tar" = "org.gnome.FileRoller.desktop"; + "application/x-7z-compressed" = "org.gnome.FileRoller.desktop"; + "application/x-rar" = "org.gnome.FileRoller.desktop"; + "application/gzip" = "org.gnome.FileRoller.desktop"; + "application/x-bzip" = "org.gnome.FileRoller.desktop"; + "inode/directory" = "org.gnome.Nautilus.desktop"; + }; + }; + }; + + # Set Ghostty as default terminal + home.sessionVariables = { + TERMINAL = "ghostty"; + }; +} diff --git a/users/modules/desktop/niri.nix b/users/modules/desktop/niri.nix new file mode 100644 index 0000000..0cb5db8 --- /dev/null +++ b/users/modules/desktop/niri.nix @@ -0,0 +1,229 @@ +{ + inputs, + lib, + pkgs, + hostname ? null, + ... +}: + +let + isRotterdam = hostname == "rotterdam"; +in + +{ + imports = [ inputs.noctalia.homeModules.default ]; + + services.kanshi = { + enable = true; + settings = [ + { + profile.name = "default"; + profile.outputs = [ + { + criteria = "*"; + scale = 1.0; + } + ]; + } + ]; + }; + + home = { + packages = with pkgs; [ + xwayland-satellite + inputs.noctalia.packages.${pkgs.system}.default + ]; + sessionVariables.QT_QPA_PLATFORMTHEME = "gtk3"; + }; + + xdg.configFile."niri/config.kdl".text = '' + input { + keyboard { + xkb { + layout "us" + variant "altgr-intl" + } + } + touchpad { + tap + dwt + drag true + drag-lock + natural-scroll + accel-speed 0.2 + accel-profile "flat" + scroll-method "two-finger" + middle-emulation + } + mouse { + natural-scroll + accel-speed 0.2 + accel-profile "flat" + } + warp-mouse-to-focus mode="center-xy" + focus-follows-mouse + } + + layout { + gaps 8 + center-focused-column "never" + auto-center-when-space-available + preset-column-widths { + ${ + if isRotterdam then + '' + proportion 0.33333 + proportion 0.5 + proportion 0.66667 + '' + else + '' + proportion 0.5 + proportion 1.0 + '' + } + } + default-column-width { proportion ${if isRotterdam then "0.33333" else "0.5"}; } + focus-ring { + off + } + border { + width 4 + active-color "#ffc87f" + inactive-color "#505050" + urgent-color "#9b0000" + } + tab-indicator { + width 4 + gap 4 + place-within-column + } + } + + overview { + zoom 0.65 + } + + spawn-at-startup "noctalia-shell" "-d" + layer-rule { + match namespace="^wallpaper$" + place-within-backdrop true + } + layer-rule { + match namespace="^quickshell-overview$" + place-within-backdrop true + } + + hotkey-overlay { + skip-at-startup + } + + prefer-no-csd + screenshot-path "~/Pictures/Screenshots/Screenshot from %Y-%m-%d %H-%M-%S.png" + + animations { + slowdown 0.3 + } + + window-rule { + match app-id="zen" + default-column-width { proportion ${if isRotterdam then "0.5" else "1.0"}; } + } + + window-rule { + geometry-corner-radius 12 + clip-to-geometry true + } + + config-notification { + disable-failed + } + + binds { + Alt+Space repeat=false { spawn "vicinae" "toggle"; } + XF86AudioRaiseVolume allow-when-locked=true { spawn "noctalia-shell" "ipc" "call" "volume" "increase"; } + XF86AudioLowerVolume allow-when-locked=true { spawn "noctalia-shell" "ipc" "call" "volume" "decrease"; } + XF86AudioMute allow-when-locked=true { spawn "noctalia-shell" "ipc" "call" "volume" "muteOutput"; } + XF86MonBrightnessUp allow-when-locked=true { spawn "noctalia-shell" "ipc" "call" "brightness" "increase"; } + XF86MonBrightnessDown allow-when-locked=true { spawn "noctalia-shell" "ipc" "call" "brightness" "decrease"; } + XF86AudioPlay allow-when-locked=true { spawn "${lib.getExe pkgs.playerctl}" "play-pause"; } + XF86AudioStop allow-when-locked=true { spawn "${lib.getExe pkgs.playerctl}" "stop"; } + XF86AudioPrev allow-when-locked=true { spawn "${lib.getExe pkgs.playerctl}" "previous"; } + XF86AudioNext allow-when-locked=true { spawn "${lib.getExe pkgs.playerctl}" "next"; } + Mod+V repeat=false { spawn "vicinae" "vicinae://extensions/vicinae/clipboard/history"; } + Mod+Shift+L repeat=false { spawn "noctalia-shell" "ipc" "call" "lockScreen" "lock"; } + Mod+Return { spawn "ghostty"; } + Ctrl+Alt+Shift+A allow-when-locked=true { spawn "toggleaudiosink"; } + Mod+W repeat=false { toggle-overview; } + Mod+Q { close-window; } + Alt+Shift+Q { close-window;} + Mod+Shift+Q { close-window; } + Alt+F4 { close-window; } + Mod+Left { focus-column-left; } + Mod+Down { focus-window-or-workspace-down; } + Mod+Up { focus-window-or-workspace-up; } + Mod+Right { focus-column-right; } + Mod+H { focus-column-left; } + Mod+L { focus-column-right; } + Mod+J { focus-window-or-workspace-down; } + Mod+K { focus-window-or-workspace-up; } + Mod+Ctrl+Left { move-column-left; } + Mod+Ctrl+Down { move-window-down-or-to-workspace-down; } + Mod+Ctrl+Up { move-window-up-or-to-workspace-up; } + Mod+Ctrl+Right { move-column-right; } + Mod+Ctrl+H { move-column-left; } + Mod+Ctrl+J { move-window-down-or-to-workspace-down; } + Mod+Ctrl+K { move-window-up-or-to-workspace-up; } + Mod+Ctrl+L { move-column-right; } + Mod+Home { focus-column-first; } + Mod+End { focus-column-last; } + Mod+Ctrl+Home { move-column-to-first; } + Mod+Ctrl+End { move-column-to-last; } + Mod+Alt+Left { focus-monitor-left; } + Mod+Alt+Down { focus-monitor-down; } + Mod+Alt+Up { focus-monitor-up; } + Mod+Alt+Right { focus-monitor-right; } + Mod+Alt+H { focus-monitor-left; } + Mod+Alt+J { focus-monitor-down; } + Mod+Alt+K { focus-monitor-up; } + Mod+Alt+L { focus-monitor-right; } + Mod+Alt+Ctrl+Left { move-column-to-monitor-left; } + Mod+Alt+Ctrl+Down { move-column-to-monitor-down; } + Mod+Alt+Ctrl+Up { move-column-to-monitor-up; } + Mod+Alt+Ctrl+Right { move-column-to-monitor-right; } + Mod+Alt+Ctrl+H { move-column-to-monitor-left; } + Mod+Alt+Ctrl+J { move-column-to-monitor-down; } + Mod+Alt+Ctrl+K { move-column-to-monitor-up; } + Mod+Alt+Ctrl+L { move-column-to-monitor-right; } + Mod+Ctrl+U { move-workspace-down; } + Mod+Ctrl+I { move-workspace-up; } + Mod+WheelScrollDown cooldown-ms=150 { focus-workspace-down; } + Mod+WheelScrollUp cooldown-ms=150 { focus-workspace-up; } + Mod+Ctrl+WheelScrollDown cooldown-ms=150 { move-column-to-workspace-down; } + Mod+Ctrl+WheelScrollUp cooldown-ms=150 { move-column-to-workspace-up; } + Mod+Shift+WheelScrollDown { focus-column-right; } + Mod+Shift+WheelScrollUp { focus-column-left; } + Mod+Ctrl+Shift+WheelScrollDown { move-column-right; } + Mod+Ctrl+Shift+WheelScrollUp { move-column-left; } + Mod+BracketLeft { consume-or-expel-window-left; } + Mod+BracketRight { consume-or-expel-window-right; } + Mod+Comma { consume-window-into-column; } + Mod+Period { expel-window-from-column; } + Mod+R { switch-preset-column-width; } + Mod+F { maximize-column; } + Mod+Ctrl+F { fullscreen-window; } + Mod+C { center-visible-columns; } + Mod+Ctrl+C { center-column; } + Mod+Space { toggle-window-floating; } + Mod+Ctrl+Space { switch-focus-between-floating-and-tiling; } + Mod+T { toggle-column-tabbed-display; } + Print { screenshot-screen; } + Mod+Print { screenshot; } + Ctrl+Print { screenshot-window; } + Mod+Backspace allow-inhibiting=false { toggle-keyboard-shortcuts-inhibit; } + Mod+Alt+E { spawn "noctalia-shell" "ipc" "call" "sessionMenu" "toggle"; } + Ctrl+Alt+Delete { spawn "noctalia-shell" "ipc" "call" "sessionMenu" "toggle"; } + Mod+Ctrl+P { power-off-monitors; } + } + ''; +} diff --git a/users/modules/helix.nix b/users/modules/helix.nix index b71799b..a72ead3 100644 --- a/users/modules/helix.nix +++ b/users/modules/helix.nix @@ -8,13 +8,12 @@ programs.helix = { enable = true; settings = { - theme = "base16_transparent"; editor = { file-picker.hidden = false; idle-timeout = 0; line-number = "relative"; cursor-shape = { - normal = "block"; + normal = "underline"; insert = "bar"; select = "underline"; }; @@ -47,4 +46,4 @@ ]; }; }; -} \ No newline at end of file +} diff --git a/users/modules/starship.nix b/users/modules/starship.nix index 8b9a14c..c836c51 100644 --- a/users/modules/starship.nix +++ b/users/modules/starship.nix @@ -13,10 +13,10 @@ ''; right_format = "$cmd_duration$character"; hostname = { - ssh_symbol = " "; + ssh_symbol = "󰖟 "; }; character = { - error_symbol = "[](red)"; + error_symbol = "[](red)"; success_symbol = "[󱐋](green)"; }; cmd_duration = { @@ -25,7 +25,7 @@ min_time = 500; }; git_branch = { - symbol = " "; + symbol = " "; style = "purple"; }; git_status.style = "red"; @@ -37,4 +37,4 @@ }; }; }; -} \ No newline at end of file +} diff --git a/users/modules/stylix.nix b/users/modules/stylix.nix new file mode 100644 index 0000000..f1c7e44 --- /dev/null +++ b/users/modules/stylix.nix @@ -0,0 +1,69 @@ +{ + config, + inputs, + pkgs, + ... +}: + +{ + imports = [ + inputs.stylix.homeModules.stylix + inputs.zen-browser.homeModules.beta + ]; + + stylix = { + enable = true; + polarity = "dark"; + base16Scheme = "${pkgs.base16-schemes}/share/themes/tokyodark.yaml"; + cursor = { + package = pkgs.kdePackages.breeze; + name = "breeze_cursors"; + size = 24; + }; + icons = { + enable = true; + package = pkgs.morewaita-icon-theme; + light = "MoreWaita"; + dark = "MoreWaita"; + }; + opacity = { + applications = 1.0; + desktop = 0.8; + popups = config.stylix.opacity.desktop; + terminal = 1.0; + }; + fonts = { + serif = { + package = pkgs.source-serif; + name = "Source Serif 4 Display"; + }; + sansSerif = { + package = pkgs.inter; + name = "Inter"; + }; + monospace = { + package = pkgs.nerd-fonts.fira-code; + name = "FiraCode Nerd Font"; + }; + emoji = { + package = pkgs.noto-fonts-color-emoji; + name = "Noto Color Emoji"; + }; + sizes = { + applications = 10; + desktop = config.stylix.fonts.sizes.applications; + popups = config.stylix.fonts.sizes.applications; + terminal = 12; + }; + }; + targets.zen-browser = { + enable = true; + profileNames = [ "william" ]; + }; + }; + + programs.zen-browser = { + enable = true; + profiles.william = { }; + }; +} diff --git a/users/user/git.nix b/users/user/git.nix index fcafc00..9c1fb20 100644 --- a/users/user/git.nix +++ b/users/user/git.nix @@ -1,10 +1,17 @@ { pkgs, ... }: { - programs.git = { - enable = true; - diff-so-fancy.enable = true; - userName = "William"; - userEmail = "baduhai@proton.me"; + programs = { + git = { + enable = true; + settings.user = { + name = "William"; + email = "baduhai@proton.me"; + }; + }; + diff-so-fancy = { + enable = true; + enableGitIntegration = true; + }; }; -} \ No newline at end of file +} diff --git a/utils.nix b/utils.nix index f25a821..8c20ab9 100644 --- a/utils.nix +++ b/utils.nix @@ -1,4 +1,5 @@ { inputs, lib }: + let inherit (inputs) self @@ -7,8 +8,14 @@ let home-manager agenix ; + + # Import shared service definitions + sharedServices = import ./shared/services.nix; in + { + # Re-export shared services for use in host configs + inherit (sharedServices) services; # Tag-based host configuration system mkHost = { @@ -97,9 +104,10 @@ in }; # Tag-based user configuration system - mkUser = + mkHome = { username, + hostname ? null, homeDirectory ? "/home/${username}", tags ? [ ], extraModules ? [ ], @@ -163,7 +171,7 @@ in home-manager.lib.homeManagerConfiguration { inherit pkgs; extraSpecialArgs = { - inherit inputs; + inherit inputs hostname; userTags = allTags; }; modules = allModules ++ [ @@ -175,16 +183,41 @@ in # Nginx virtual host utilities mkNginxVHosts = - { - acmeHost, - domains, - }: + { domains }: let - commonVHostConfig = { - useACMEHost = acmeHost; - forceSSL = true; - kTLS = true; - }; + # Extract domain name and apply it as useACMEHost + mkVHostConfig = domain: config: + lib.recursiveUpdate { + useACMEHost = domain; + forceSSL = true; + kTLS = true; + } config; in - lib.mapAttrs (_: lib.recursiveUpdate commonVHostConfig) domains; + lib.mapAttrs mkVHostConfig domains; + + # Split DNS utilities for unbound + # Generates unbound view config from a list of DNS entries + mkSplitDNS = + entries: + let + # Generate local-data entries for all domains + tailscaleData = map (e: ''"${e.domain}. IN A ${e.tailscaleIP}"'') entries; + lanData = map (e: ''"${e.domain}. IN A ${e.lanIP}"'') entries; + in + [ + # Single Tailscale view with all domains + { + name = "tailscale"; + view-first = true; + local-zone = ''"baduhai.dev." transparent''; + local-data = tailscaleData; + } + # Single LAN view with all domains + { + name = "lan"; + view-first = true; + local-zone = ''"baduhai.dev." transparent''; + local-data = lanData; + } + ]; }