diff --git a/.github/workflows/eval.yaml b/.github/workflows/eval.yaml new file mode 100644 index 0000000..528dd53 --- /dev/null +++ b/.github/workflows/eval.yaml @@ -0,0 +1,51 @@ +name: Eval NixOS Configurations + +on: + push: + branches: + - deploy + workflow_dispatch: + +permissions: + contents: write + +jobs: + deploy: + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + ref: deploy + + - name: Install Nix + uses: cachix/install-nix-action@v25 + + - name: Configure Git + run: | + git config --global user.name "GitHub Actions Bot" + git config --global user.email "actions@github.com" + + - name: Process Configurations + run: | + git checkout -b deploy-comin-eval + mkdir -p eval + hosts=$(nix flake show --json | jq -r '.nixosConfigurations | keys[]') + echo "Found hosts: $hosts" + + for host in $hosts; do + echo "Eval derivation for $host" + if ! nix show-derivation -L ".#nixosConfigurations.$host.config.system.build.toplevel" > "eval/$host.json"; then + echo "❌ Failed to evaluate $host" + else + echo "✅ Successfully evaluated $host" + fi + done + + echo "Total hosts: $(echo "$hosts" | wc -w)" + echo "Failed hosts: $failed_hosts" + + git add eval/ + git commit -m "Update deployment configurations for all hosts" + + git push origin deploy-comin-eval diff --git a/.sops.yaml b/.sops.yaml index c092203..ad2d8e4 100644 --- a/.sops.yaml +++ b/.sops.yaml @@ -15,6 +15,7 @@ creation_rules: - age: - *xin - *host-calcite + - *host-weilite - *host-massicot - *host-thorite - *host-biotite diff --git a/flake.lock b/flake.lock index c23bdb6..8b8ea79 100644 --- a/flake.lock +++ b/flake.lock @@ -2,11 +2,11 @@ "nodes": { "catppuccin": { "locked": { - "lastModified": 1731232837, - "narHash": "sha256-0aIwr/RC/oe7rYkfJb47xjdEQDSNcqpFGsEa+EPlDEs=", + "lastModified": 1733001911, + "narHash": "sha256-uX/9m0TbdhEzuWA0muM5mI/AaWcLiDLjCCyu5Qr9MRk=", "owner": "catppuccin", "repo": "nix", - "rev": "32359bf226fe874d3b7a0a5753d291a4da9616fe", + "rev": "a817009ebfd2cca7f70a77884e5098d0a8c83f8e", "type": "github" }, "original": { @@ -68,11 +68,11 @@ ] }, "locked": { - "lastModified": 1732645828, - "narHash": "sha256-+4U2I2653JvPFxcux837ulwYS864QvEueIljUkwytsk=", + "lastModified": 1733168902, + "narHash": "sha256-8dupm9GfK+BowGdQd7EHK5V61nneLfr9xR6sc5vtDi0=", "owner": "nix-community", "repo": "disko", - "rev": "869ba3a87486289a4197b52a6c9e7222edf00b3e", + "rev": "785c1e02c7e465375df971949b8dcbde9ec362e5", "type": "github" }, "original": { @@ -167,6 +167,27 @@ "type": "github" } }, + "flake-parts_3": { + "inputs": { + "nixpkgs-lib": [ + "nur", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1733312601, + "narHash": "sha256-4pDvzqnegAfRkPwO3wmwBhVi/Sye1mzps0zHWYnP88c=", + "owner": "hercules-ci", + "repo": "flake-parts", + "rev": "205b12d8b7cd4802fbcb8e8ef6a0f1408781a4f9", + "type": "github" + }, + "original": { + "owner": "hercules-ci", + "repo": "flake-parts", + "type": "github" + } + }, "flake-utils": { "locked": { "lastModified": 1659877975, @@ -238,11 +259,11 @@ ] }, "locked": { - "lastModified": 1730302582, - "narHash": "sha256-W1MIJpADXQCgosJZT8qBYLRuZls2KSiKdpnTVdKBuvU=", + "lastModified": 1730814269, + "narHash": "sha256-fWPHyhYE6xvMI1eGY3pwBTq85wcy1YXqdzTZF+06nOg=", "owner": "cachix", "repo": "git-hooks.nix", - "rev": "af8a16fe5c264f5e9e18bcee2859b40a656876cf", + "rev": "d70155fdc00df4628446352fc58adc640cd705c2", "type": "github" }, "original": { @@ -281,11 +302,11 @@ ] }, "locked": { - "lastModified": 1731786860, - "narHash": "sha256-130gQ5k8kZlxjBEeLpE+SvWFgSOFgQFeZlqIik7KgtQ=", + "lastModified": 1733754861, + "narHash": "sha256-3JKzIou54yjiMVmvgdJwopekEvZxX3JDT8DpKZs4oXY=", "owner": "nix-community", "repo": "home-manager", - "rev": "1bd5616e33c0c54d7a5b37db94160635a9b27aeb", + "rev": "9ebaa80a227eaca9c87c53ed515ade013bc2bca9", "type": "github" }, "original": { @@ -303,11 +324,11 @@ ] }, "locked": { - "lastModified": 1730490306, - "narHash": "sha256-AvCVDswOUM9D368HxYD25RsSKp+5o0L0/JHADjLoD38=", + "lastModified": 1731235328, + "narHash": "sha256-NjavpgE9/bMe/ABvZpyHIUeYF1mqR5lhaep3wB79ucs=", "owner": "nix-community", "repo": "home-manager", - "rev": "1743615b61c7285976f85b303a36cdf88a556503", + "rev": "60bb110917844d354f3c18e05450606a435d2d10", "type": "github" }, "original": { @@ -332,16 +353,16 @@ ] }, "locked": { - "lastModified": 1729544999, - "narHash": "sha256-YcyJLvTmN6uLEBGCvYoMLwsinblXMkoYkNLEO4WnKus=", + "lastModified": 1729958008, + "narHash": "sha256-EiOq8jF4Z/zQe0QYVc3+qSKxRK//CFHMB84aYrYGwEs=", "owner": "NuschtOS", "repo": "ixx", - "rev": "65c207c92befec93e22086da9456d3906a4e999c", + "rev": "9fd01aad037f345350eab2cd45e1946cc66da4eb", "type": "github" }, "original": { "owner": "NuschtOS", - "ref": "v0.0.5", + "ref": "v0.0.6", "repo": "ixx", "type": "github" } @@ -355,17 +376,17 @@ "nixvim": "nixvim" }, "locked": { - "lastModified": 1730642581, - "narHash": "sha256-Tcq+RnctJTm+TUr1fN3ivqYNcd1pJnHYzLDQdgUCX70=", + "lastModified": 1732936640, + "narHash": "sha256-NcluA0L+ZV5MUj3UuQhlkGCj8KoEhX/ObWlMHZ/F/ac=", "ref": "refs/heads/master", - "rev": "a09d2b94efb5e2d801275a244eedaab0816f3702", - "revCount": 18, + "rev": "a3709a89797ea094f82d38edeb4a538c07c8c3fa", + "revCount": 20, "type": "git", - "url": "https://git.xinyang.life/xin/nixvim" + "url": "https://git.xiny.li/xin/nixvim" }, "original": { "type": "git", - "url": "https://git.xinyang.life/xin/nixvim" + "url": "https://git.xiny.li/xin/nixvim" } }, "nix-darwin": { @@ -377,11 +398,11 @@ ] }, "locked": { - "lastModified": 1730448474, - "narHash": "sha256-qE/cYKBhzxHMtKtLK3hlSR3uzO1pWPGLrBuQK7r0CHc=", + "lastModified": 1731153869, + "narHash": "sha256-3Ftf9oqOypcEyyrWJ0baVkRpvQqroK/SVBFLvU3nPuc=", "owner": "lnl7", "repo": "nix-darwin", - "rev": "683d0c4cd1102dcccfa3f835565378c7f3cbe05e", + "rev": "5c74ab862c8070cbf6400128a1b56abb213656da", "type": "github" }, "original": { @@ -418,11 +439,11 @@ ] }, "locked": { - "lastModified": 1731814505, - "narHash": "sha256-l9ryrx1Twh08a+gxrMGM9O/aZKEimZfa6sZVyPCImgI=", + "lastModified": 1733629314, + "narHash": "sha256-U0vivjQFAwjNDYt49Krevs1murX9hKBFe2Ye0cHpgbU=", "owner": "Mic92", "repo": "nix-index-database", - "rev": "bdba246946fb079b87b4cada4df9b1cdf1c06132", + "rev": "f1e477a7dd11e27e7f98b646349cd66bbabf2fb8", "type": "github" }, "original": { @@ -442,11 +463,11 @@ ] }, "locked": { - "lastModified": 1731808759, - "narHash": "sha256-WwJqguc/5Q7HEwHlgDzDT8mtd8ZxInxZM2neJKC1oh8=", + "lastModified": 1733795858, + "narHash": "sha256-K595Q2PrZv2iiumdBkwM2G456T2lKsLD71bn/fbJiQ0=", "owner": "nix-community", "repo": "nix-vscode-extensions", - "rev": "5cf92678e6799ce45442dee4c9cb8094843c7cfa", + "rev": "66ced222ef9235f90dbdd754ede3d6476722aaa9", "type": "github" }, "original": { @@ -457,11 +478,11 @@ }, "nixos-hardware": { "locked": { - "lastModified": 1731797098, - "narHash": "sha256-UhWmEZhwJZmVZ1jfHZFzCg+ZLO9Tb/v3Y6LC0UNyeTo=", + "lastModified": 1733481457, + "narHash": "sha256-IS3bxa4N1VMSh3/P6vhEAHQZecQ3oAlKCDvzCQSO5Is=", "owner": "NixOS", "repo": "nixos-hardware", - "rev": "672ac2ac86f7dff2f6f3406405bddecf960e0db6", + "rev": "e563803af3526852b6b1d77107a81908c66a9fcf", "type": "github" }, "original": { @@ -473,11 +494,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1730200266, - "narHash": "sha256-l253w0XMT8nWHGXuXqyiIC/bMvh1VRszGXgdpQlfhvU=", + "lastModified": 1731139594, + "narHash": "sha256-IigrKK3vYRpUu+HEjPL/phrfh7Ox881er1UEsZvw9Q4=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "807e9154dcb16384b1b765ebe9cd2bba2ac287fd", + "rev": "76612b17c0ce71689921ca12d9ffdc9c23ce40b2", "type": "github" }, "original": { @@ -501,11 +522,11 @@ }, "nixpkgs-stable": { "locked": { - "lastModified": 1731652201, - "narHash": "sha256-XUO0JKP1hlww0d7mm3kpmIr4hhtR4zicg5Wwes9cPMg=", + "lastModified": 1733730953, + "narHash": "sha256-dlK7n82FEyZlHH7BFHQAM5tua+lQO1Iv7aAtglc1O5s=", "owner": "nixos", "repo": "nixpkgs", - "rev": "c21b77913ea840f8bcf9adf4c41cecc2abffd38d", + "rev": "7109b680d161993918b0a126f38bc39763e5a709", "type": "github" }, "original": { @@ -515,29 +536,13 @@ "type": "github" } }, - "nixpkgs-stable_2": { - "locked": { - "lastModified": 1731797254, - "narHash": "sha256-df3dJApLPhd11AlueuoN0Q4fHo/hagP75LlM5K1sz9g=", - "owner": "NixOS", - "repo": "nixpkgs", - "rev": "e8c38b73aeb218e27163376a2d617e61a2ad9b59", - "type": "github" - }, - "original": { - "owner": "NixOS", - "ref": "release-24.05", - "repo": "nixpkgs", - "type": "github" - } - }, "nixpkgs_2": { "locked": { - "lastModified": 1731819057, - "narHash": "sha256-nfqKsQhFCakM+eIKGf/JWu/g56rOPoGny10EZN8q7R0=", + "lastModified": 1733805440, + "narHash": "sha256-AQdCeGt3dMV9/cchlWGMcP0Z8qM47V+B0p7cSRr+HhA=", "owner": "xinyangli", "repo": "nixpkgs", - "rev": "b2644ed7258502987ad4a70cf8959bf5a26ce26d", + "rev": "61b1078fca3a097ce06ada68a6f2766347eed02c", "type": "github" }, "original": { @@ -547,6 +552,22 @@ "type": "github" } }, + "nixpkgs_3": { + "locked": { + "lastModified": 1733581040, + "narHash": "sha256-Qn3nPMSopRQJgmvHzVqPcE3I03zJyl8cSbgnnltfFDY=", + "owner": "nixos", + "repo": "nixpkgs", + "rev": "22c3f2cf41a0e70184334a958e6b124fb0ce3e01", + "type": "github" + }, + "original": { + "owner": "nixos", + "ref": "nixos-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, "nixvim": { "inputs": { "devshell": "devshell", @@ -560,11 +581,11 @@ "treefmt-nix": "treefmt-nix" }, "locked": { - "lastModified": 1730569492, - "narHash": "sha256-NByr7l7JetL9kIrdCOcRqBu+lAkruYXETp1DMiDHNQs=", + "lastModified": 1731527733, + "narHash": "sha256-12OpSgbLDiKmxvBXwVracIfGI9FpjFyHpa1r0Ho+NFA=", "owner": "nix-community", "repo": "nixvim", - "rev": "6f210158b03b01a1fd44bf3968165e6da80635ce", + "rev": "f11a877bcc1d66cc8bd7990c704f91c1e99c7d08", "type": "github" }, "original": { @@ -574,12 +595,17 @@ } }, "nur": { + "inputs": { + "flake-parts": "flake-parts_3", + "nixpkgs": "nixpkgs_3", + "treefmt-nix": "treefmt-nix_2" + }, "locked": { - "lastModified": 1731819675, - "narHash": "sha256-GGp/rEfxRdi1BD9TlHoXxp2g9IuKDp0Jk7wYh1LacP8=", + "lastModified": 1733805328, + "narHash": "sha256-5F49/mOzFb40uUZh71uNr7kBXjDCw5ZfHMbpZjjUVBQ=", "owner": "nix-community", "repo": "NUR", - "rev": "59740d792bea5caa547c9bc7ce366802ecfafb7f", + "rev": "b54fa3d8c020e077d88be036a12a711b84fe2031", "type": "github" }, "original": { @@ -599,11 +625,11 @@ ] }, "locked": { - "lastModified": 1730515563, - "narHash": "sha256-8lklUZRV7nwkPLF3roxzi4C2oyLydDXyAzAnDvjkOms=", + "lastModified": 1731060242, + "narHash": "sha256-43yLsOm/wxBbfYSNDWVJeVv5Ij+23X3BIjFUfsdx/6M=", "owner": "NuschtOS", "repo": "search", - "rev": "9e22bd742480916ff5d0ab20ca2522eaa3fa061e", + "rev": "ef493352f9e1f051e01a55c062731503a6b36b4e", "type": "github" }, "original": { @@ -633,15 +659,14 @@ "inputs": { "nixpkgs": [ "nixpkgs" - ], - "nixpkgs-stable": "nixpkgs-stable_2" + ] }, "locked": { - "lastModified": 1731814239, - "narHash": "sha256-TGnMXCeXS924w9W6CvRFtUCUFr8E/RK138lHxU3vcw8=", + "lastModified": 1733785344, + "narHash": "sha256-pm4cfEcPXripE36PYCl0A2Tu5ruwHEvTee+HzNk+SQE=", "owner": "Mic92", "repo": "sops-nix", - "rev": "47fc1d8c72dbd69b32ecb2019b5b648da3dd20ce", + "rev": "a80af8929781b5fe92ddb8ae52e9027fae780d2a", "type": "github" }, "original": { @@ -717,6 +742,27 @@ "repo": "treefmt-nix", "type": "github" } + }, + "treefmt-nix_2": { + "inputs": { + "nixpkgs": [ + "nur", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1733222881, + "narHash": "sha256-JIPcz1PrpXUCbaccEnrcUS8jjEb/1vJbZz5KkobyFdM=", + "owner": "numtide", + "repo": "treefmt-nix", + "rev": "49717b5af6f80172275d47a418c9719a31a78b53", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "treefmt-nix", + "type": "github" + } } }, "root": "root", diff --git a/flake.nix b/flake.nix index 7e725f2..4da0466 100644 --- a/flake.nix +++ b/flake.nix @@ -43,7 +43,7 @@ }; my-nixvim = { - url = "git+https://git.xinyang.life/xin/nixvim"; + url = "git+https://git.xiny.li/xin/nixvim"; inputs.nixpkgs.follows = "nixpkgs"; }; @@ -84,11 +84,16 @@ overlayModule = { ... }: { - _module.args.my-lib = import ./overlays/my-lib; - nixpkgs.overlays = [ - editorOverlay - (import ./overlays/add-pkgs.nix) - ]; + options.my-lib = nixpkgs.lib.mkOption { + type = nixpkgs.lib.types.attrs; + default = import ./overlays/my-lib; + }; + config = { + nixpkgs.overlays = [ + editorOverlay + (import ./overlays/add-pkgs.nix) + ]; + }; }; deploymentModule = { deployment.targetUser = "xin"; @@ -106,7 +111,6 @@ nodeNixosModules = { calcite = [ nixos-hardware.nixosModules.asus-zephyrus-ga401 - nur.nixosModules.nur catppuccin.nixosModules.catppuccin machines/calcite/configuration.nix (mkHome "xin" "calcite") @@ -142,17 +146,15 @@ user: host: { ... }: { - imports = [ - home-manager.nixosModules.home-manager - { - home-manager = { - sharedModules = sharedHmModules; - useGlobalPkgs = true; - useUserPackages = true; - }; - home-manager.users.${user} = (import ./home).${user}.${host}; - } - ]; + imports = [ home-manager.nixosModules.home-manager ]; + config = { + home-manager = { + sharedModules = sharedHmModules; + useGlobalPkgs = true; + useUserPackages = true; + }; + home-manager.users.${user} = (import ./home).${user}.${host}; + }; }; mkNixos = { @@ -284,16 +286,22 @@ { imports = nodeNixosModules.biotite ++ sharedColmenaModules; }; + + osmium = + { ... }: + { + deployment = { + targetHost = "osmium.coho-tet.ts.net"; + buildOnTarget = false; + }; + imports = nodeNixosModules.osmium ++ sharedColmenaModules; + }; }; nixosConfigurations = { calcite = mkNixos { hostname = "calcite"; }; - - osmium = mkNixos { - hostname = "osmium"; - }; } // self.colmenaHive.nodes; } @@ -303,7 +311,7 @@ pkgs = nixpkgs.legacyPackages.${system}; mkHomeConfiguration = user: host: { - name = user; + name = "${user}-${host}"; value = home-manager.lib.homeManagerConfiguration { inherit pkgs; modules = [ diff --git a/home/xin/calcite.nix b/home/xin/calcite.nix index 9f246cf..d90cc4d 100644 --- a/home/xin/calcite.nix +++ b/home/xin/calcite.nix @@ -125,7 +125,8 @@ in profiles.default = { isDefault = true; userChrome = '' - #titlebar { + + #TabsToolbar { display: none; } @@ -136,7 +137,7 @@ in [titlepreface*="."] #sidebar-header { visibility: collapse !important; } - [titlepreface*="."] #titlebar { + [titlepreface*="."] #TabsToolbar { visibility: collapse; } @@ -148,7 +149,7 @@ in min-width: var(--uc-sidebar-width) !important; width: var(--uc-sidebar-width) !important; max-width: var(--uc-sidebar-width) !important; - z-index:1; + z-index: calc(var(--browser-area-z-index-tabbox) + 1); } #sidebar-box[positionend]{ direction: rtl } @@ -190,12 +191,12 @@ in transition-delay: 0ms !important; } - .sidebar-panel{ - background-color: transparent !important; + .sidebar-placeTree { + /* background-color: transparent !important; */ color: var(--newtab-text-primary-color) !important; } - .sidebar-panel #search-box{ + .sidebar-placeTree #search-box{ -moz-appearance: none !important; background-color: rgba(249,249,250,0.1) !important; color: inherit !important; diff --git a/home/xin/common/default.nix b/home/xin/common/default.nix index 8fbf3bb..728dd93 100644 --- a/home/xin/common/default.nix +++ b/home/xin/common/default.nix @@ -5,13 +5,12 @@ ... }: { - imports = [ ]; + imports = [ + ./modern-unix.nix + ]; home.packages = with pkgs; [ dig - du-dust # du + rust - zoxide # autojumper - ripgrep file man-pages unar @@ -19,7 +18,6 @@ wget tmux ffmpeg - tealdeer rclone wl-clipboard diff --git a/home/xin/common/modern-unix.nix b/home/xin/common/modern-unix.nix new file mode 100644 index 0000000..298fae2 --- /dev/null +++ b/home/xin/common/modern-unix.nix @@ -0,0 +1,17 @@ +{ pkgs, ... }: +{ + home.packages = with pkgs; [ + httpie + curlie + bat + htop + procs + rust-parallel + jq + fd + du-dust # du + rust + zoxide # autojumper + ripgrep + tealdeer + ]; +} diff --git a/machines/biotite/default.nix b/machines/biotite/default.nix index a507675..741e281 100644 --- a/machines/biotite/default.nix +++ b/machines/biotite/default.nix @@ -1,5 +1,7 @@ { + pkgs, lib, + config, ... }: @@ -7,6 +9,12 @@ imports = [ ./hardware-configurations.nix ./services/gotosocial.nix + ./services/synapse.nix + ./services/restic.nix + ./services/miniflux.nix + ./services/hedgedoc.nix + ./services/forgejo.nix + ./services/vaultwarden.nix ]; networking.hostName = "biotite"; @@ -28,20 +36,56 @@ commonSettings = { auth.enable = true; - autoupgrade.enable = true; }; custom.monitoring = { promtail.enable = true; }; + custom.prometheus.exporters = { + enable = true; + node.enable = true; + }; + + services.tailscale.enable = true; + + services.caddy.enable = true; + sops = { defaultSopsFile = ./secrets.yaml; age.sshKeyPaths = [ "/etc/ssh/ssh_host_ed25519_key" ]; }; - services.caddy.enable = true; - services.tailscale.enable = true; + services.postgresql = { + enable = true; + package = pkgs.postgresql_17; + settings = { + allow_alter_system = false; + # DB Version: 17 + # OS Type: linux + # DB Type: mixed + # Total Memory (RAM): 8 GB + # CPUs num: 4 + # Data Storage: ssd + max_connections = 100; + shared_buffers = "2GB"; + effective_cache_size = "6GB"; + maintenance_work_mem = "512MB"; + checkpoint_completion_target = 0.9; + wal_buffers = "16MB"; + default_statistics_target = 100; + random_page_cost = 1.1; + effective_io_concurrency = 200; + work_mem = "5242kB"; + huge_pages = "off"; + min_wal_size = "1GB"; + max_wal_size = "4GB"; + max_worker_processes = 4; + max_parallel_workers_per_gather = 2; + max_parallel_workers = 4; + max_parallel_maintenance_workers = 2; + }; + }; users.users.root.hashedPassword = "$y$j9T$NToEZWJBONjSgRnMd9Ur9/$o6n7a9b8eUILQz4d37oiHCCVnDJ8hZTZt.c.37zFfU."; diff --git a/machines/biotite/secrets.yaml b/machines/biotite/secrets.yaml index 5d8f181..1e71c85 100644 --- a/machines/biotite/secrets.yaml +++ b/machines/biotite/secrets.yaml @@ -1,5 +1,16 @@ gotosocial: oidc_client_secret: ENC[AES256_GCM,data:KVQxzs67sohax2h0Y/jjhnbY4fetrdVvWhBGbqgDSGgBC7QazrOmTA++BSRzMmVv,iv:HIRMc56aLanqQRTWH9E0wzzXymImi0pxK/ccPEP8Fcc=,tag:PMhOLeE3mKIIQveRdfpgpA==,type:str] +synapse: + oidc_client_secret: ENC[AES256_GCM,data:TdZF8Bo+h34fn03sPpt7JEqmP8Cwm8V++q9VDvaapMBc3rlkrVu3iDUhQE2DvJri,iv:/QNX+aYUPpDKIqWZ13TLAznR3ZpUPI8rQHrJuqv7R+g=,tag:lcBIpeWiIXK/NV84uuxNiA==,type:str] +restic: + repo_url: ENC[AES256_GCM,data:ZcBMqwEsyc7zyEftJZj4XkKBzUHwlqd6cjX8xVDn9m26jBL7aP5atpnXDRE9FXY4CuAllFyQZyAOQ2L61Nfx+iplL2ADbSoH,iv:fhNODiyoOlZEqYR2O/GsH2IWTPDr3rXSJgWC/EFDLSA=,tag:nZdKKnpiszSiXxdZI1KQ/A==,type:str] + repo_password: ENC[AES256_GCM,data:9YDOz1tiyykz6zSXboWtIg==,iv:j96mRLXGuD4NZcC0Nv1yXFbtOlr6UborqclefZ7J94w=,tag:MqhSewK2NuckTJBf7xu+lA==,type:str] +miniflux: + oauth2_secret: ENC[AES256_GCM,data:/WtZemrdKU8bQbxzrAn437uqoJSO+yZSUDCnxovXV0HFZYQvAn2rbMrgOdoc1OuP,iv:xENKuGDYS1ctnO/WkGv1TxjtQYZ8p64Ik/lMIIam4Q0=,tag:RbAA0LUmsAQDqEM5+a2quQ==,type:str] +hedgedoc: + client_secret: ENC[AES256_GCM,data:J6lRBM7V6F+gPYVyEbOzsFUQe8+3ggP0r58c655DNt7TGgKGdq95pRvLaghMmBCc,iv:i+eLYwnmG1/bKtad2iM2pwEAC3GZLNaKS5ldbubRvyY=,tag:yxaug6YdYo8RR3YOyHd/iA==,type:str] +forgejo: + client_secret: ENC[AES256_GCM,data:5OXhaGzBCbge2tvTaU4ry6/KoavQeYJ45EuakCQJlxb5gMXjRK/s+feF25YJSr2f,iv:TT8j+ciKeSQCZzu1E7D70hWNFpn0cGiomz7jURXjavc=,tag:JVJR033Pc2vaLudaovkl8w==,type:str] sops: kms: [] gcp_kms: [] @@ -24,8 +35,8 @@ sops: RzBMVDNjS29SUkdRK3dIV01sU0hYR3cK1SbvKAM6Gpsffv3HIi/WtWnCZUBic0AT ZRv4pvJBx1oxWsKIHW0t6VrqWMQ+suup8p6dW+h5HE8Z4ciIMrXLEg== -----END AGE ENCRYPTED FILE----- - lastmodified: "2024-12-02T05:10:32Z" - mac: ENC[AES256_GCM,data:ZAdFsjVuk1Fiv+DKmHrc1yu1XQpRDmRHaQhu5hduSZUa1W1cXdTlChvIW5vADFg5tVCjuYptuLvCMW+ZSQeqqG2ntHHZ+IkuovZzKFuc+BIiL/jF2ZzbyJ7X4Wj1GziCScHVxx98dgbpFoufHe6N3wCaHmngo1RYsY5N1RRbRdU=,iv:5IMQ0kOX9UAOm8bcsQRyu6zu8GJjvnHFufCNjY0s9UI=,tag:zBEPSR9DZDpwbCaIka8mXA==,type:str] + lastmodified: "2024-12-04T05:07:32Z" + mac: ENC[AES256_GCM,data:hD7645epMVYHU6K1AZsHu+fp/PMIqqiZpv7K4Vxzo84slzn0CfZSYaVaYxKNGjOIgEGN9D2FFmq9WL6ChMskMfqqafY7qDpSQqFp9TUwb5jN34XcQg9vplfNw+lMqsnDCt1HENWErRnlDxTI2ctSEcx3UKGBOQ3ttLzUIySdnFY=,iv:reOsqvc8E3l8yxb5gVcqF/rU2o2yKmaUyGNRNT+Skx8=,tag:eBoV8G+X0cPs3Q1xAuv55w==,type:str] pgp: [] unencrypted_suffix: _unencrypted version: 3.9.1 diff --git a/machines/biotite/services/forgejo.nix b/machines/biotite/services/forgejo.nix new file mode 100644 index 0000000..7321b89 --- /dev/null +++ b/machines/biotite/services/forgejo.nix @@ -0,0 +1,115 @@ +{ + config, + pkgs, + lib, + ... +}: +let + inherit (lib) getExe; + inherit (config.my-lib.settings) idpUrl forgejoDomain forgejoGitDomain; + settings = { + service.DISABLE_REGISTRATION = true; + server = { + DOMAIN = forgejoDomain; + ROOT_URL = "https://${forgejoDomain}"; + HTTP_ADDR = "/var/run/forgejo/forgejo.sock"; + START_SSH_SERVER = false; + SSH_USER = config.services.forgejo.user; + SSH_DOMAIN = forgejoGitDomain; + SSH_PORT = 22; + PROTOCOL = "http+unix"; + LFS_MAX_FILE_SIZE = 10737418240; + LANDING_PAGE = "/explore/repos"; + }; + repository = { + ENABLE_PUSH_CREATE_USER = true; + }; + service = { + ENABLE_BASIC_AUTHENTICATION = false; + }; + oauth2 = { + ENABLED = false; # Disable forgejo as oauth2 provider + }; + oauth2_client = { + ACCOUNT_LINKING = "auto"; + USERNAME = "email"; + ENABLE_AUTO_REGISTRATION = true; + UPDATE_AVATAR = false; + OPENID_CONNECT_SCOPES = "openid profile email groups"; + }; + metrics = { + # ENABLED = true; + }; + other = { + SHOW_FOOTER_VERSION = false; + }; + }; +in +{ + sops.secrets."forgejo/client_secret" = { }; + sops.templates."forgejo/env" = { + content = '' + CLIENT_SECRET=${config.sops.placeholder."forgejo/client_secret"} + ''; + owner = config.systemd.services.forgejo.serviceConfig.User; + }; + + services.forgejo = { + enable = true; + inherit settings; + # Use cutting edge instead of lts + package = pkgs.forgejo; + # repositoryRoot = "/mnt/storage/forgejo/repositories"; + lfs = { + enable = true; + # contentDir = "/mnt/storage/forgejo/lfs"; + }; + }; + + systemd.services.forgejo = { + serviceConfig = { + EnvironmentFile = config.sops.templates."forgejo/env".path; + preStart = + let + providerName = "kanidm"; + args = lib.concatStringsSep " " [ + "--name ${providerName}" + "--provider openidConnect" + "--key forgejo" + "--secret $CLIENT_SECRET" + "--icon-url ${idpUrl}/pkg/img/favicon.png" + "--group-claim-name forgejo_role --admin-group Admin" + ]; + exe = getExe config.services.forgejo.package; + in + '' + provider_id=$(${exe} admin auth list | ${pkgs.gnugrep}/bin/grep -w '${providerName}' | cut -f1) + if [[ -z "$provider_id" ]]; then + ${exe} admin auth add-oauth ${args} + else + ${exe} admin auth update-oauth --id "$provider_id" ${args} + fi + ''; + }; + }; + + users.users.git = { + isSystemUser = true; + useDefaultShell = true; + group = "git"; + extraGroups = [ "forgejo" ]; + }; + users.groups.git = { }; + + services.caddy = { + virtualHosts."https://${forgejoDomain}".extraConfig = with settings; '' + ${ + if server.PROTOCOL == "http+unix" then + "reverse_proxy unix/${server.HTTP_ADDR}" + else + "reverse_proxy http://${server.HTTP_ADDR}:${toString server.HTTP_PORT}" + } + ''; + }; + users.users.caddy.extraGroups = lib.optional (settings.server.PROTOCOL == "http+unix") "forgejo"; +} diff --git a/machines/biotite/services/gotosocial.nix b/machines/biotite/services/gotosocial.nix index 743b3f7..3114cf6 100644 --- a/machines/biotite/services/gotosocial.nix +++ b/machines/biotite/services/gotosocial.nix @@ -1,4 +1,7 @@ { config, ... }: +let + inherit (config.my-lib.settings) idpUrl; +in { sops.secrets."gotosocial/oidc_client_secret" = { owner = "gotosocial"; @@ -23,17 +26,17 @@ instance-expose-public-timeline = true; oidc-enabled = true; oidc-idp-name = "Kanidm"; - oidc-issuer = "https://auth.xinyang.life/oauth2/openid/gotosocial"; + oidc-issuer = "${idpUrl}/oauth2/openid/gotosocial"; oidc-client-id = "gotosocial"; oidc-link-existing = true; }; + setupPostgresqlDB = true; environmentFile = config.sops.templates."gotosocial.env".path; }; services.caddy = { virtualHosts."https://gts.xiny.li".extraConfig = '' - encode zstd gzip - reverse_proxy * http://${config.services.gotosocial.settings.bind-address}:${toString config.services.gotosocial.settings.port} { + reverse_proxy http://${config.services.gotosocial.settings.bind-address}:${toString config.services.gotosocial.settings.port} { flush_interval -1 } ''; diff --git a/machines/biotite/services/hedgedoc.nix b/machines/biotite/services/hedgedoc.nix new file mode 100644 index 0000000..c8b33bc --- /dev/null +++ b/machines/biotite/services/hedgedoc.nix @@ -0,0 +1,45 @@ +{ config, pkgs, ... }: +let + inherit (config.my-lib.settings) hedgedocDomain idpUrl; +in +{ + sops.secrets."hedgedoc/client_secret" = { }; + sops.templates."hedgedoc/env" = { + content = '' + CMD_OAUTH2_CLIENT_SECRET=${config.sops.placeholder."hedgedoc/client_secret"} + ''; + owner = config.systemd.services.hedgedoc.serviceConfig.User; + }; + services.hedgedoc = { + enable = true; + environmentFile = config.sops.templates."hedgedoc/env".path; + settings = { + domain = hedgedocDomain; + protocolUseSSL = true; # use SSL for resources + path = "/run/hedgedoc/hedgedoc.sock"; + email = false; + allowEmailRegister = false; + oauth2 = { + baseURL = "${idpUrl}/oauth2/openid/hedgedoc"; + authorizationURL = "${idpUrl}/ui/oauth2"; + tokenURL = "${idpUrl}/oauth2/token"; + userProfileURL = "${idpUrl}/oauth2/openid/hedgedoc/userinfo"; + userProfileEmailAttr = "email"; + userProfileUsernameAttr = "name"; + userProfileDisplayNameAttr = "preferred_name"; + scope = "openid email profile"; + clientID = "hedgedoc"; + }; + enableStatsApi = true; + allowAnonymous = false; + defaultPermission = "private"; + }; + }; + services.caddy = { + enable = true; + virtualHosts."https://${hedgedocDomain}".extraConfig = '' + reverse_proxy unix/${config.services.hedgedoc.settings.path} + ''; + }; + users.users.caddy.extraGroups = [ "hedgedoc" ]; +} diff --git a/machines/biotite/services/miniflux.nix b/machines/biotite/services/miniflux.nix new file mode 100644 index 0000000..1bee3dc --- /dev/null +++ b/machines/biotite/services/miniflux.nix @@ -0,0 +1,35 @@ +{ config, pkgs, ... }: +let + inherit (config.my-lib.settings) idpUrl minifluxUrl; +in +{ + sops = { + secrets."miniflux/oauth2_secret" = { }; + }; + + services.miniflux = { + enable = true; + config = { + LOG_LEVEL = "debug"; + LISTEN_ADDR = "127.0.0.1:58173"; + BASE_URL = "https://rss.xiny.li/"; + OAUTH2_PROVIDER = "oidc"; + OAUTH2_CLIENT_ID = "miniflux"; + OAUTH2_CLIENT_SECRET_FILE = "%d/oauth2_secret"; + OAUTH2_REDIRECT_URL = "${minifluxUrl}/oauth2/oidc/callback"; + OAUTH2_OIDC_DISCOVERY_ENDPOINT = "${idpUrl}/oauth2/openid/miniflux"; + OAUTH2_USER_CREATION = 1; + CREATE_ADMIN = 0; + }; + createDatabaseLocally = true; + }; + + systemd.services.miniflux.serviceConfig.LoadCredential = [ + "oauth2_secret:${config.sops.secrets."miniflux/oauth2_secret".path}" + ]; + + services.caddy.virtualHosts.${minifluxUrl}.extraConfig = '' + reverse_proxy ${config.services.miniflux.config.LISTEN_ADDR} + ''; + +} diff --git a/machines/biotite/services/restic.nix b/machines/biotite/services/restic.nix new file mode 100644 index 0000000..2e53c46 --- /dev/null +++ b/machines/biotite/services/restic.nix @@ -0,0 +1,55 @@ +{ + config, + lib, + pkgs, + ... +}: +let + sqliteBackup = fromPath: toPath: file: '' + mkdir -p ${toPath} + ${lib.getExe pkgs.sqlite} ${fromPath} ".backup '${toPath}/${file}'" + ''; +in +{ + sops.secrets = { + "restic/repo_url" = { + sopsFile = ../secrets.yaml; + }; + "restic/repo_password" = { + sopsFile = ../secrets.yaml; + }; + }; + + custom.restic = { + enable = true; + paths = [ + "/backup/db" + "/backup/var/lib" + ]; + backupPrepareCommand = [ + '' + mkdir -p /backup/var + ${pkgs.btrfs-progs}/bin/btrfs subvolume snapshot -r /var/lib /backup/var/lib + '' + ]; + backupCleanupCommand = [ + '' + ${pkgs.btrfs-progs}/bin/btrfs subvolume delete /backup/var/lib + '' + ]; + btrfsRoots = [ ]; + }; + + services.postgresqlBackup = { + enable = true; + compression = "zstd"; + compressionLevel = 9; + location = "/backup/db/postgresql"; + }; + + services.restic.backups.${config.networking.hostName} = { + extraBackupArgs = [ + "--limit-upload=1024" + ]; + }; +} diff --git a/machines/biotite/services/synapse.nix b/machines/biotite/services/synapse.nix new file mode 100644 index 0000000..e352495 --- /dev/null +++ b/machines/biotite/services/synapse.nix @@ -0,0 +1,120 @@ +{ + config, + lib, + pkgs, + ... +}: +let + inherit (config.my-lib.settings) idpUrl synapseDelegateUrl synapseUrl; + port-synapse = 6823; +in +{ + sops.secrets."synapse/oidc_client_secret" = { + owner = "matrix-synapse"; + }; + + nixpkgs.config.permittedInsecurePackages = [ + "olm-3.2.16" + ]; + + services.postgresql = { + # Not using ensure here because LC_COLLATE and LC_CTYPE must be provided + # at db creation + initialScript = pkgs.writeText "synapse-init.sql" '' + CREATE ROLE "matrix-synapse" WITH LOGIN PASSWORD 'synapse'; + CREATE DATABASE "matrix-synapse" WITH OWNER "matrix-synapse" + TEMPLATE template0 + LC_COLLATE = "C" + LC_CTYPE = "C"; + ''; + }; + + services.matrix-synapse = { + enable = true; + withJemalloc = true; + settings = { + server_name = "xiny.li"; + public_baseurl = synapseDelegateUrl; + database = { + name = "psycopg2"; + args = { + user = "matrix-synapse"; + }; + }; + listeners = [ + { + bind_addresses = [ + "127.0.0.1" + ]; + port = port-synapse; + resources = [ + { + compress = true; + names = [ + "client" + "federation" + ]; + } + ]; + tls = false; + type = "http"; + x_forwarded = true; + } + ]; + experimental_features = { + # Room summary api + msc3266_enabled = true; + # Removing account data + msc3391_enabled = true; + # Thread notifications + msc3773_enabled = true; + # Remotely toggle push notifications for another client + msc3881_enabled = true; + # Remotely silence local notifications + msc3890_enabled = true; + # Remove legacy mentions + msc4210_enabled = true; + }; + oidc_providers = [ + { + idp_id = "Kanidm"; + idp_name = lib.removePrefix "https://" idpUrl; + issuer = "${idpUrl}/oauth2/openid/synapse"; + authorization_endpoint = "${idpUrl}/ui/oauth2"; + token_endpoint = "${idpUrl}/oauth2/token"; + userinfo_endpoint = "${idpUrl}/oauth2/openid/synapse/userinfo"; + client_id = "synapse"; + client_secret_path = config.sops.secrets."synapse/oidc_client_secret".path; + scopes = [ + "openid" + "profile" + ]; + allow_existing_users = true; + backchannel_logout_enabled = true; + user_mapping_provider.config = { + confirm_localpart = true; + localpart_template = "{{ user.preferred_username }}"; + display_name_template = "{{ user.name }}"; + }; + } + ]; + }; + }; + + services.caddy = { + virtualHosts.${synapseUrl}.extraConfig = '' + header /.well-known/matrix/* Content-Type application/json + header /.well-known/matrix/* Access-Control-Allow-Origin * + respond /.well-known/matrix/server `{"m.server":"synapse.xiny.li:443"}` + respond /.well-known/matrix/client `{"m.homeserver":{"base_url":"${synapseDelegateUrl}"}}` + ''; + virtualHosts.${synapseDelegateUrl}.extraConfig = '' + reverse_proxy /_matrix/* 127.0.0.1:${toString port-synapse} + reverse_proxy /_synapse/client/* 127.0.0.1:${toString port-synapse} + ''; + }; + + networking.firewall.allowedTCPPorts = [ + 443 + ]; +} diff --git a/machines/biotite/services/vaultwarden.nix b/machines/biotite/services/vaultwarden.nix new file mode 100644 index 0000000..f7c55c3 --- /dev/null +++ b/machines/biotite/services/vaultwarden.nix @@ -0,0 +1,25 @@ +{ config, pkgs, ... }: +let + inherit (config.my-lib.settings) vaultwardenUrl; +in +{ + services.vaultwarden = { + enable = true; + dbBackend = "sqlite"; + config = { + DOMAIN = "${vaultwardenUrl}"; + SIGNUPS_ALLOWED = false; + + ROCKET_ADDRESS = "127.0.0.1"; + ROCKET_PORT = 8222; + + ROCKET_LOG = "normal"; + }; + }; + + services.caddy = { + virtualHosts.${vaultwardenUrl}.extraConfig = with config.services.vaultwarden.config; '' + reverse_proxy ${ROCKET_ADDRESS}:${toString ROCKET_PORT} + ''; + }; +} diff --git a/machines/calcite/configuration.nix b/machines/calcite/configuration.nix index 27760b5..c5afb73 100644 --- a/machines/calcite/configuration.nix +++ b/machines/calcite/configuration.nix @@ -16,7 +16,7 @@ in ]; commonSettings = { - auth.enable = true; + # auth.enable = true; nix = { signing.enable = true; }; @@ -51,7 +51,6 @@ in }; # services.gnome.gnome-keyring.enable = lib.mkForce false; security.pam.services.login.enableGnomeKeyring = lib.mkForce false; - services.ssh-tpm-agent.enable = true; programs.ssh.agentPKCS11Whitelist = "${config.security.tpm2.pkcs11.package}/lib/libtpm_pkcs11.so"; @@ -66,18 +65,7 @@ in }; }; - programs.oidc-agent.enable = true; - programs.oidc-agent.providers = [ - { - issuer = "https://home.xinyang.life:9201"; - pubclient = { - client_id = "xdXOt13JKxym1B1QcEncf2XDkLAexMBFwiT9j6EfhhHFJhs2KM9jbjTmf8JBXE69"; - client_secret = "UBntmLjC2yYCeHwsyj73Uwo9TAaecAetRwMw0xYcvNL9yRdLSUi0hUAHfvCHFeFh"; - scope = "openid offline_access profile email"; - }; - } - ]; - + programs.vim.enable = true; programs.vim.defaultEditor = true; # Keep this even if enabled in home manager @@ -307,23 +295,22 @@ in bitwarden # Browser - (chromium.override { - commandLineArgs = [ - "--ozone-platform-hint=auto" - "--enable-wayland-ime" - ]; - }) - brave + chromium # Writting zotero # onlyoffice-bin - config.nur.repos.linyinfeng.wemeet + wemeet virt-manager + wineWowPackages.waylandFull + winetricks ]; + services.esphome.enable = true; + users.groups.dialout.members = [ "xin" ]; + system.stateVersion = "22.05"; system.switch.enable = false; @@ -352,16 +339,16 @@ in ]; }; - custom.forgejo-actions-runner = { - enable = false; - tokenFile = config.sops.secrets."gitea/envfile".path; - settings = { - runner.capacity = 2; - runner.fetch_timeout = "120s"; - runner.fetch_interval = "30s"; - }; - }; - + # custom.forgejo-actions-runner = { + # enable = false; + # tokenFile = config.sops.secrets."gitea/envfile".path; + # settings = { + # runner.capacity = 2; + # runner.fetch_timeout = "120s"; + # runner.fetch_interval = "30s"; + # }; + # }; + # custom.prometheus = { exporters.node.enable = true; }; @@ -379,15 +366,12 @@ in # Fonts fonts = { packages = with pkgs; [ - (nerdfonts.override { - fonts = [ - "FiraCode" - "FiraMono" - "JetBrainsMono" - "RobotoMono" - "Ubuntu" - ]; - }) + nerd-fonts.ubuntu-sans + nerd-fonts.ubuntu + nerd-fonts.fira-code + nerd-fonts.fira-mono + nerd-fonts.jetbrains-mono + nerd-fonts.roboto-mono noto-fonts noto-fonts-emoji liberation_ttf diff --git a/machines/calcite/network.nix b/machines/calcite/network.nix index 31203ad..27e77ee 100644 --- a/machines/calcite/network.nix +++ b/machines/calcite/network.nix @@ -1,4 +1,9 @@ -{ config, pkgs, lib, ... }: +{ + config, + pkgs, + lib, + ... +}: { imports = [ ]; @@ -24,16 +29,9 @@ services.dae.enable = true; services.dae.configFile = "/var/lib/dae/config.dae"; - systemd.services.dae.after = lib.mkIf (config.networking.networkmanager.enable) [ "NetworkManager-wait-online.service" ]; - - custom.sing-box = { - enable = false; - configFile = { - urlFile = config.sops.secrets.sing_box_url.path; - hash = "6ca5bc8a16f8c413227690aceeee2c12c02cab09473c216b849af1e854b98588"; - }; - overrideSettings.experimental.clash_api.external_ui = "${config.nur.repos.linyinfeng.yacd}"; - }; + systemd.services.dae.after = lib.mkIf (config.networking.networkmanager.enable) [ + "NetworkManager-wait-online.service" + ]; # Open ports in the firewall. networking.firewall.enable = true; diff --git a/machines/dolomite/common.nix b/machines/dolomite/common.nix index c50c1a9..65b10c7 100644 --- a/machines/dolomite/common.nix +++ b/machines/dolomite/common.nix @@ -3,6 +3,7 @@ config = { sops = { age.sshKeyPaths = [ "/etc/ssh/ssh_host_ed25519_key" ]; + defaultSopsFile = ./secrets/secrets.yaml; secrets = { wg_private_key = { owner = "root"; @@ -12,14 +13,6 @@ owner = "root"; sopsFile = ./secrets + "/${config.networking.hostName}.yaml"; }; - "sing-box/password" = { - owner = "root"; - sopsFile = ./secrets/secrets.yaml; - }; - "sing-box/uuid" = { - owner = "root"; - sopsFile = ./secrets/secrets.yaml; - }; }; }; swapDevices = [ @@ -32,6 +25,8 @@ custom.prometheus.exporters = { enable = true; node.enable = true; + blackbox.enable = true; + v2ray.enable = true; }; custom.monitoring = { @@ -44,6 +39,11 @@ auth.enable = true; proxyServer = { enable = true; + users = [ + "wyj" + "yhb" + "xin" + ]; }; }; }; diff --git a/machines/dolomite/secrets/secrets.yaml b/machines/dolomite/secrets/secrets.yaml index 53a7131..e0df929 100644 --- a/machines/dolomite/secrets/secrets.yaml +++ b/machines/dolomite/secrets/secrets.yaml @@ -1,6 +1,14 @@ sing-box: - password: ENC[AES256_GCM,data:qCc1v8nAL0oYisRinMDXGrBQA+r6XNoa,iv:eTxtad4kEdE28XqnrZEek8BtXNY1rNgLvGLxlMzRtl4=,tag:s/shWAkYE4DSnScpTY8ulQ==,type:str] - uuid: ENC[AES256_GCM,data:lEpz15sLOVrGDzQwTJyS+tFJY0bMeO265bxocWAjB6qrvxYx,iv:lhk5jl/udUH3AZEuk5ffuvin/qhRUaOZ/3nk1Jaw+DI=,tag:4mKFIVKT+D47njfDsxe9iA==,type:str] + users: + wyj: + password: ENC[AES256_GCM,data:yp+T3eci9RiuZzdmRSq5nTjHaz8e/Rri,iv:hIPc+7YHUnaIdU9O8GGx3r7l3oBA6prQb+KBQV0G+8k=,tag:2GNiBP4PQy+KGHgLupKGSg==,type:str] + uuid: ENC[AES256_GCM,data:Qrgil6G7pjQAQzCCOlstDi27EqqmSuBMhs+RTl9++wrPrIgJ,iv:u+3Z17uX4I6li2qd9UP3y+WaKn7aKfbb3J6H1Pyc1QY=,tag:hSa4AB383/B58XMmZ8LIfQ==,type:str] + yhb: + password: ENC[AES256_GCM,data:TwRct68TePpcZcnpWIQpFaF23WGMre8=,iv:YU4mQNm0rt2u4ItJwQ8nZPEmJi0+lmEIPG2Kxh/nI58=,tag:ukZem38O/b42dEKM3CYa+w==,type:str] + uuid: ENC[AES256_GCM,data:6hVhEqWPLVrn8rCS4x/eapd+iL7JRaXtOGCj9uuPlkGjBTMK,iv:VZ27KWCY6/K5GoNwRNmaRWzqfV7+8iFjtias1vKeGfA=,tag:8mhmZPooxHaGNYdznuFhMQ==,type:str] + xin: + password: ENC[AES256_GCM,data:SRiPFO+Uwy/PT41SIg7eI68wk4AX6so=,iv:aXwP5wa1IrlnvFo/ZL+DYFFHDdWw2Z83de3ApHUTsXo=,tag:sxXoy1FnDxZBQCDeNxphzQ==,type:str] + uuid: ENC[AES256_GCM,data:7xK53SO4x0tOIEIYl6kmmAvnpdsR/tYQoG1t/ytsnO4QqWY3,iv:i694Fnu7g1OA3IGzSaoSGA5/eMPo+I/1TZbYuaQrgNA=,tag:4cUlioJn/IvsvZclgboOSA==,type:str] sops: kms: [] gcp_kms: [] @@ -43,8 +51,8 @@ sops: K1F1SzI2NFNIKzlreVBXSjAxaUxQd28KFaf1uu7OlqIe0TirJFgS3iPjhXPyfNDE m2XUjzdXp+chJCzVOFvpYStqz+e08ADEc+jp3YsTLcxyqvXhQdyL/Q== -----END AGE ENCRYPTED FILE----- - lastmodified: "2024-12-02T05:26:17Z" - mac: ENC[AES256_GCM,data:K94zFWPWGUisLCqDjSLs17QxHXPH4tPU/98Sb4lCnt7IRAIn14x/T+BnInY/DK+DOVLLtzSfuN0kgzzGjSzwJx5Vq1G3MkhngRQQRT9dvODTCMAw6lPt98Ofw1CEEsFQnpYo9zIUlCGKg2YPKFLqE7OjkPxqw7VYvgzr5dDw58s=,iv:3xcJfNX5v/e9HgZt3UrHs2/C5ivaBV1rXKIBs9hKKFg=,tag:RQPQQ1cmZiOpQjUwqnzZQA==,type:str] + lastmodified: "2024-12-06T04:35:52Z" + mac: ENC[AES256_GCM,data:DAg4UTwNv+rs6hye2z5UUtA1a4yZbFaAWjLoKAXf87tKgBCZzK8C1q6gLyTQOqp07ptYQd5Q951kfE1a/35SFJsubREzJmu6haxznRgq7pO5HDGqgtjYEHsngsWZh3bUSX/aG2dLISdD81VY68nLzTO0r4h/SL6DNG36RzJgL8E=,iv:V0WhENNt/Szi5VWVD2t5AsWP1tOZUGjFjMNYPDq59XI=,tag:ThRstdzVNtSs6E7qlvKPOw==,type:str] pgp: [] unencrypted_suffix: _unencrypted version: 3.9.1 diff --git a/machines/massicot/default.nix b/machines/massicot/default.nix index da2cbd5..7b56e15 100644 --- a/machines/massicot/default.nix +++ b/machines/massicot/default.nix @@ -15,24 +15,9 @@ defaultSopsFile = ./secrets.yaml; age.sshKeyPaths = [ "/etc/ssh/ssh_host_ed25519_key" ]; secrets = { - storage_box_mount = { - owner = "root"; - }; gts_env = { owner = "gotosocial"; }; - hedgedoc_env = { - owner = "hedgedoc"; - }; - grafana_oauth_secret = { - owner = "grafana"; - }; - "miniflux/oauth2_secret" = { - owner = "root"; - }; - "forgejo/env" = { - owner = "forgejo"; - }; }; }; diff --git a/machines/massicot/kanidm-provision.nix b/machines/massicot/kanidm-provision.nix index 8a95a99..e44c729 100644 --- a/machines/massicot/kanidm-provision.nix +++ b/machines/massicot/kanidm-provision.nix @@ -1,4 +1,14 @@ -{ config, lib, ... }: +{ pkgs, config, ... }: +let + inherit (config.my-lib.settings) + gotosocialUrl + minifluxUrl + hedgedocDomain + forgejoDomain + grafanaUrl + synapseDelegateUrl + ; +in { services.kanidm.provision = { enable = true; @@ -45,6 +55,9 @@ miniflux-users = { members = [ "xin" ]; }; + synapse-users = { + members = [ "xin" ]; + }; idm_people_self_mail_write = { members = [ ]; }; @@ -73,8 +86,8 @@ systems.oauth2 = { forgejo = { displayName = "ForgeJo"; - originUrl = "https://git.xinyang.life/user/oauth2/kanidm/callback"; - originLanding = "https://git.xinyang.life/user/oauth2/kanidm"; + originUrl = "https://${forgejoDomain}/user/oauth2/kanidm/callback"; + originLanding = "https://${forgejoDomain}/user/oauth2/kanidm"; allowInsecureClientDisablePkce = true; scopeMaps = { forgejo-access = [ @@ -110,8 +123,8 @@ }; gotosocial = { displayName = "GoToSocial"; - originUrl = "https://gts.xiny.li/auth/callback"; - originLanding = "https://gts.xiny.li/auth/callback"; + originUrl = "${gotosocialUrl}/auth/callback"; + originLanding = "${gotosocialUrl}/auth/callback"; allowInsecureClientDisablePkce = true; scopeMaps = { gts-users = [ @@ -147,8 +160,8 @@ hedgedoc = { displayName = "HedgeDoc"; - originUrl = "https://docs.xinyang.life/auth/oauth2/callback"; - originLanding = "https://docs.xinyang.life/auth/oauth2"; + originUrl = "https://${hedgedocDomain}/auth/oauth2/callback"; + originLanding = "https://${hedgedocDomain}/auth/oauth2"; allowInsecureClientDisablePkce = true; scopeMaps = { hedgedoc-users = [ @@ -177,9 +190,8 @@ }; miniflux = { displayName = "Miniflux"; - originUrl = "https://rss.xinyang.life/oauth2/oidc/callback"; - - originLanding = "https://rss.xinyang.life/oauth2/oidc/redirect"; + originUrl = "${minifluxUrl}/oauth2/oidc/callback"; + originLanding = "${minifluxUrl}/oauth2/oidc/redirect"; scopeMaps = { miniflux-users = [ "openid" @@ -190,8 +202,8 @@ }; grafana = { displayName = "Grafana"; - originUrl = "https://grafana.xinyang.life/login/generic_oauth"; - originLanding = "https://grafana.xinyang.life/"; + originUrl = "${grafanaUrl}/login/generic_oauth"; + originLanding = "${grafanaUrl}/"; scopeMaps = { grafana-users = [ "openid" @@ -211,6 +223,17 @@ }; }; }; + synapse = { + displayName = "Synapse"; + originUrl = "${synapseDelegateUrl}/_synapse/client/oidc/callback"; + originLanding = "${synapseDelegateUrl}/"; + scopeMaps = { + synapse-users = [ + "openid" + "profile" + ]; + }; + }; }; }; } diff --git a/machines/massicot/services.nix b/machines/massicot/services.nix index 14dc9d9..a4f0d72 100644 --- a/machines/massicot/services.nix +++ b/machines/massicot/services.nix @@ -23,26 +23,6 @@ in 8448 ]; - custom.vaultwarden = { - enable = true; - domain = "vaultwarden.xinyang.life"; - }; - - custom.hedgedoc = { - enable = true; - caddy = true; - domain = "docs.xinyang.life"; - mediaPath = "/mnt/storage/hedgedoc"; - oidc = { - enable = true; - baseURL = "https://auth.xinyang.life/oauth2/openid/hedgedoc"; - authorizationURL = "https://auth.xinyang.life/ui/oauth2"; - tokenURL = "https://auth.xinyang.life/oauth2/token"; - userProfileURL = "https://auth.xinyang.life/oauth2/openid/hedgedoc/userinfo"; - }; - environmentFile = config.sops.secrets.hedgedoc_env.path; - }; - custom.monitoring = { promtail.enable = true; }; @@ -66,18 +46,6 @@ in }; }; - services.ntfy-sh = { - enable = true; - group = "caddy"; - settings = { - listen-unix = "/var/run/ntfy-sh/ntfy.sock"; - listen-unix-mode = 432; # octal 0660 - base-url = "https://ntfy.xinyang.life"; - }; - }; - - systemd.services.ntfy-sh.serviceConfig.RuntimeDirectory = "ntfy-sh"; - services.kanidm = { package = pkgs.kanidm.withSecretProvisioning; enableServer = true; @@ -92,40 +60,6 @@ in }; }; - custom.miniflux = { - enable = true; - environment = { - LOG_LEVEL = "debug"; - LISTEN_ADDR = "127.0.0.1:58173"; - BASE_URL = "https://rss.xinyang.life/"; - OAUTH2_PROVIDER = "oidc"; - OAUTH2_CLIENT_ID = "miniflux"; - OAUTH2_REDIRECT_URL = "https://rss.xinyang.life/oauth2/oidc/callback"; - OAUTH2_OIDC_DISCOVERY_ENDPOINT = "https://auth.xinyang.life/oauth2/openid/miniflux"; - OAUTH2_USER_CREATION = 1; - }; - oauth2SecretFile = config.sops.secrets."miniflux/oauth2_secret".path; - }; - - services.matrix-conduit = { - enable = true; - package = pkgs.matrix-conduit; - settings.global = { - server_name = "xinyang.life"; - port = 6167; - # database_path = "/var/lib/matrix-conduit/"; - max_concurrent_requests = 100; - log = "info"; - database_backend = "rocksdb"; - allow_registration = false; - - well_known = { - client = "https://msg.xinyang.life"; - server = "msg.xinyang.life:443"; - }; - }; - }; - users.users.conduit = { isSystemUser = true; group = "conduit"; @@ -150,128 +84,8 @@ in environmentFile = config.sops.secrets.gts_env.path; }; - services.forgejo = { - enable = true; - # Use cutting edge instead of lts - package = pkgs.forgejo; - repositoryRoot = "/mnt/storage/forgejo/repositories"; - lfs = { - enable = true; - contentDir = "/mnt/storage/forgejo/lfs"; - }; - settings = { - service.DISABLE_REGISTRATION = true; - server = { - ROOT_URL = "https://git.xinyang.life/"; - START_SSH_SERVER = false; - SSH_USER = config.services.forgejo.user; - SSH_DOMAIN = "ssh.xinyang.life"; - SSH_PORT = 22; - LFS_MAX_FILE_SIZE = 10737418240; - LANDING_PAGE = "/explore/repos"; - }; - repository = { - ENABLE_PUSH_CREATE_USER = true; - }; - service = { - ENABLE_BASIC_AUTHENTICATION = false; - }; - oauth2 = { - ENABLED = false; # Disable forgejo as oauth2 provider - }; - oauth2_client = { - ACCOUNT_LINKING = "auto"; - USERNAME = "email"; - ENABLE_AUTO_REGISTRATION = true; - UPDATE_AVATAR = false; - OPENID_CONNECT_SCOPES = "openid profile email groups"; - }; - other = { - SHOW_FOOTER_VERSION = false; - }; - }; - }; - - systemd.services.forgejo = { - serviceConfig = { - EnvironmentFile = config.sops.secrets."forgejo/env".path; - ExecStartPost = '' - ${lib.getExe config.services.forgejo.package} admin auth update-oauth \ - --id 1 \ - --name kanidm \ - --provider openidConnect \ - --key forgejo \ - --secret $CLIENT_SECRET \ - --icon-url https://auth.xinyang.life/pkg/img/favicon.png \ - --group-claim-name forgejo_role --admin-group Admin - ''; - }; - }; - - services.grafana = { - enable = true; - settings = { - server = { - http_addr = "127.0.0.1"; - http_port = 3003; - root_url = "https://grafana.xinyang.life"; - domain = "grafana.xinyang.life"; - }; - "auth.generic_oauth" = { - enabled = true; - name = "Kanidm"; - client_id = "grafana"; - scopes = "openid,profile,email,groups"; - auth_url = "https://auth.xinyang.life/ui/oauth2"; - token_url = "https://auth.xinyang.life/oauth2/token"; - api_url = "https://auth.xinyang.life/oauth2/openid/grafana/userinfo"; - use_pkce = true; - use_refresh_token = true; - allow_sign_up = true; - login_attribute_path = "preferred_username"; - groups_attribute_path = "groups"; - role_attribute_path = "contains(grafana_role[*], 'GrafanaAdmin') && 'GrafanaAdmin' || contains(grafana_role[*], 'Admin') && 'Admin' || contains(grafana_role[*], 'Editor') && 'Editor' || 'Viewer'"; - allow_assign_grafana_admin = true; - auto_login = true; - }; - "auth" = { - disable_login_form = true; - }; - }; - }; - - systemd.services.grafana.serviceConfig.EnvironmentFile = - config.sops.secrets.grafana_oauth_secret.path; - - users.users.git = { - isSystemUser = true; - useDefaultShell = true; - group = "git"; - extraGroups = [ "forgejo" ]; - }; - users.groups.git = { }; - - users.users = { - ${config.services.caddy.user}.extraGroups = [ config.services.ntfy-sh.group ]; - }; - services.caddy = { enable = true; - virtualHosts."xinyang.life:443".extraConfig = '' - tls internal - encode zstd gzip - reverse_proxy /.well-known/matrix/* localhost:6167 - reverse_proxy * http://localhost:8080 { - flush_interval -1 - } - ''; - virtualHosts."https://msg.xinyang.life:443".extraConfig = '' - reverse_proxy /_matrix/* localhost:6167 - ''; - virtualHosts."https://git.xinyang.life:443".extraConfig = '' - reverse_proxy http://${config.services.gitea.settings.server.DOMAIN}:${toString config.services.gitea.settings.server.HTTP_PORT} - ''; - virtualHosts."http://auth.xinyang.life:80".extraConfig = '' reverse_proxy ${config.security.acme.certs."auth.xinyang.life".listenHTTP} ''; @@ -284,27 +98,5 @@ in } } ''; - - virtualHosts."https://rss.xinyang.life".extraConfig = '' - reverse_proxy ${config.custom.miniflux.environment.LISTEN_ADDR} - ''; - - virtualHosts."https://ntfy.xinyang.life".extraConfig = '' - reverse_proxy unix/${config.services.ntfy-sh.settings.listen-unix} - @httpget { - protocol http - method GET - path_regexp ^/([-_a-z0-9]{0,64}$|docs/|static/) - } - redir @httpget https://{host}{uri} - ''; - - virtualHosts."https://grafana.xinyang.life".extraConfig = - let - grafanaSettings = config.services.grafana.settings.server; - in - '' - reverse_proxy http://${grafanaSettings.http_addr}:${toString grafanaSettings.http_port} - ''; }; } diff --git a/machines/massicot/services/restic.nix b/machines/massicot/services/restic.nix index c205989..e8d2501 100644 --- a/machines/massicot/services/restic.nix +++ b/machines/massicot/services/restic.nix @@ -34,13 +34,6 @@ in ]; }; - services.postgresqlBackup = { - enable = true; - compression = "zstd"; - compressionLevel = 9; - location = "/backup/postgresql"; - }; - services.restic.backups.${config.networking.hostName} = { extraBackupArgs = [ "--limit-upload=1024" diff --git a/machines/secrets.yaml b/machines/secrets.yaml index 69456c4..6d94d7e 100644 --- a/machines/secrets.yaml +++ b/machines/secrets.yaml @@ -10,74 +10,83 @@ sops: - recipient: age1uw059wcwfvd9xuj0hpqzqpeg7qemecspjrsatg37wc7rs2pumfdsgken0c enc: | -----BEGIN AGE ENCRYPTED FILE----- - YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSAwMHB1bFQ3dWJIU3NiOVVP - Yi9LZE1PTVdMY1BqS1JHV3VPLzZIY0hGK0NZClNlclVXKzBvNTBrTlhiR0VsaVoz - RlVLNVBEVDgzSXB5ZGxDd3hqNDh2V2MKLS0tIEhBZHFUY3c2VXJBVEVKamZ6TzBa - MlFsNnVEV0xCdlJoRnBhUHF2MmswUEUKNYD9zssGBy9SaKeOMvTz71B6KMPW87cM - tFJzgnQceEQF658lVa5cCzG1gzraCgBtQU15XzC7e8zWI9CHquRRlQ== + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSA5SjAzOEozUzh1bzVvaHgr + T2xsVUszTHVSdWIyM3B5TFhtUEFMeVZlYzNrCk5IOWFNbTErbTVkQnNlVllMZWlV + Q2lHZXRIdzBiRFRSZnNUVWd2NXVXVGcKLS0tIERhcjh3VVlqSGxHUHpnc1JzVksv + VXpQVVVCUC9xR3crWm9rTk13LzVhK1EKwiuvwx3ZhcDE+9w7/dR4PrZSSoJMvklT + m7I32dMRk0o9zcl5KYU5L9Hwb+z+EBE34raoGKBF5K4aQcbZQUX3Cw== -----END AGE ENCRYPTED FILE----- - recipient: age1ytwfqfeez3dqtazyjltn7mznccwx3ua8djhned7n8mxqhw4p6e5s97skfa enc: | -----BEGIN AGE ENCRYPTED FILE----- - YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBTTnZLTlZQRzc1enVEa1BN - SHdoSi9oOXk4UTV0SlRZS2tLS2FFL3VjNzNNClVWTTNKekF6T0RTUzdEeWhLbHoz - WFZKaHJEaVBWa04zRWRiVnJZRjU0YVEKLS0tIFJVL0FEemowS3V6MmsxbWJMU2I1 - U2NnUnVKdFlRSGVzUFQ4ZFcwL0lWTlkKz1t3yqjgIdMWS/Nsy2nq3oCjOhGDP+UT - L+LAuFExJPV0qlsOG/kCGB/WtCJfnBvcp6vPDBLqjK8NllIX/iPI5g== + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSA5R1ZIRlN2b3M2OUQ0T2cw + eE5DTm9KY1NUY1p5eDhLNG4xMDVkVjRyWDNRClp3MTRWeGJMYTczcC9YQTNZdkxx + ejJ3QnhjcUcyUldUNEVqVUh6Z2grd00KLS0tIDVvbDZWbmZPZVhDNHM1K1kzaE95 + aHJqSU16dlJiRGl0VWNMVXVYMmhPb2MKMboq9ShGIJMFVENgLPlQdwdtTOjVb0CC + 4ttM3xWnYkf8416a0OYFrda5l1kfJJzQakbk/tbGcTu1yTcd+6lOtA== + -----END AGE ENCRYPTED FILE----- + - recipient: age17r3fxfmt6hgwe984w4lds9u0cnkf5ttq8hnqt800ayfmx7t8t5gqjddyml + enc: | + -----BEGIN AGE ENCRYPTED FILE----- + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBVby8wYS9pa0szTlVUS3FI + VWhjaCtyUzNLbkw2VXRlWkVMZlRkeXJMZGlRCnBTWklnZ0Uzd2lTMGt1M2wxZ0px + NFl2RW5hSUZVdHI0aVFRMHJtMFQ3ODAKLS0tIFlYOHVRYVFGbkcvUWRmQitQQnI5 + bG5vemMvcWdpOEtxNGRpS0doQmtuUFkK8Hxl//kOtbEw3jf96ZZ4G1Yb94f4Jeb4 + TfPs7O/ESJY8ovNsoXRQEt99vOR5D1wBzyZBY9E3f2ZzY/uBmup0cw== -----END AGE ENCRYPTED FILE----- - recipient: age1jle2auermhswqtehww9gqada8car5aczrx43ztzqf9wtcld0sfmqzaecta enc: | -----BEGIN AGE ENCRYPTED FILE----- - YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBETWpkcjhINktqeGxjdWxz - UTVVNC9kalorcVJOdHpJSkZJNXlGUHZ2VUdrCjRCclBTZnJEZ3JGOVpqS1Y0b0dt - eldFMS91WUc2Y1FnWWZoN0grc01pT0UKLS0tIC96TjlEaVBGRkZhZ0hac2lmbEdI - eHMzTFhsQ0FqY05uUEZSbExCcmdscEkKdxITlc0V5ayq+9fmj77SnEMFxKJhOOta - RfJhOQUv8g3nCN+SsuaOy0TitUCiDWh5XoB0DufEQPcS/kzGZN1Inw== + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBPSmRYMkNIdERJZVBxV1p1 + emlqOTBpN3l2WXkzNjRRcFI5NUZDZnQ1WXdnCkRVbm8xais5aGVCTmtSTGxaTXlT + L2ZWQ0p5WFZNRWl5SWVkRUYwc2R3b1UKLS0tIEZEck4yMmJUQWVvNHRJQnpCQTBo + cDJsaG83MTdXWVd2NUpLczhjWTBBZVUK5BxBIYVqkqVLw9LTbnJ8SQWN2i4USdI8 + 8m/hZFXTJ4GI0f795DEmbcZq9xET14aQqta0wSASqwP/5Ld1mo0a0w== -----END AGE ENCRYPTED FILE----- - recipient: age12ng08vjx5jde5ncqutwkd5vm4ygfwy33mzhzwe0lkxzglulgpqusc89r96 enc: | -----BEGIN AGE ENCRYPTED FILE----- - YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBydlQ4S1duQU53Wk1nd21K - d2RqM1F0VDFJVXB2aGRTZ2hxczI2V1lndVdrCjArVlE2N0RGZ0htUEZYdVlQMlU5 - SWIwWHVCaWxaQTJMNzg3WC8xRS9IYzgKLS0tIDRvSS8ybVlrSy9zYjQ2NXBaMlZk - Ulg4cUFBejRoS3VEWkRaZEUxMExUeWMKNeq6TN1gaBNU9vAitGttcU+8HmFQipdm - LPwo4/toyf27emb4KGs0AV0Dm4Sxj9S3Xvrv1B+qvhfT638/RIUm2w== + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSAwSkhjRTdBWklZUEpUanM0 + Wjl4b2c3K0g0ZUxxMlRrUFhhZzhNRXhPVnpvCmpNWVBNTXNYczV3aWhCd05FOGJ0 + YlNobFhWdStGbDRZV2NlUWV6ZFRVNEkKLS0tIGd1RUR4K21GOEQ0aWtqRi9RREpE + RXBXcXFYUDVXVzN4Q25zSklFU21wbFkKQuTHkgFC5HRPO7/PuVhJzbbHOTPaFXvN + +Y31AK3OAVdUETMEuJ2mk50Bi5BiiUeOnnv1bZ6O+iX0o20ysUseTg== -----END AGE ENCRYPTED FILE----- - recipient: age1v5h946jfke6ae8pcgz52mhj26cacqcpl9dmmrrkf37x55rnq2v3szqctvv enc: | -----BEGIN AGE ENCRYPTED FILE----- - YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSB4YXpyOXE3MFovWEQvMVRr - TGVST3U0N2dCVDJGT1A3eUtlRis3bFEvTHlFClZHQ2xRWklMMCtER01QNEVHaVYr - MC94V3R4MVdNdUU3eXQ2RGFFVGo4VFEKLS0tIDQ4b2ZuMy9URUswWUZqNHlxandU - OFducVVzdGZGY0tnbFFBZDdjVzVkaUEKN8qAbbrd4pAHRGIN8O64fl7bQ6hx6Isr - Qx0xKeuhJCVXgtE8xc7xmnEhqrcONlflJ/XUnYV9jOkB71zSBJxruA== + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBnc3NOZFRYT1VnaVZSaTRi + WnluSEk4d1U5TWx2REZRZ3VCRVp2ZzlKY0NvCjNlUnIwdWVqSnlQOWp1dlJ5THlW + c2xTNHhnaE94a2ZTeXJjQTVxeGRLTmsKLS0tIFV4c2NZK1ZnL2xtUlVvSksxNi9o + L3dodkJXVjZrekVldTVsRFRxSFlrTmMKiokjgIRIsI8D2aFP/Qem4iGzC4yr5lm2 + ZwggC/UfD56ysTEqrVaDnR7f5fSqZLWdstPJn7I/vr5CwKRMbMPYSA== -----END AGE ENCRYPTED FILE----- - recipient: age1p2dlc8gfgyrvtta6mty2pezjycn244gmvh456qd3wvkfwesp253qnwyta9 enc: | -----BEGIN AGE ENCRYPTED FILE----- - YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSAzczdPMDdWU1ZtckJRQm5j - UWJub0Yzd3NzOEh4YWdId01nYWI1YVY3dng0ClpEYXBJV2cvWEdjdXcwUFI3Y0NG - MDgvTmNZOXRQQndyVmRHamNRbzVaVU0KLS0tIGFKVTI4TkE2UjhDUSsxQTlNQ0Vk - QmFMNnlqbnhScC90T012K1QxRnRUOHcKAV7NxUn0CMcjKwK8zrocoLO1P9jc22uG - eG+vdJ6xzA99UX51aPxQOeEJgdFPEd3y1QJszQmRzThvid7y4lv0Cw== + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBpN0llOTBJU1pNNVFxVWxt + aFdKdStKL1ZlZ0p6WFRQbHpGNnpmdlJXdG1FCkx5eDhZWWJvQ2xSWEJqWnZ6NmNt + Y0MzNDg5QzVSbEZteW1LNlFyRFg5Q0EKLS0tIDBrT0dEZlBoTExYcGRNZjZ5Znpz + cnE4YWRTMmRsTENhOTl5R2dYSzQwazAKvnTvZz842Mg5AVlIoYHI2BG+0/hO5zIv + jRVJri98fgGterXADTPmeoY3p+fFQggTPhs/5s5GSQxd5aiX8vvvrA== -----END AGE ENCRYPTED FILE----- - recipient: age18u4mqrhqkrpcytxfxfex6aeap04u38emhy6u4wrp5k62sz2vae4qm5jj7s enc: | -----BEGIN AGE ENCRYPTED FILE----- - YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBsVmpzenRvWE5EK2wzRFkx - SERZV0s1Rkt0ZnZ1U3JQSFNhdGVvaWhWcTA4CjVxK0Z0MHI0ZnMrUS9YYWhTTG1z - L2lVS1Q2UkVQd2x5b1E1eWpQVGp2ZHMKLS0tIHNLOGhTYjkzWkFEM05wYkRZeXFQ - SXNTSGZZSFE2bFhybXdIc1FUb1ZBd0kKkYzflPRk6GrE6t9oVGOzc8xcyZDxiIw8 - 9SVXIgV0WVpY4lnFKYKH2i4+1sIm6tKOpizlQxTg5VgmmrTtfazWAA== + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBPQWljdGg4VTlDdGhoblpk + LytxK2FnQVI1dzB2bnFaWUtoUVNGS3lpU3prCnRwUTNnZVVXTnZ6eCtScTk5YzI3 + TGM2MmNhaHQ3NXAzMk0rcnJoTlp5STQKLS0tIEp2U3YvUUhXTkt3VFczY3J1LzMv + ZzM0VHpqamRIZVROS2lQdXFhQTNBekEKEySldC+VvZvPY398ZVkB5s73bT3QbuLh + IqTv+wbkbjlvZJUavVyycY5SwMXkSX3ge9W/64mt/RDs88gSXFS+Sw== -----END AGE ENCRYPTED FILE----- - recipient: age1fw2sqaa5s9c8ml6ncsexkj8ar4288387ju92ytjys4awf9aw6smqqz94dh enc: | -----BEGIN AGE ENCRYPTED FILE----- - YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSB0NHpkOTFHaXRhVGNua0dV - alRieWJ6WG5ZNzlvcTR2aTVUeWFBVGVVUUNZCnY2VUZUOWVlNGY1ZldyVGE2bkpi - VXVtQ3IyK0kyV1cyMU5nN1lYaW1oOUkKLS0tIFRVRGFCNWlGendSVEhHY0w0QTl6 - emJEQkQ3QlU0TFVWaW1uQytaUndmQlEKKahqJpX8vI+PASOzzod/sFvXSkQFnJ9O - YmnmiFxm5WZDPLHwkgVx8FgCq9RfAad4HybhsMjYPKXJ/fNa/WVZRA== + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSA4bGppem15NlVod2hCRkM5 + MzY1aUZOdEVzRzdEYTRNakdMQWJlRkk0eEZzClRLSnRrQUoreU5MVG40KzRKSGcw + bUU4ZnpLU0VtOWxXVllrSW5lN0NWb0kKLS0tIE1iemRlVVpieEhxRnlIb2dFUHZr + am04NVRtU2N6SThYZWdXVE5RZ1B2aE0KVcHvB5k2Gcu/St0P8WPFzlCtuZthZTKo + hwVc0lC6Xxt25hriaUFinwnyvcjxrLCx0Nq7f9Zn16nJcza5kev1nQ== -----END AGE ENCRYPTED FILE----- lastmodified: "2024-11-30T06:31:42Z" mac: ENC[AES256_GCM,data:xh8x9IrQ01ZzdcCTIfBrifIGduMYVmSSP52BkTyr/bx7AgQAz2WeA7LFrccxIayCGHrQKfMQDLUKJ/EBamG/6p8AX6QqZBTfqFD688ZhmRfxgpj7fYR9jPYnhb/9XHI9R2jTaJWwrorXvu3pa+Gy/hWB3Kb+WZc3fslmIuKuLH0=,iv:GDrHSFZxPbpACdusVDPHXEjeEusYfk53N/KGHtdvrYo=,tag:ap38sCSTZVDQ0ZazXM3vlg==,type:str] diff --git a/machines/thorite/default.nix b/machines/thorite/default.nix index b85bab8..f2de662 100644 --- a/machines/thorite/default.nix +++ b/machines/thorite/default.nix @@ -1,7 +1,10 @@ +{ config, ... }: { imports = [ ./hardware-configurations.nix ./monitoring.nix + ./restic.nix + ./ntfy.nix ]; config = { @@ -28,6 +31,10 @@ 443 ]; + services.tailscale.enable = true; + + services.caddy.enable = true; + commonSettings = { auth.enable = true; }; diff --git a/machines/thorite/monitoring.nix b/machines/thorite/monitoring.nix index bc10492..981fd14 100644 --- a/machines/thorite/monitoring.nix +++ b/machines/thorite/monitoring.nix @@ -1,5 +1,20 @@ -{ config, my-lib, ... }: -with my-lib; +{ + config, + lib, + pkgs, + ... +}: +with config.my-lib; +let + inherit (config.my-lib.settings) + minifluxUrl + gotosocialUrl + hedgedocDomain + grafanaUrl + ntfyUrl + ; + removeHttps = s: lib.removePrefix "https://" s; +in { config = { sops = { @@ -14,11 +29,23 @@ with my-lib; custom.monitoring = { grafana.enable = true; - loki.enable = true; + loki = { + enable = true; + rules = { + sshd_closed = { + expr = ''count_over_time({unit="sshd.service"} |~ "Connection closed by authenticating user" [15m]) > 25''; + description = "More then 25 login attemps in last 15 min without success"; + }; + unusual_log_volume = { + expr = ''sum by (unit) (rate({unit=~".+"}[5m])) > 80''; + description = "Unit {{ $labels.unit }} is logging at an unusually high rate"; + }; + }; + }; promtail.enable = true; }; - services.caddy.virtualHosts."https://grafana.xinyang.life".extraConfig = + services.caddy.virtualHosts.${grafanaUrl}.extraConfig = with config.services.grafana.settings.server; '' reverse_proxy http://${http_addr}:${toString http_port} ''; @@ -30,19 +57,28 @@ with my-lib; blackbox.enable = true; node.enable = true; }; - ruleModules = (mkCaddyRules [ { host = "thorite"; } ]) ++ (mkNodeRules [ { host = "thorite"; } ]); + ruleModules = + (mkCaddyRules [ { host = "thorite"; } ]) + ++ (mkNodeRules [ { host = "thorite"; } ]) + ++ (mkBlackboxRules [ { host = "thorite"; } ]); }; services.prometheus.scrapeConfigs = let probeList = [ "la-00.video.namely.icu:8080" - "fre-00.video.namely.icu:8080" + "fra-00.video.namely.icu:8080" "hk-00.video.namely.icu:8080" - "49.13.13.122:443" - "45.142.178.32:22" "home.xinyang.life:8000" ]; + chinaTargets = [ + "bj-cu-v4.ip.zstaticcdn.com:80" + "bj-cm-v4.ip.zstaticcdn.com:80" + "bj-ct-v4.ip.zstaticcdn.com:80" + "sh-cu-v4.ip.zstaticcdn.com:80" + "sh-cm-v4.ip.zstaticcdn.com:80" + "sh-ct-v4.ip.zstaticcdn.com:80" + ]; passwordFile = config.sops.secrets."prometheus/metrics_password".path; in (mkScrapes [ @@ -52,32 +88,50 @@ with my-lib; address = "weilite.coho-tet.ts.net"; port = 8082; } + { + name = "restic_rest_server"; + address = "backup.xinyang.life"; + port = 8443; + } { inherit passwordFile; name = "gotosocial"; - address = "xinyang.life"; + address = removeHttps gotosocialUrl; } { inherit passwordFile; name = "miniflux"; - address = "rss.xinyang.life"; + address = removeHttps minifluxUrl; + } + { + name = "hedgedoc"; + address = hedgedocDomain; } { name = "ntfy"; - address = "ntfy.xinyang.life"; + address = removeHttps ntfyUrl; } { name = "grafana-eu"; - address = "grafana.xinyang.life"; + address = removeHttps grafanaUrl; + } + { + name = "loki"; + scheme = "http"; + address = "thorite.coho-tet.ts.net"; + port = 3100; } ]) ++ (mkCaddyScrapes [ { address = "thorite.coho-tet.ts.net"; } + { address = "biotite.coho-tet.ts.net"; } + { address = "weilite.coho-tet.ts.net"; } ]) ++ (mkNodeScrapes [ { address = "thorite.coho-tet.ts.net"; } { address = "massicot.coho-tet.ts.net"; } { address = "weilite.coho-tet.ts.net"; } + { address = "biotite.coho-tet.ts.net"; } { address = "hk-00.coho-tet.ts.net"; } { address = "la-00.coho-tet.ts.net"; } { address = "fra-00.coho-tet.ts.net"; } @@ -85,20 +139,37 @@ with my-lib; ++ (mkBlackboxScrapes [ { hostAddress = "thorite.coho-tet.ts.net"; - targetAddresses = probeList; + targetAddresses = probeList ++ [ "49.13.13.122:443" ]; } { hostAddress = "massicot.coho-tet.ts.net"; - targetAddresses = probeList; + targetAddresses = probeList ++ [ "45.142.178.32:443" ]; } { hostAddress = "weilite.coho-tet.ts.net"; targetAddresses = [ "la-00.video.namely.icu:8080" - "fre-00.video.namely.icu:8080" + "fra-00.video.namely.icu:8080" "hk-00.video.namely.icu:8080" ]; } + { + hostAddress = "la-00.coho-tet.ts.net"; + targetAddresses = chinaTargets; + } + { + hostAddress = "hk-00.coho-tet.ts.net"; + targetAddresses = chinaTargets; + } + { + hostAddress = "fra-00.coho-tet.ts.net"; + targetAddresses = chinaTargets; + } + ]) + ++ (mkV2rayScrapes [ + { address = "la-00.coho-tet.ts.net"; } + { address = "hk-00.coho-tet.ts.net"; } + { address = "fra-00.coho-tet.ts.net"; } ]); }; diff --git a/machines/thorite/ntfy.nix b/machines/thorite/ntfy.nix new file mode 100644 index 0000000..8e950f8 --- /dev/null +++ b/machines/thorite/ntfy.nix @@ -0,0 +1,29 @@ +{ config, ... }: +let + inherit (config.my-lib.settings) ntfyUrl; +in +{ + + services.ntfy-sh = { + enable = true; + group = "caddy"; + settings = { + listen-unix = "/var/run/ntfy-sh/ntfy.sock"; + listen-unix-mode = 432; # octal 0660 + base-url = ntfyUrl; + }; + }; + + systemd.services.ntfy-sh.serviceConfig.RuntimeDirectory = "ntfy-sh"; + + services.caddy.virtualHosts.${ntfyUrl}.extraConfig = '' + reverse_proxy unix/${config.services.ntfy-sh.settings.listen-unix} + @httpget { + protocol http + method GET + path_regexp ^/([-_a-z0-9]{0,64}$|docs/|static/) + } + redir @httpget https://{host}{uri} + ''; + +} diff --git a/machines/thorite/restic.nix b/machines/thorite/restic.nix new file mode 100644 index 0000000..d359304 --- /dev/null +++ b/machines/thorite/restic.nix @@ -0,0 +1,51 @@ +{ + config, + lib, + pkgs, + ... +}: +let + sqliteBackup = fromPath: toPath: file: '' + mkdir -p ${toPath} + ${lib.getExe pkgs.sqlite} ${fromPath} ".backup '${toPath}/${file}'" + ''; +in +{ + sops.secrets = { + "restic/repo_url" = { }; + "restic/repo_password" = { }; + }; + + custom.restic = { + enable = true; + paths = [ + "/backup/db" + "/backup/var/lib" + ]; + backupPrepareCommand = [ + '' + mkdir -p /backup/var + ${pkgs.btrfs-progs}/bin/btrfs subvolume snapshot -r /var/lib /backup/var/lib + '' + ]; + backupCleanupCommand = [ + '' + ${pkgs.btrfs-progs}/bin/btrfs subvolume delete /backup/var/lib + '' + ]; + btrfsRoots = [ ]; + }; + + services.postgresqlBackup = lib.mkIf config.services.postgresql.enable { + enable = true; + compression = "zstd"; + compressionLevel = 9; + location = "/backup/db/postgresql"; + }; + + services.restic.backups.${config.networking.hostName} = { + extraBackupArgs = [ + "--limit-upload=1024" + ]; + }; +} diff --git a/machines/thorite/secrets.yaml b/machines/thorite/secrets.yaml index 60d475f..c246e2b 100644 --- a/machines/thorite/secrets.yaml +++ b/machines/thorite/secrets.yaml @@ -1,5 +1,8 @@ grafana: oauth_secret: ENC[AES256_GCM,data:angZR3sl8vGcbAXyKFBvCSm+YhF5OooCcxRiSxR2zBoXMz5wv5/uMJFynwOTRVI6,iv:hVpOlM89lNbK6AsGf4Is/tLv3xPfg/XdtA8vuEK52L8=,tag:zCER+IdRnTcG2WHQ/AhxZA==,type:str] +restic: + repo_url: ENC[AES256_GCM,data:tc7wYRN20sHxATTZYEBpf6tNafzq9vcvqdUHYJDmJIArxprNd6WiyqPXowzbksZcEi5JwSwwJH/MYminnPGtrR8erWZg8OB3,iv:/z7mF58tMAviscFWHd4NJw7UZlq7Bzz+LU88J+kE9qg=,tag:i97FP4SmmNXOuxylkHhYCA==,type:str] + repo_password: ENC[AES256_GCM,data:o3MbXJRwR5UE9uCELN2ejQ==,iv:cYPNjJAV7H2BNCuFLDJoJvPk+CFvagXJwW9LRAGc0G0=,tag:qF6Di2W+8kESCRAphC/c0g==,type:str] sops: kms: [] gcp_kms: [] @@ -24,8 +27,8 @@ sops: M2pqMUJoMGlBZnpBaVBUTFFRZUMzb2sKrlWy26Cv55/8XQEl9hee8P29uj582sIx mUjaYE0U2qOP9bklXUQyyzQjfkBLWTLc1PTX9BjqOOsqXwkRQIYppA== -----END AGE ENCRYPTED FILE----- - lastmodified: "2024-11-28T17:02:03Z" - mac: ENC[AES256_GCM,data:14FOUXuKP+8+sad1UlhBW37fWzmutpyn6d4q2qKtBiOyT5ivHunFHJfHrtX83X2fLDmUfiD42bXf+rYfdtKzVUmQ6vutCUQk+Hal8NElhjcq5Ns5kT4VZRKG7/ya9+eNEEkajtq/7OFEM5KOQKTKjyOBqBq/AdYQ+ni9r45c1sM=,iv:WrdWSfrZrGalZO4WGk3JpgACY7W0odt3vP+pRkMXHfA=,tag:jeRBfR2QYjLBylOLHxU3hQ==,type:str] + lastmodified: "2024-12-03T08:18:54Z" + mac: ENC[AES256_GCM,data:jqSt34avoMfL9g3LmvjrPTzW4xGLgX70CXI8qk4isaLbZ8FkxjVU8QY1ot9GZnFEQWUkReSuGD4gFxi8TjetlNdx0zDPcv6zGJUSfcYpyKDCqGdyL/2x8xnYtI2pWINBZxR/2XxT3cus39FJdXVcz3l7KX4DvYvm8t/D9+r4ef0=,iv:KY/OTbDOOD/bBDTIuIk1ck7wDxLogo2EKeSOfOe4j5o=,tag:B17iF5O32KDZfctubpXCng==,type:str] pgp: [] unencrypted_suffix: _unencrypted version: 3.9.1 diff --git a/machines/weilite/default.nix b/machines/weilite/default.nix index b694f40..9d8cd04 100644 --- a/machines/weilite/default.nix +++ b/machines/weilite/default.nix @@ -52,9 +52,8 @@ owner = "caddy"; mode = "400"; }; - "immich/oauth_client_secret" = { - owner = "immich"; - mode = "400"; + "restic/localpass" = { + owner = "restic"; }; }; }; @@ -69,6 +68,10 @@ }; }; + custom.monitoring = { + promtail.enable = true; + }; + systemd.mounts = [ { what = "immich"; @@ -105,43 +108,6 @@ 2222 ]; - services.immich = { - enable = true; - mediaLocation = "/mnt/XinPhotos/immich"; - host = "127.0.0.1"; - port = 3001; - openFirewall = true; - machine-learning.enable = true; - environment = { - IMMICH_MACHINE_LEARNING_ENABLED = "true"; - }; - database.enable = true; - }; - - custom.immich.jsonSettings = { - oauth = { - enabled = true; - issuerUrl = "https://auth.xinyang.life/oauth2/openid/immich/"; - clientId = "immich"; - clientSecret = { - _secret = config.sops.secrets."immich/oauth_client_secret".path; - }; - scope = "openid email profile"; - signingAlgorithm = "ES256"; - storageLabelClaim = "email"; - buttonText = "Login with Kanidm"; - autoLaunch = true; - mobileOverrideEnabled = true; - mobileRedirectUri = "https://immich.xinyang.life:8000/api/oauth/mobile-redirect/"; - }; - passwordLogin = { - enabled = false; - }; - newVersionCheck = { - enabled = false; - }; - }; - services.dae = { enable = true; configFile = "/var/lib/dae/config.dae"; diff --git a/machines/weilite/secrets.yaml b/machines/weilite/secrets.yaml index 8446f0a..0394a80 100644 --- a/machines/weilite/secrets.yaml +++ b/machines/weilite/secrets.yaml @@ -2,6 +2,8 @@ cloudflare_dns_token: ENC[AES256_GCM,data:m4euSkxxJmiMk9UPyeni/hwpl1W9A4MM0ssg71 dnspod_dns_token: ENC[AES256_GCM,data:uZfr3g103amywxh3NMU+AkwuYb61svzyavvQ4rxJijIMIbfPvERrVNcyivoOrFWYXHpPWkhZFdU=,iv:mArVAcebW9i+u26GmQmfmJTsFkR4ZRMIisTqjpMYan8=,tag:Zsmv1Wzfi3+PHigjReToHQ==,type:str] immich: oauth_client_secret: ENC[AES256_GCM,data:EFs2hPjGMj0idwY3oQVIDTOIWkdwoAoAVjDQE9Z2eAKzUDH3grmYpYE+33V8d/Ux,iv:A9cjwFr/ZqltG62/N8MQ1LhdDbSIVVAqIPVB492zYJw=,tag:VTTtE697BZTVsI32UF53/w==,type:str] +restic: + localpass: ENC[AES256_GCM,data:GIQAmkpDmGu4+sSG5/b5yQ==,iv:dcu6F8NnVjeQzEG2vM3fOV5owI0PWc86ts20UP3vN18=,tag:vsG8x062FG1pH5YNcAajeg==,type:str] sops: kms: [] gcp_kms: [] @@ -26,8 +28,8 @@ sops: V0thRjU4WGpQRGFpcnoxSjZTZHhTTkUKzNMHh9p7GUY3hL5XZ9S4x20CwaItsXFV RKujsFVVBd8Kuq/jyOCBTRCscuHI4LW/wYeZYHFEZFSTK2liAqspgw== -----END AGE ENCRYPTED FILE----- - lastmodified: "2024-09-13T12:02:54Z" - mac: ENC[AES256_GCM,data:c5p+B2mPCDyS/Q4QH4MkzCww6jFDhP8RfHqrKLf4e/8XuNEGfNmPKaeliZG26j1YQWRvFHiGQX3AMnQ3Q+fSRUQCVi5KV+KW7fADNIB3TiTT5hAFuynhiWWQSmIrWP0GGek3GDGi7OJ1PrFbxWP9bwaf+zBegiaUcWoTorJg7No=,iv:6MohNgPpq80eTUlf3RvPKsxdx69V0jl+/hrMxAPpPQE=,tag:BtWp1FChP2hdclbGl5W+vQ==,type:str] + lastmodified: "2024-12-03T05:59:51Z" + mac: ENC[AES256_GCM,data:0dLbfkm7fJvH5Mmct0/qHulg2AtDCeeeOgWMXfeGRUaX3GlLDiLga0zW4uNPDuahVecdh6ofvYfBOxFaGUdBCHk9vq5GzrwrzBNhqObWQ3AqVuq5rjqSxEKoFM4Eb5qoqaOefFzT/9qC94NDETTsHhjiEeIgd4fgSr2dazNiFPE=,iv:Ggw0FHzkrhKh5Uzo3seHGwwHsWW/tTAgAl0iIq9PVk4=,tag:rJvUI5/wsLJ01XyKmkRghw==,type:str] pgp: [] unencrypted_suffix: _unencrypted - version: 3.9.0 + version: 3.9.1 diff --git a/machines/weilite/services/default.nix b/machines/weilite/services/default.nix index d70e175..0a6e4ca 100644 --- a/machines/weilite/services/default.nix +++ b/machines/weilite/services/default.nix @@ -3,5 +3,6 @@ ./ocis.nix ./restic.nix ./media-download.nix + ./immich.nix ]; } diff --git a/machines/weilite/services/immich.nix b/machines/weilite/services/immich.nix new file mode 100644 index 0000000..33a98d3 --- /dev/null +++ b/machines/weilite/services/immich.nix @@ -0,0 +1,63 @@ +{ + config, + ... +}: +let + user = config.systemd.services.immich-server.serviceConfig.User; + jsonSettings = { + oauth = { + enabled = true; + issuerUrl = "https://auth.xinyang.life/oauth2/openid/immich/"; + clientId = "immich"; + clientSecret = config.sops.placeholder."immich/oauth_client_secret"; + scope = "openid email profile"; + signingAlgorithm = "ES256"; + storageLabelClaim = "email"; + buttonText = "Login with Kanidm"; + autoLaunch = true; + mobileOverrideEnabled = true; + mobileRedirectUri = "https://immich.xinyang.life:8000/api/oauth/mobile-redirect/"; + }; + passwordLogin = { + enabled = false; + }; + image = { + extractEmbedded = true; + }; + newVersionCheck = { + enabled = false; + }; + }; +in +{ + config = { + sops.secrets."immich/oauth_client_secret" = { }; + + sops.templates."immich/config.json" = { + owner = user; # Read when running + content = builtins.toJSON jsonSettings; + }; + + systemd.services.immich-server = { + serviceConfig = { + Environment = "IMMICH_CONFIG_FILE=${config.sops.templates."immich/config.json".path}"; + }; + }; + + services.immich = { + enable = true; + mediaLocation = "/mnt/XinPhotos/immich"; + host = "127.0.0.1"; + port = 3001; + openFirewall = true; + machine-learning.enable = true; + environment = { + IMMICH_MACHINE_LEARNING_ENABLED = "true"; + }; + database.enable = true; + }; + + # https://github.com/NixOS/nixpkgs/pull/324127/files#r1723763510 + services.immich.redis.host = "/run/redis-immich/redis.sock"; + }; +} diff --git a/machines/weilite/services/media-download.nix b/machines/weilite/services/media-download.nix index 0e1ab58..6f22744 100644 --- a/machines/weilite/services/media-download.nix +++ b/machines/weilite/services/media-download.nix @@ -13,6 +13,13 @@ openFirewall = false; }; + nixpkgs.config.permittedInsecurePackages = [ + "aspnetcore-runtime-6.0.36" + "aspnetcore-runtime-wrapped-6.0.36" + "dotnet-sdk-6.0.428" + "dotnet-sdk-wrapped-6.0.428" + ]; + services.sonarr = { enable = true; }; diff --git a/machines/weilite/services/restic.nix b/machines/weilite/services/restic.nix index 4858590..f62786e 100644 --- a/machines/weilite/services/restic.nix +++ b/machines/weilite/services/restic.nix @@ -35,6 +35,8 @@ in services.restic.backups = builtins.listToAttrs [ (mkPrune "xin" "calcite") (mkPrune "xin" "massicot") + (mkPrune "xin" "biotite") + (mkPrune "xin" "thorite") ]; networking.firewall.allowedTCPPorts = [ 8443 ]; diff --git a/modules/home-manager/fish.nix b/modules/home-manager/fish.nix index 4d265d5..1b9f626 100644 --- a/modules/home-manager/fish.nix +++ b/modules/home-manager/fish.nix @@ -91,6 +91,10 @@ in ${pkgs.comma}/bin/comma $argv end set -gx LS_COLORS (${lib.getExe pkgs.vivid} generate catppuccin-mocha) + alias ctlsp="systemctl stop" + alias ctlst="systemctl start" + alias ctlrt="systemctl restart" + alias ctls="systemctl status" '' else ""; diff --git a/modules/home-manager/git.nix b/modules/home-manager/git.nix index d28eb50..56bc382 100644 --- a/modules/home-manager/git.nix +++ b/modules/home-manager/git.nix @@ -25,8 +25,9 @@ in }; }; }; - config = { - programs.git = mkIf cfg.enable { + config = mkIf cfg.enable { + home.packages = [ pkgs.git-absorb ]; + programs.git = { enable = true; delta.enable = true; userName = "Xinyang Li"; @@ -42,6 +43,10 @@ in signByDefault = true; key = cfg.signing.keyFile; }; + extraConfig.absorb = { + oneFixupPerCommit = true; + maxStack = 20; + }; extraConfig.user = mkIf cfg.signing.enable { signingkey = cfg.signing.keyFile; }; extraConfig.gpg = mkIf cfg.signing.enable { format = "ssh"; }; }; diff --git a/modules/nixos/common-settings/auth.nix b/modules/nixos/common-settings/auth.nix index d0a54cb..1cd85ec 100644 --- a/modules/nixos/common-settings/auth.nix +++ b/modules/nixos/common-settings/auth.nix @@ -9,8 +9,6 @@ let inherit (lib) mkIf mkEnableOption - mkOption - types ; cfg = config.commonSettings.auth; @@ -21,25 +19,43 @@ in }; config = mkIf cfg.enable { - custom.kanidm-client = { - enable = true; - uri = "https://auth.xinyang.life"; - asSSHAuth = { - enable = true; - allowedGroups = [ "linux_users" ]; + services.kanidm = { + enableClient = true; + clientSettings = { + uri = "https://auth.xinyang.life"; + }; + enablePam = true; + unixSettings = { + pam_allowed_login_groups = [ "linux_users" ]; + default_shell = "/bin/sh"; }; - sudoers = [ "xin@auth.xinyang.life" ]; }; services.openssh = { + enable = true; + authorizedKeysCommand = "/etc/ssh/auth %u"; + authorizedKeysCommandUser = "kanidm-ssh-runner"; settings = { PasswordAuthentication = false; KbdInteractiveAuthentication = false; - PermitRootLogin = "no"; - GSSAPIAuthentication = "no"; - KerberosAuthentication = "no"; + PermitRootLogin = lib.mkForce "no"; }; }; + + environment.etc."ssh/auth" = { + mode = "0555"; + text = '' + #!${pkgs.stdenv.shell} + ${pkgs.kanidm}/bin/kanidm_ssh_authorizedkeys $1 + ''; + }; + users.groups.wheel.members = [ "xin@auth.xinyang.life" ]; + users.groups.kanidm-ssh-runner = { }; + users.users.kanidm-ssh-runner = { + isSystemUser = true; + group = "kanidm-ssh-runner"; + }; + services.fail2ban.enable = true; security.sudo = { diff --git a/modules/nixos/common-settings/proxy-server.nix b/modules/nixos/common-settings/proxy-server.nix index b54774a..2384900 100644 --- a/modules/nixos/common-settings/proxy-server.nix +++ b/modules/nixos/common-settings/proxy-server.nix @@ -1,5 +1,6 @@ { config, + pkgs, lib, ... }: @@ -21,106 +22,117 @@ let config.security.acme.certs.${config.deployment.targetHost}.directory + "/cert.pem"; }; - mkSingConfig = - { uuid, password, ... }: - { - log = { - level = "warn"; - }; - inbounds = - [ - { - tag = "sg0"; - type = "trojan"; - listen = "::"; - listen_port = cfg.trojan.port; - tcp_multi_path = true; - tcp_fast_open = true; - users = [ - { - name = "proxy"; - password = { - _secret = password; - }; - } - ]; - tls = singTls; - } - ] - ++ lib.forEach (lib.range 6311 6314) (port: { - tag = "sg" + toString (port - 6310); - type = "tuic"; + mkSingConfig = users: { + log = { + level = "warn"; + }; + inbounds = + [ + { + tag = "sg0"; + type = "trojan"; listen = "::"; - listen_port = port; - congestion_control = "bbr"; - users = [ + listen_port = cfg.trojan.port; + tcp_multi_path = true; + tcp_fast_open = true; + users = map (user: { + name = user.name; + password = { + _secret = user.passwordFile; + }; + }) users; + tls = singTls; + } + ] + ++ lib.forEach (lib.range 6311 6314) (port: { + tag = "sg" + toString (port - 6310); + type = "tuic"; + listen = "::"; + listen_port = port; + congestion_control = "bbr"; + users = map (user: { + name = user.name; + uuid = { + _secret = user.uuidFile; + }; + password = { + _secret = user.passwordFile; + }; + }) users; + tls = singTls; + }); + outbounds = + # warp outbound goes first to make it default outbound + (lib.optionals (cfg.warp.onTuic or cfg.warp.onTrojan) [ + { + type = "wireguard"; + tag = "wg-out"; + private_key = { + _secret = config.sops.secrets.wg_private_key.path; + }; + local_address = [ + "172.16.0.2/32" + { _secret = config.sops.secrets.wg_ipv6_local_addr.path; } + ]; + peers = [ { - name = "proxy"; - uuid = { - _secret = uuid; - }; - password = { - _secret = password; - }; + public_key = "bmXOC+F1FxEMF9dyiK2H5/1SUtzH0JuVo51h2wPfgyo="; + allowed_ips = [ + "0.0.0.0/0" + "::/0" + ]; + server = "162.159.192.1"; + server_port = 500; } ]; - tls = singTls; - }); - outbounds = - # warp outbound goes first to make it default outbound - (lib.optionals (cfg.warp.onTuic or cfg.warp.onTrojan) [ - { - type = "wireguard"; - tag = "wg-out"; - private_key = { - _secret = config.sops.secrets.wg_private_key.path; - }; - local_address = [ - "172.16.0.2/32" - { _secret = config.sops.secrets.wg_ipv6_local_addr.path; } - ]; - peers = [ - { - public_key = "bmXOC+F1FxEMF9dyiK2H5/1SUtzH0JuVo51h2wPfgyo="; - allowed_ips = [ - "0.0.0.0/0" - "::/0" - ]; - server = "162.159.192.1"; - server_port = 500; - } - ]; - } - ]) - ++ [ + } + ]) + ++ [ + { + type = "direct"; + tag = "direct"; + } + ]; + route = { + rules = + [ { - type = "direct"; - tag = "direct"; + inbound = "sg4"; + outbound = "direct"; } - ]; - route = { - rules = - [ - { - inbound = "sg4"; - outbound = "direct"; - } - ] - ++ (lib.optionals (!cfg.warp.onTuic) ( - lib.forEach (lib.range 1 3) (i: { - inbound = "sg${toString i}"; - outbound = "direct"; - }) - )) - ++ (lib.optionals (!cfg.warp.onTrojan) [ - { - inbound = "sg0"; - outbound = "direct"; - } - ]); + ] + ++ (lib.optionals (!cfg.warp.onTuic) ( + lib.forEach (lib.range 1 3) (i: { + inbound = "sg${toString i}"; + outbound = "direct"; + }) + )) + ++ (lib.optionals (!cfg.warp.onTrojan) [ + { + inbound = "sg0"; + outbound = "direct"; + } + ]); + }; + experimental = { + v2ray_api = { + listen = "127.0.0.1:15175"; + stats = { + users = map (u: u.name) users; + enabled = true; + inbounds = map (p: "sg" + toString p) (lib.range 0 4); + }; }; }; + }; + sing-box = pkgs.sing-box.overrideAttrs ( + finalAttrs: previousAttrs: { + tags = previousAttrs.tags ++ [ + "with_v2ray_api" + ]; + } + ); in { options.commonSettings.proxyServer = { @@ -137,40 +149,62 @@ in onTrojan = mkEnableOption "forward to warp in trojan"; onTuic = mkEnableOption "forward to warp in first two port of tuic"; }; - }; - config = mkIf cfg.enable { - boot.kernel.sysctl = { - "net.core.default_qdisc" = "fq"; - "net.ipv4.tcp_congestion_control" = "bbr"; - }; - - networking.firewall.trustedInterfaces = [ "tun0" ]; - - security.acme = { - acceptTerms = true; - certs.${config.deployment.targetHost} = { - email = "me@namely.icu"; - # Avoid port conflict - listenHTTP = if config.services.caddy.enable then ":30310" else ":80"; - }; - }; - services.caddy.virtualHosts."http://${config.deployment.targetHost}:80".extraConfig = '' - reverse_proxy 127.0.0.1:30310 - ''; - - networking.firewall.allowedTCPPorts = [ - 80 - cfg.trojan.port - ]; - networking.firewall.allowedUDPPorts = [ ] ++ (lib.range 6311 6314); - - services.sing-box = { - enable = true; - settings = mkSingConfig { - uuid = config.sops.secrets."sing-box/uuid".path; - password = config.sops.secrets."sing-box/password".path; - }; + users = mkOption { + type = lib.types.listOf lib.types.str; }; }; + + config = mkIf cfg.enable ( + { + boot.kernel.sysctl = { + "net.core.default_qdisc" = "fq"; + "net.ipv4.tcp_congestion_control" = "bbr"; + }; + + networking.firewall.trustedInterfaces = [ "tun0" ]; + + security.acme = { + acceptTerms = true; + certs.${config.deployment.targetHost} = { + email = "me@namely.icu"; + # Avoid port conflict + listenHTTP = if config.services.caddy.enable then ":30310" else ":80"; + }; + }; + services.caddy.virtualHosts."http://${config.deployment.targetHost}:80".extraConfig = '' + reverse_proxy 127.0.0.1:30310 + ''; + + networking.firewall.allowedTCPPorts = [ + 80 + cfg.trojan.port + ]; + networking.firewall.allowedUDPPorts = [ ] ++ (lib.range 6311 6314); + + services.sing-box = { + enable = true; + package = sing-box; + settings = ( + mkSingConfig ( + map (n: { + name = n; + uuidFile = config.sops.secrets."sing-box/users/${n}/uuid".path; + passwordFile = config.sops.secrets."sing-box/users/${n}/password".path; + }) cfg.users + ) + ); + }; + } + // { + sops.secrets = ( + builtins.foldl' (a: b: a // b) { } ( + map (u: { + "sing-box/users/${u}/uuid" = { }; + "sing-box/users/${u}/password" = { }; + }) cfg.users + ) + ); + } + ); } diff --git a/modules/nixos/default.nix b/modules/nixos/default.nix index 4669a94..d2f210d 100644 --- a/modules/nixos/default.nix +++ b/modules/nixos/default.nix @@ -7,15 +7,6 @@ ./common-settings/mainland.nix ./disk-partitions ./restic.nix - ./vaultwarden.nix ./monitor - ./hedgedoc.nix - ./sing-box.nix - ./kanidm-client.nix - ./ssh-tpm-agent.nix # FIXME: Waiting for upstream merge - ./forgejo-actions-runner.nix - ./oidc-agent.nix - ./miniflux.nix - ./immich.nix ]; } diff --git a/modules/nixos/hedgedoc.nix b/modules/nixos/hedgedoc.nix deleted file mode 100644 index a632a78..0000000 --- a/modules/nixos/hedgedoc.nix +++ /dev/null @@ -1,78 +0,0 @@ -{ - config, - pkgs, - lib, - ... -}: - -with lib; - -let - cfg = config.custom.hedgedoc; -in -{ - options = { - custom.hedgedoc = { - enable = mkEnableOption "HedgeDoc Markdown Editor"; - domain = mkOption { - type = types.str; - default = "docs.example.com"; - description = "Domain name of the HedgeDoc server"; - }; - caddy = mkOption { - type = types.bool; - default = true; - description = "Enable Caddy as reverse proxy"; - }; - mediaPath = mkOption { - type = types.path; - default = /var/lib/hedgedoc/uploads; - description = "Directory for storing medias"; - }; - oidc = { - enable = mkEnableOption "OIDC support for HedgeDoc"; - baseURL = mkOption { type = types.str; }; - authorizationURL = mkOption { type = types.str; }; - tokenURL = mkOption { type = types.str; }; - userProfileURL = mkOption { type = types.str; }; - }; - environmentFile = mkOption { type = types.path; }; - }; - }; - config = mkIf cfg.enable { - services.hedgedoc = { - enable = true; - environmentFile = cfg.environmentFile; - settings = { - domain = cfg.domain; - protocolUseSSL = cfg.caddy; - uploadsPath = cfg.mediaPath; - path = "/run/hedgedoc/hedgedoc.sock"; - email = false; - allowEmailRegister = false; - oauth2 = mkIf cfg.oidc.enable { - baseURL = cfg.oidc.baseURL; - authorizationURL = cfg.oidc.authorizationURL; - tokenURL = cfg.oidc.tokenURL; - userProfileURL = cfg.oidc.userProfileURL; - userProfileEmailAttr = "email"; - userProfileUsernameAttr = "name"; - userProfileDisplayNameAttr = "preferred_name"; - scope = "openid email profile"; - clientID = "$HEDGEDOC_CLIENT_ID"; - clientSecret = "$HEDGEDOC_CLIENT_SECRET"; - }; - allowAnonymous = false; - defaultPermission = "private"; - }; - }; - services.caddy = mkIf cfg.caddy { - enable = true; - virtualHosts."https://${cfg.domain}".extraConfig = '' - reverse_proxy unix/${config.services.hedgedoc.settings.path} - ''; - }; - users.users.caddy.extraGroups = mkIf cfg.caddy [ "hedgedoc" ]; - - }; -} diff --git a/modules/nixos/immich.nix b/modules/nixos/immich.nix deleted file mode 100644 index d79afc1..0000000 --- a/modules/nixos/immich.nix +++ /dev/null @@ -1,60 +0,0 @@ -{ - config, - lib, - pkgs, - utils, - ... -}: -let - cfg = config.custom.immich; - upstreamCfg = config.services.immich; - settingsFormat = pkgs.formats.json { }; - user = config.systemd.services.immich-server.serviceConfig.User; - group = config.systemd.services.immich-server.serviceConfig.Group; -in -{ - options = { - custom.immich.jsonSettings = lib.mkOption { - type = lib.types.submodule { - freeformType = settingsFormat.type; - }; - default = { }; - }; - }; - config = { - /* - LoadCredential happens before preStart. We need to ensure the - configuration file exist, otherwise LoadCredential will fail. - */ - systemd.tmpfiles.settings = lib.mkIf upstreamCfg.enable { - "10-etc-immich" = { - "/etc/immich" = { - d = { - inherit user group; - mode = "0700"; - }; - }; - "/etc/immich/config.json" = { - "f+" = { - inherit user group; - mode = "0600"; - }; - }; - }; - }; - - systemd.services.immich-server = { - preStart = '' - umask 0077 - ${utils.genJqSecretsReplacementSnippet cfg.jsonSettings "/etc/immich/config.json"} - ''; - serviceConfig = { - LoadCredential = "config:/etc/immich/config.json"; - Environment = "IMMICH_CONFIG_FILE=%d/config"; - }; - }; - - # https://github.com/NixOS/nixpkgs/pull/324127/files#r1723763510 - services.immich.redis.host = "/run/redis-immich/redis.sock"; - }; -} diff --git a/modules/nixos/inbounds.nix b/modules/nixos/inbounds.nix deleted file mode 100644 index cd6fb9e..0000000 --- a/modules/nixos/inbounds.nix +++ /dev/null @@ -1,134 +0,0 @@ -{ config, lib, ... }: -let - cfg = config.custom.sing-box-server; - - secretFileType = lib.types.submodule { _secret = lib.types.path; }; - singTls = { - enabled = true; - server_name = config.deployment.targetHost; - key_path = config.security.acme.certs.${config.deployment.targetHost}.directory + "/key.pem"; - certificate_path = - config.security.acme.certs.${config.deployment.targetHost}.directory + "/cert.pem"; - }; -in -{ - options = { - enable = lib.mkEnableOption "sing-box proxy server"; - users = lib.types.listOf lib.types.submodule { - name = lib.mkOption { - type = lib.types.str; - default = "proxy"; - }; - password = lib.mkOption { type = secretFileType; }; - uuid = lib.mkOption { type = secretFileType; }; - }; - wgOut = { - privKeyFile = lib.mkOption { type = lib.types.path; }; - pubkey = lib.mkOption { - type = lib.types.str; - default = "bmXOC+F1FxEMF9dyiK2H5/1SUtzH0JuVo51h2wPfgyo="; - }; - }; - inbounds = { - trojan = { - enable = lib.mkOption { - type = lib.types.bool; - default = true; - }; - }; - tuic = { - enable = lib.mkOption { - type = lib.types.bool; - default = true; - }; - ports = lib.mkOption { - type = lib.types.listOf lib.types.int; - default = lib.range 6311 6313; - }; - directPorts = lib.mkOption { - type = lib.types.listOf lib.types.int; - default = [ 6314 ]; - }; - }; - }; - }; - config = lib.mkIf cfg.enable { - services.sing-box = { - enable = true; - settings = { - dns = { - servers = [ - { - address = "1.1.1.1"; - detour = "wg-out"; - } - ]; - }; - inbounds = - [ - # TODO: Trojan and tuic enable - { - tag = "trojan-in"; - type = "trojan"; - listen = "::"; - listen_port = 8080; - users = map (u: removeAttrs u [ "uuid" ]) cfg.users; - tls = singTls; - } - ] - ++ lib.forEach (cfg.tuic.ports ++ cfg.tuic.directPorts) (port: { - tag = "tuic-in" + toString port; - type = "tuic"; - listen = "::"; - listen_port = port; - congestion_control = "bbr"; - users = cfg.users; - tls = singTls; - }); - outbounds = [ - { - type = "wireguard"; - tag = "wg-out"; - private_key = cfg.wgOut.privKeyFile; - local_address = [ - "172.16.0.2/32" - "2606:4700:110:82ed:a443:3c62:6cbc:b59b/128" - ]; - peers = [ - { - public_key = cfg.wgOut.pubkey; - allowed_ips = [ - "0.0.0.0/0" - "::/0" - ]; - server = "162.159.192.1"; - server_port = 500; - } - ]; - } - { - type = "direct"; - tag = "direct-out"; - } - { - type = "dns"; - tag = "dns-out"; - } - ]; - route = { - rules = - [ - { - outbound = "dns-out"; - protocol = "dns"; - } - ] - ++ lib.forEach cfg.tuic.directPorts (port: { - inbound = "tuic-in" + toString port; - outbound = "direct-out"; - }); - }; - }; - }; - }; -} diff --git a/modules/nixos/kanidm-client.nix b/modules/nixos/kanidm-client.nix index 80e2bf9..881d48b 100644 --- a/modules/nixos/kanidm-client.nix +++ b/modules/nixos/kanidm-client.nix @@ -59,8 +59,6 @@ in PasswordAuthentication = false; KbdInteractiveAuthentication = false; PermitRootLogin = lib.mkForce "no"; - GSSAPIAuthentication = "no"; - KerberosAuthentication = "no"; }; }; diff --git a/modules/nixos/miniflux.nix b/modules/nixos/miniflux.nix deleted file mode 100644 index 0653f41..0000000 --- a/modules/nixos/miniflux.nix +++ /dev/null @@ -1,165 +0,0 @@ -{ - config, - pkgs, - lib, - ... -}: -let - inherit (lib) - mkEnableOption - mkPackageOption - mkOption - types - literalExpression - mkIf - mkDefault - ; - cfg = config.custom.miniflux; - - defaultAddress = "localhost:8080"; - - pgbin = "${config.services.postgresql.package}/bin"; - preStart = pkgs.writeScript "miniflux-pre-start" '' - #!${pkgs.runtimeShell} - ${pgbin}/psql "miniflux" -c "CREATE EXTENSION IF NOT EXISTS hstore" - ''; -in -{ - options = { - custom.miniflux = { - enable = mkEnableOption "miniflux"; - - package = mkPackageOption pkgs "miniflux" { }; - - oauth2SecretFile = mkOption { type = types.path; }; - - environment = mkOption { - type = - with types; - attrsOf (oneOf [ - int - str - ]); - }; - - createDatabaseLocally = mkOption { - type = types.bool; - default = true; - description = '' - Whether a PostgreSQL database should be automatically created and - configured on the local host. If set to `false`, you need provision a - database yourself and make sure to create the hstore extension in it. - ''; - }; - }; - }; - - config = lib.mkIf cfg.enable { - services.miniflux.enable = false; - custom.miniflux.environment = { - LISTEN_ADDR = mkDefault defaultAddress; - RUN_MIGRATIONS = mkDefault 1; - DATABASE_URL = lib.mkIf cfg.createDatabaseLocally "user=miniflux host=/run/postgresql dbname=miniflux"; - OAUTH2_CLIENT_SECRET_FILE = "%d/oauth2_secret"; - WATCHDOG = mkDefault 1; - }; - - services.postgresql = lib.mkIf cfg.createDatabaseLocally { - enable = true; - ensureUsers = [ - { - name = "miniflux"; - ensureDBOwnership = true; - } - ]; - ensureDatabases = [ "miniflux" ]; - }; - - systemd.services.miniflux-dbsetup = lib.mkIf cfg.createDatabaseLocally { - description = "Miniflux database setup"; - requires = [ "postgresql.service" ]; - after = [ - "network.target" - "postgresql.service" - ]; - serviceConfig = { - Type = "oneshot"; - User = config.services.postgresql.superUser; - ExecStart = preStart; - }; - }; - - systemd.services.miniflux = { - description = "Miniflux service"; - wantedBy = [ "multi-user.target" ]; - requires = lib.optional cfg.createDatabaseLocally "miniflux-dbsetup.service"; - after = - [ "network.target" ] - ++ lib.optionals cfg.createDatabaseLocally [ - "postgresql.service" - "miniflux-dbsetup.service" - ]; - - serviceConfig = { - Type = "notify"; - ExecStart = lib.getExe cfg.package; - User = "miniflux"; - DynamicUser = true; - LoadCredential = [ "oauth2_secret:${cfg.oauth2SecretFile}" ]; - RuntimeDirectory = "miniflux"; - RuntimeDirectoryMode = "0750"; - WatchdogSec = 60; - WatchdogSignal = "SIGKILL"; - Restart = "always"; - RestartSec = 5; - - # Hardening - CapabilityBoundingSet = [ "" ]; - DeviceAllow = [ "" ]; - LockPersonality = true; - MemoryDenyWriteExecute = true; - PrivateDevices = true; - PrivateUsers = true; - ProcSubset = "pid"; - ProtectClock = true; - ProtectControlGroups = true; - ProtectHome = true; - ProtectHostname = true; - ProtectKernelLogs = true; - ProtectKernelModules = true; - ProtectKernelTunables = true; - ProtectProc = "invisible"; - RestrictAddressFamilies = [ - "AF_INET" - "AF_INET6" - "AF_UNIX" - ]; - RestrictNamespaces = true; - RestrictRealtime = true; - RestrictSUIDSGID = true; - SystemCallArchitectures = "native"; - SystemCallFilter = [ - "@system-service" - "~@privileged" - ]; - UMask = "0077"; - }; - - environment = lib.mapAttrs (_: toString) cfg.environment; - }; - environment.systemPackages = [ cfg.package ]; - - security.apparmor.policies."bin.miniflux".profile = '' - include - ${cfg.package}/bin/miniflux { - include - include - include - include "${pkgs.apparmorRulesFromClosure { name = "miniflux"; } cfg.package}" - r ${cfg.package}/bin/miniflux, - r @{sys}/kernel/mm/transparent_hugepage/hpage_pmd_size, - rw /run/miniflux/**, - } - ''; - }; -} diff --git a/modules/nixos/monitor/default.nix b/modules/nixos/monitor/default.nix index 249f13b..71ec05e 100644 --- a/modules/nixos/monitor/default.nix +++ b/modules/nixos/monitor/default.nix @@ -11,6 +11,7 @@ let mkMerge types ; + inherit (config.my-lib.settings) ntfyUrl; cfg = config.custom.prometheus; mkRulesOption = mkOption { @@ -56,6 +57,13 @@ in default = "${config.networking.hostName}.coho-tet.ts.net"; }; }; + v2ray = { + enable = mkEnableOption "blackbox exporter"; + listenAddress = mkOption { + type = types.str; + default = "${config.networking.hostName}.coho-tet.ts.net"; + }; + }; }; }; }; @@ -81,19 +89,9 @@ in ]; } (mkIf cfg.enable { - - services.tailscale = { - enable = true; - permitCertUid = config.services.caddy.user; - openFirewall = true; - }; - - services.caddy = { - enable = true; - virtualHosts."${config.networking.hostName}.coho-tet.ts.net".extraConfig = '' - reverse_proxy 127.0.0.1:${toString config.services.prometheus.port} - ''; - }; + services.caddy.virtualHosts."${config.networking.hostName}.coho-tet.ts.net".extraConfig = '' + reverse_proxy 127.0.0.1:${toString config.services.prometheus.port} + ''; services.prometheus = mkIf cfg.enable { enable = true; port = 9091; @@ -121,12 +119,11 @@ in name = "ntfy"; webhook_configs = [ { - url = "https://ntfy.xinyang.life/prometheus-alerts?tpl=yes&m=${lib.escapeURL '' - Alert {{.status}} - {{range .alerts}}-----{{range $k,$v := .labels}} + url = "${ntfyUrl}/prometheus-alerts?tpl=yes&m=${lib.escapeURL '' + {{range .alerts}}[{{ if eq .status "resolved" }}✅ RESOLVED{{ else }}{{ if eq .status "firing" }}🔥 FIRING{{end}}{{end}}]{{range $k,$v := .labels}} {{$k}}={{$v}}{{end}} - {{end}} - ''}"; + + {{end}}''}"; send_resolved = true; } ]; diff --git a/modules/nixos/monitor/exporters.nix b/modules/nixos/monitor/exporters.nix index 0c9b95d..56750ef 100644 --- a/modules/nixos/monitor/exporters.nix +++ b/modules/nixos/monitor/exporters.nix @@ -5,7 +5,8 @@ ... }: let - inherit (lib) mkIf; + inherit (lib) mkIf concatStringsSep; + inherit (config.my-lib.settings) prometheusCollectors; cfg = config.custom.prometheus.exporters; in { @@ -46,6 +47,13 @@ in ); }; + services.prometheus.exporters.v2ray = mkIf cfg.v2ray.enable { + enable = true; + listenAddress = cfg.v2ray.listenAddress; + port = 9516; + v2rayEndpoint = config.services.sing-box.settings.experimental.v2ray_api.listen; + }; + # gotosocial sops.templates."gotosocial_metrics.env" = { content = '' @@ -71,7 +79,7 @@ in services.restic.server.prometheus = true; - # miniflux + # miniflux sops.templates."miniflux_metrics_env" = { content = '' METRICS_COLLECTOR=1 @@ -95,8 +103,28 @@ in metrics } - admin ${config.networking.hostName}.coho-tet.ts.net:2019 { + admin unix//var/run/caddy/admin.sock { + origins 127.0.0.1 ${config.networking.hostName}.coho-tet.ts.net:2019 } ''; + + systemd.services.caddy.serviceConfig = { + RuntimeDirectory = "caddy"; + RuntimeDirectoryMode = "0700"; + }; + + services.tailscale = { + permitCertUid = config.services.caddy.user; + openFirewall = true; + }; + + services.caddy = { + virtualHosts."https://${config.networking.hostName}.coho-tet.ts.net:2019".extraConfig = '' + handle /metrics { + reverse_proxy unix//var/run/caddy/admin.sock + } + respond 403 + ''; + }; }; } diff --git a/modules/nixos/monitor/grafana.nix b/modules/nixos/monitor/grafana.nix index e1b2cf3..9692fb5 100644 --- a/modules/nixos/monitor/grafana.nix +++ b/modules/nixos/monitor/grafana.nix @@ -1,5 +1,6 @@ { config, lib, ... }: let + inherit (config.my-lib.settings) grafanaUrl idpUrl; cfg = config.custom.monitoring.grafana; in { @@ -13,17 +14,17 @@ in server = { http_addr = "127.0.0.1"; http_port = 3003; - root_url = "https://grafana.xinyang.life"; - domain = "grafana.xinyang.life"; + root_url = grafanaUrl; + domain = lib.removePrefix "https://" grafanaUrl; }; "auth.generic_oauth" = { enabled = true; name = "Kanidm"; client_id = "grafana"; scopes = "openid,profile,email,groups"; - auth_url = "https://auth.xinyang.life/ui/oauth2"; - token_url = "https://auth.xinyang.life/oauth2/token"; - api_url = "https://auth.xinyang.life/oauth2/openid/grafana/userinfo"; + auth_url = "${idpUrl}/ui/oauth2"; + token_url = "${idpUrl}/oauth2/token"; + api_url = "${idpUrl}/oauth2/openid/grafana/userinfo"; use_pkce = true; use_refresh_token = true; allow_sign_up = true; diff --git a/modules/nixos/monitor/loki.nix b/modules/nixos/monitor/loki.nix index 324235f..105a33a 100644 --- a/modules/nixos/monitor/loki.nix +++ b/modules/nixos/monitor/loki.nix @@ -1,68 +1,159 @@ { + pkgs, config, lib, ... }: let inherit (lib) + mkOption mkEnableOption mkIf mkMerge + types + literalExpression + ; + inherit (config.my-lib.settings) + alertmanagerPort ; cfg = config.custom.monitoring; - port-loki = 3100; + lokiPort = 3100; in { options = { custom.monitoring = { - loki.enable = mkEnableOption "loki"; + loki = { + enable = mkEnableOption "loki"; + rules = mkOption { + type = types.attrsOf ( + types.submodule { + options = { + expr = mkOption { + type = types.str; + description = '' + Loki alert expression. + ''; + example = ''count_over_time({job=~"secure"} |="sshd[" |~": Failed|: Invalid|: Connection closed by authenticating user" | __error__="" [15m]) > 15''; + default = null; + }; + description = mkOption { + type = types.str; + description = '' + Loki alert message. + ''; + example = "Prometheus encountered value {{ $value }} with {{ $labels }}"; + default = null; + }; + labels = mkOption { + type = types.nullOr (types.attrsOf types.str); + description = '' + Additional alert labels. + ''; + example = literalExpression '' + { severity = "page" }; + ''; + default = { }; + }; + time = mkOption { + type = types.str; + description = '' + Time until the alert is fired. + ''; + example = "5m"; + default = "2m"; + }; + }; + } + ); + description = '' + Defines the loki rules. + ''; + default = { }; + }; + }; promtail.enable = mkEnableOption "promtail"; }; }; config = mkMerge [ - (mkIf cfg.loki.enable { - services.loki = { - enable = true; - configuration = { - auth_enabled = false; - server.http_listen_address = "${config.networking.hostName}.coho-tet.ts.net"; - server.http_listen_port = port-loki; - - common = { - ring = { - instance_addr = "${config.networking.hostName}.coho-tet.ts.net"; - kvstore.store = "inmemory"; - }; - replication_factor = 1; - path_prefix = "/var/lib/loki"; - }; - - schema_config.configs = [ + ( + let + rulerConfig = { + groups = [ { - from = "2024-12-01"; - store = "boltdb-shipper"; - object_store = "filesystem"; - schema = "v13"; - index = { - prefix = "index_"; - period = "24h"; - }; + name = "alerting-rules"; + rules = lib.mapAttrsToList (name: opts: { + alert = name; + inherit (opts) expr labels; + for = opts.time; + annotations.description = opts.description; + }) cfg.loki.rules; } ]; + }; + rulerFile = pkgs.writeText "ruler.yml" (builtins.toJSON rulerConfig); + in + mkIf cfg.loki.enable { + services.loki = { + enable = true; + configuration = { + auth_enabled = false; + server.http_listen_address = "${config.networking.hostName}.coho-tet.ts.net"; + server.http_listen_port = lokiPort; - storage_config = { - filesystem.directory = "/var/lib/loki/chunks"; - }; + common = { + ring = { + instance_addr = "${config.networking.hostName}.coho-tet.ts.net"; + kvstore.store = "inmemory"; + }; + replication_factor = 1; + path_prefix = "/var/lib/loki"; + }; - limits_config = { - reject_old_samples = true; - reject_old_samples_max_age = "168h"; - allow_structured_metadata = false; + schema_config.configs = [ + { + from = "2024-12-01"; + store = "boltdb-shipper"; + object_store = "filesystem"; + schema = "v13"; + index = { + prefix = "index_"; + period = "24h"; + }; + } + ]; + + storage_config = { + filesystem.directory = "/var/lib/loki/chunks"; + }; + + limits_config = { + reject_old_samples = true; + reject_old_samples_max_age = "168h"; + allow_structured_metadata = false; + }; + + ruler = { + storage = { + type = "local"; + local.directory = "${config.services.loki.dataDir}/rules"; + }; + rule_path = "${config.services.loki.dataDir}/rules-temp"; + enable_api = true; + alertmanager_url = "http://127.0.0.1:${toString alertmanagerPort}"; + }; }; }; - }; - }) + systemd.tmpfiles.rules = [ + "d /var/lib/loki 0700 loki loki - -" + "d /var/lib/loki/rules-temp 0700 loki loki - -" + "d /var/lib/loki/rules 0700 loki loki - -" + "d /var/lib/loki/rules/fake 0700 loki loki - -" + "L /var/lib/loki/rules/fake/ruler.yml - - - - ${rulerFile}" + ]; + systemd.services.loki.restartTriggers = [ rulerFile ]; + } + ) (mkIf cfg.promtail.enable { services.promtail = { enable = true; @@ -78,7 +169,7 @@ in clients = [ { - url = "http://thorite.coho-tet.ts.net:${toString port-loki}/loki/api/v1/push"; + url = "http://thorite.coho-tet.ts.net:${toString lokiPort}/loki/api/v1/push"; } ]; @@ -150,17 +241,42 @@ in ]; } # { - # job_name = "caddy-access"; - # file_sd_configs = { - # files = [ - # "/var/log/caddy/*.log" - # ]; - # refresh_interval = "5m"; - # }; + # job_name = "caddy"; + # static_configs = [ + # { + # targets = [ "localhost" ]; + # labels = { + # job = "caddy"; + # __path__ = "/var/log/caddy/*log"; + # agent = "caddy-promtail"; + # }; + # } + # ]; + # pipeline_stages = [ + # { + # json = { + # expressions = { + # duration = "duration"; + # status = "status"; + # }; + # }; + # } + # { + # labels = { + # duration = null; + # status = null; + # }; + # } + # ]; # } ]; }; }; + + services.caddy.logFormat = '' + format json + level INFO + ''; }) ]; } diff --git a/modules/nixos/restic.nix b/modules/nixos/restic.nix index bef9c44..f07bdfb 100644 --- a/modules/nixos/restic.nix +++ b/modules/nixos/restic.nix @@ -39,7 +39,7 @@ let echo "Creating snapshot for ${rootDir}" subvolumes=$(${pkgs.btrfs-progs}/bin/btrfs subvolume list -o "${rootDir}" | ${awk} '{print $NF}') mkdir -p "${backupDir}" - ${pkgs.btrfs-progs}/bin/btrfs subvolume snapshot -r "${rootDir}" "${backupDir}/rootfs" + ${pkgs.btrfs-progs}/bin/btrfs subvolume snapshot -r "${rootDir}" "${backupDir}/rootDirectory" for subvol in $subvolumes; do ${continueIfInExclude} [[ /"$subvol" == "${backupDir}"* ]] && continue diff --git a/modules/nixos/sing-box.nix b/modules/nixos/sing-box.nix deleted file mode 100644 index 695356e..0000000 --- a/modules/nixos/sing-box.nix +++ /dev/null @@ -1,87 +0,0 @@ -{ - config, - pkgs, - lib, - utils, - ... -}: -let - cfg = config.custom.sing-box; - settingsFormat = pkgs.formats.json { }; -in -{ - options = { - custom.sing-box = { - enable = lib.mkEnableOption "sing-box"; - - package = lib.mkPackageOption pkgs "sing-box" { }; - - stateDir = lib.mkOption { - type = lib.types.path; - default = "/var/lib/sing-box"; - }; - - configFile = { - urlFile = lib.mkOption { type = lib.types.path; }; - name = lib.mkOption { - type = lib.types.str; - default = "config.json"; - }; - hash = lib.mkOption { - type = lib.types.str; - example = "9a304bcb87d4c3f1e50f6281f25dd78635255ebde06cd4d2555729ecda43aed4"; - }; - }; - - overrideSettings = lib.mkOption { - type = lib.types.submodule { - freeformType = settingsFormat.type; - options = { - route = { - geoip.path = lib.mkOption { - type = lib.types.path; - default = "${pkgs.sing-geoip}/share/sing-box/geoip.db"; - defaultText = lib.literalExpression "\${pkgs.sing-geoip}/share/sing-box/geoip.db"; - description = lib.mdDoc '' - The path to the sing-geoip database. - ''; - }; - geosite.path = lib.mkOption { - type = lib.types.path; - default = "${pkgs.sing-geosite}/share/sing-box/geosite.db"; - defaultText = lib.literalExpression "\${pkgs.sing-geosite}/share/sing-box/geosite.db"; - description = lib.mdDoc '' - The path to the sing-geosite database. - ''; - }; - }; - }; - }; - default = { }; - }; - }; - }; - config = lib.mkIf cfg.enable { - networking.firewall.trustedInterfaces = [ "tun0" ]; - - systemd.packages = [ cfg.package ]; - - systemd.services.sing-box = - let - configFile = cfg.stateDir + "/${cfg.configFile.name}"; - in - { - preStart = '' - umask 0077 - mkdir -p /etc/sing-box - if ! [ -e ${configFile} ]; then - ${pkgs.curl}/bin/curl "$(${pkgs.coreutils}/bin/cat ${cfg.configFile.urlFile})" > '${configFile}' - test "${cfg.configFile.hash}" $(${pkgs.coreutils}/bin/sha256sum '${configFile}' | ${pkgs.coreutils}/bin/cut -d ' ' -f 1) - fi - ${utils.genJqSecretsReplacementSnippet cfg.overrideSettings "/etc/sing-box/config.json"} - ${cfg.package}/bin/sing-box merge -c '${configFile}' -c /etc/sing-box/config.json /etc/sing-box/config.json - ''; - wantedBy = [ "multi-user.target" ]; - }; - }; -} diff --git a/note.md b/note.md index 93a14d6..6b25aae 100644 --- a/note.md +++ b/note.md @@ -1,3 +1,10 @@ # nix-tree Demonstrate disk usage by nix-store path. + +## TODO +- [x] change caddy admin to unix socket +- [ ] admin config persist = false +- [x] synapse jmalloc +- [ ] backup all directories under /var/lib/forgejo +- [ ] collect caddy access logs with promtail (waiting for caddy v2.9.0 release after which log file mode can be set) diff --git a/overlays/my-lib/default.nix b/overlays/my-lib/default.nix index 8d07bc1..c684e36 100644 --- a/overlays/my-lib/default.nix +++ b/overlays/my-lib/default.nix @@ -1,3 +1,11 @@ { + mkSystemdDebug = + { lib, pkgs }: + { + ExecStart = lib.mkForce "${pkgs.tmux}/bin/tmux -S /tmp/tmux.socket new-session -s my-session -d"; + ExecStop = lib.mkForce "${pkgs.tmux}/bin/tmux -S /tmp/tmux.socket kill-session -t my-session"; + Type = "forking"; + }; } // (import ./prometheus.nix) +// (import ./settings.nix) diff --git a/overlays/my-lib/prometheus.nix b/overlays/my-lib/prometheus.nix index da43f77..c79f131 100644 --- a/overlays/my-lib/prometheus.nix +++ b/overlays/my-lib/prometheus.nix @@ -28,17 +28,51 @@ in ) ); - mkCaddyScrapes = mkFunction ( + mkV2rayScrapes = targets: [ { - address, - port ? 2019, - ... - }: - { - job_name = "caddy_${address}"; - static_configs = [ { targets = [ "${address}${mkPort port}" ]; } ]; + job_name = "v2ray-exporter"; + scheme = "http"; + static_configs = map ( + { + address, + port ? 9516, + }: + { + targets = [ "${address}${mkPort port}" ]; + } + ) targets; } - ); + { + job_name = "singbox_stat"; + scheme = "http"; + metrics_path = "/scrape"; + static_configs = map ( + { + address, + port ? 9516, + }: + { + targets = [ "${address}${mkPort port}" ]; + } + ) targets; + } + ]; + + mkCaddyScrapes = targets: [ + { + job_name = "caddy"; + scheme = "https"; + static_configs = map ( + { + address, + port ? 2019, + }: + { + targets = [ "${address}${mkPort port}" ]; + } + ) targets; + } + ]; mkCaddyRules = mkFunction ( { @@ -63,17 +97,20 @@ in } ); - mkNodeScrapes = mkFunction ( + mkNodeScrapes = targets: [ { - address, - port ? 9100, - ... - }: - { - job_name = "node_${address}"; - static_configs = [ { targets = [ "${address}${mkPort port}" ]; } ]; + job_name = "node_exporter"; + static_configs = map ( + { + address, + port ? 9100, + }: + { + targets = [ "${address}${mkPort port}" ]; + } + ) targets; } - ); + ]; mkNodeRules = mkFunction ( { @@ -108,22 +145,10 @@ in description = "The 1-minute load average ({{ $value }}) exceeds 80% the number of CPUs."; }; } - { - alert = "HighTransmitTraffic"; - expr = "rate(node_network_transmit_bytes_total{device!=\"lo\"}[5m]) > 100000000"; - for = "1m"; - labels = { - severity = "warning"; - }; - annotations = { - summary = "High network transmit traffic on {{ $labels.instance }} ({{ $labels.device }})"; - description = "The network interface {{ $labels.device }} on {{ $labels.instance }} is transmitting data at a rate exceeding 100 MB/s for the last 1 minute."; - }; - } { alert = "NetworkTrafficExceedLimit"; - expr = ''increase(node_network_transmit_bytes_total{device!="lo",device!~"tailscale.*",device!~"wg.*",device!~"br.*"}[30d]) > 322122547200''; - for = "0m"; + expr = ''sum by(instance) (increase(node_network_transmit_bytes_total{device!="lo", device!~"tailscale.*", device!~"wg.*", device!~"br.*"}[30d])) > 322122547200''; + for = "1m"; labels = { severity = "critical"; }; @@ -131,6 +156,66 @@ in summary = "Outbound network traffic exceed 300GB for last 30 day"; }; } + { + alert = "HighDiskUsage"; + expr = ''(1 - node_filesystem_free_bytes{fstype!~"vfat|ramfs"} / node_filesystem_size_bytes) * 100 > 85''; + for = "5m"; + labels = { + severity = "warning"; + }; + annotations = { + summary = "High disk usage on {{ $labels.instance }}"; + }; + } + { + alert = "DiskWillFull"; + expr = ''predict_linear(node_filesystem_free_bytes{fstype!~"vfat|ramfs"}[1h], 12 * 3600) < (node_filesystem_size_bytes * 0.05)''; + + for = "3m"; + labels = { + severity = "critical"; + }; + annotations = { + summary = "Disk usage will exceed 95% in 12 hours on {{ $labels.instance }}"; + description = "Disk {{ $labels.mountpoint }} is predicted to exceed 92% usage within 12 hours at current growth rate"; + }; + } + { + alert = "HighSwapUsage"; + expr = ''(1 - (node_memory_SwapFree_bytes / node_memory_SwapTotal_bytes)) * 100 > 80''; + for = "5m"; + labels = { + severity = "warning"; + }; + annotations = { + summary = "High swap usage on {{ $labels.instance }}"; + description = "Swap usage is above 80% for 5 minutes\n Current value: {{ $value }}%"; + }; + } + { + alert = "OOMKillDetected"; + expr = ''increase(node_vmstat_oom_kill[5m]) > 0''; + for = "1m"; + labels = { + severity = "critical"; + }; + annotations = { + summary = "OOM kill detected on {{ $labels.instance }}"; + description = "Out of memory killer was triggered in the last 5 minutes"; + }; + } + { + alert = "HighMemoryUsage"; + expr = ''(1 - (node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes)) * 100 > 90''; + for = "5m"; + labels = { + severity = "warning"; + }; + annotations = { + summary = "High memory usage on {{ $labels.instance }}"; + description = "Memory usage is above 90% for 5 minutes\n Current value: {{ $value }}%"; + }; + } ]; } ); @@ -152,6 +237,9 @@ in static_configs = [ { targets = targetAddresses; + labels = { + from = hostAddress; + }; } ]; relabel_configs = [ @@ -179,6 +267,17 @@ in { inherit name; rules = [ + { + alert = "ProbeError"; + expr = "probe_success != 1"; + for = "3m"; + labels = { + severity = "critical"; + }; + annotations = { + summary = "Probing {{ $labels.instance }} from {{ $labels.from }} failed"; + }; + } { alert = "HighProbeLatency"; expr = "probe_duration_seconds > 0.5"; @@ -187,23 +286,25 @@ in severity = "warning"; }; annotations = { - summary = "High request latency on {{ $labels.instance }}"; - description = "Request latency is above 0.5 seconds for the last 3 minutes."; + summary = "High request latency from {{ $labels.from }} to {{ $labels.instance }}"; + description = "Request latency is above 0.5 seconds for the last 2 minutes."; }; } { alert = "VeryHighProbeLatency"; - expr = "probe_duration_seconds > 1"; + expr = "probe_duration_seconds > 2"; for = "3m"; labels = { severity = "critical"; }; annotations = { - summary = "High request latency on {{ $labels.instance }}"; - description = "Request latency is above 0.5 seconds for the last 3 minutes."; + summary = "Very high request latency from {{ $labels.from }} to {{ $labels.instance }}"; + description = "Request latency is above 2 seconds for the last 2 minutes."; }; } ]; } ); + + # mkResticScrapes = mkFunction () ; } diff --git a/overlays/my-lib/settings.nix b/overlays/my-lib/settings.nix new file mode 100644 index 0000000..46bdb04 --- /dev/null +++ b/overlays/my-lib/settings.nix @@ -0,0 +1,20 @@ +{ + settings = { + alertmanagerPort = 9093; + idpUrl = "https://auth.xinyang.life"; + gotosocialUrl = "https://gts.xiny.li"; + minifluxUrl = "https://rss.xiny.li"; + hedgedocDomain = "docs.xiny.li"; + forgejoDomain = "git.xiny.li"; + forgejoGitDomain = "git.xiny.li"; + vaultwardenUrl = "https://vaultwarden.xiny.li"; + ntfyUrl = "https://ntfy.xiny.li"; + grafanaUrl = "https://grafana.xiny.li"; + synapseUrl = "https://xiny.li"; + synapseDelegateUrl = "https://synapse.xiny.li"; + + prometheusCollectors = [ + "thorite.coho-tet.ts.net" + ]; + }; +} diff --git a/overlays/pkgs/oidc-agent/default.nix b/overlays/pkgs/oidc-agent/default.nix deleted file mode 100644 index 9634c4c..0000000 --- a/overlays/pkgs/oidc-agent/default.nix +++ /dev/null @@ -1,56 +0,0 @@ -{ - lib, - stdenv, - fetchFromGitHub, - curl, - webkitgtk, - libmicrohttpd, - libsecret, - qrencode, - libsodium, - pkg-config, - help2man, -}: - -stdenv.mkDerivation rec { - pname = "oidc-agent"; - version = "5.1.0"; - - src = fetchFromGitHub { - owner = "indigo-dc"; - repo = "oidc-agent"; - rev = "v${version}"; - sha256 = "sha256-cOK/rZ/jnyALLuhDM3+qvwwe4Fjkv8diQBkw7NfVo0c="; - }; - - buildInputs = [ - pkg-config - help2man - ]; - nativeBuildInputs = [ - curl - webkitgtk - libmicrohttpd - libsecret - qrencode - libsodium - ]; - enableParallelBuilding = true; - - installPhase = '' - make -j $NIX_BUILD_CORES PREFIX=$out BIN_PATH=$out LIB_PATH=$out/lib \ - install_bin install_lib install_conf - ''; - postFixup = '' - # Override with patched binary to be used by help2man - cp -r $out/bin/* bin - make install_man PREFIX=$out - ''; - - meta = with lib; { - description = "oidc-agent for managing OpenID Connect tokens on the command line"; - homepage = "https://github.com/indigo-dc/oidc-agent"; - maintainers = [ ]; - license = licenses.mit; - }; -}