From ed15ef02bb1eaac2c0c4c2de90fe65f229288fff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leon=20Schwarz=C3=A4ugl?= Date: Sun, 15 Jun 2025 04:36:40 +0200 Subject: [PATCH] feat: network overhaul --- .envrc | 1 - .sops.yaml | 3 + SwarselSystems.org | 1355 ++++++++++++-------- hosts/nixos/iso/default.nix | 159 +-- hosts/nixos/moonside/default.nix | 35 +- hosts/nixos/nbl-imba-2/default.nix | 1 - hosts/nixos/nbl-imba-2/secrets/pii.nix.enc | 10 +- hosts/nixos/sync/default.nix | 1 - hosts/nixos/winters/default.nix | 1 - lib/default.nix | 4 + modules/nixos/common/meta.nix | 4 + modules/nixos/common/nodes.nix | 78 ++ modules/nixos/common/syncthing.nix | 2 +- modules/nixos/common/users.nix | 7 +- modules/nixos/optional/work.nix | 2 +- modules/nixos/server/firefly-iii.nix | 112 +- modules/nixos/server/freshrss.nix | 13 +- modules/nixos/server/immich.nix | 31 +- modules/nixos/server/jellyfin.nix | 27 +- modules/nixos/server/kanidm.nix | 147 +-- modules/nixos/server/kavita.nix | 32 +- modules/nixos/server/koillection.nix | 29 +- modules/nixos/server/matrix.nix | 158 +-- modules/nixos/server/monitoring.nix | 109 +- modules/nixos/server/navidrome.nix | 38 +- modules/nixos/server/nextcloud.nix | 50 +- modules/nixos/server/oauth2-proxy.nix | 107 ++ modules/nixos/server/paperless.nix | 40 +- modules/nixos/server/syncthing.nix | 56 +- nix/sops-decrypt-and-cache.sh | 1 - profiles/nixos/moonside/default.nix | 1 + secrets/general/secrets.yaml | 114 +- secrets/moonside/secrets.yaml | 7 +- secrets/repo/pii.nix.enc | 6 +- 34 files changed, 1704 insertions(+), 1037 deletions(-) delete mode 100644 .envrc create mode 100644 modules/nixos/common/nodes.nix create mode 100644 modules/nixos/server/oauth2-proxy.nix diff --git a/.envrc b/.envrc deleted file mode 100644 index 3550a30..0000000 --- a/.envrc +++ /dev/null @@ -1 +0,0 @@ -use flake diff --git a/.sops.yaml b/.sops.yaml index 4f80904..408fcd4 100644 --- a/.sops.yaml +++ b/.sops.yaml @@ -22,6 +22,8 @@ creation_rules: - *toto - *surface - *nbl + - *sync + - *moonside - path_regex: secrets/repo/[^/]+$ key_groups: - pgp: @@ -73,6 +75,7 @@ creation_rules: - *swarsel age: - *nbl + - *moonside - path_regex: hosts/nixos/winters/secrets/pii.nix.enc key_groups: - pgp: diff --git a/SwarselSystems.org b/SwarselSystems.org index cabd4b3..cf41a25 100644 --- a/SwarselSystems.org +++ b/SwarselSystems.org @@ -340,75 +340,75 @@ In this section I am creating some attributes that define general concepts of my They are defined in [[#h:5e3e21e0-57af-4dad-b32f-6400af9b7aab][Overlays (additions, overrides, nixpkgs-stable)]]. The way this is handled was simplified in =647a2ae feat: simplify overlay structure=; however, the old structure might be easier to understand as a reference. #+begin_src nix :tangle no :noweb-ref flakeoutputgeneral - inherit lib; + inherit lib; - # nixosModules = import ./modules/nixos { inherit lib; }; - # homeModules = import ./modules/home { inherit lib; }; - packages = lib.swarselsystems.forEachSystem (pkgs: import ./pkgs { inherit lib pkgs; }); - formatter = lib.swarselsystems.forEachSystem (pkgs: pkgs.nixpkgs-fmt); - overlays = import ./overlays { inherit self lib inputs; }; + # nixosModules = import ./modules/nixos { inherit lib; }; + # homeModules = import ./modules/home { inherit lib; }; + packages = lib.swarselsystems.forEachSystem (pkgs: import ./pkgs { inherit lib pkgs; }); + formatter = lib.swarselsystems.forEachSystem (pkgs: pkgs.nixpkgs-fmt); + overlays = import ./overlays { inherit self lib inputs; }; - apps = lib.swarselsystems.forAllSystems (system: - let - appNames = [ - "swarsel-bootstrap" - "swarsel-install" - "swarsel-rebuild" - "swarsel-postinstall" + apps = lib.swarselsystems.forAllSystems (system: + let + appNames = [ + "swarsel-bootstrap" + "swarsel-install" + "swarsel-rebuild" + "swarsel-postinstall" + ]; + appSet = lib.swarselsystems.mkApps system appNames self; + in + + appSet // { + default = appSet.swarsel-bootstrap; + } + ); + + devShells = lib.swarselsystems.forAllSystems (system: + let + pkgs = lib.swarselsystems.pkgsFor.${system}; + checks = self.checks.${system}; + in + { + default = pkgs.mkShell { + # plugin-files = ${pkgs.nix-plugins.overrideAttrs (o: { + # buildInputs = [pkgs.nixVersions.latest pkgs.boost]; + # patches = (o.patches or []) ++ [ "${self}/nix/nix-plugins.patch" ]; + # })}/lib/nix/plugins + NIX_CONFIG = '' + plugin-files = ${pkgs.nix-plugins}/lib/nix/plugins + extra-builtins-file = ${self + /nix/extra-builtins.nix} + ''; + inherit (checks.pre-commit-check) shellHook; + + buildInputs = checks.pre-commit-check.enabledPackages; + nativeBuildInputs = [ + (builtins.trace "alarm: we pinned nix_2_24 because of https://github.com/shlevy/nix-plugins/issues/20" pkgs.nixVersions.nix_2_24) # Always use the nix version from this flake's nixpkgs version, so that nix-plugins (below) doesn't fail because of different nix versions. + # pkgs.nix + pkgs.home-manager + pkgs.git + pkgs.just + pkgs.age + pkgs.ssh-to-age + pkgs.sops + pkgs.statix + pkgs.deadnix + pkgs.nixpkgs-fmt ]; - appSet = lib.swarselsystems.mkApps system appNames self; - in + }; + } + ); - appSet // { - default = appSet.swarsel-bootstrap; - } - ); + templates = import ./templates { inherit lib; }; - devShells = lib.swarselsystems.forAllSystems (system: - let - pkgs = lib.swarselsystems.pkgsFor.${system}; - checks = self.checks.${system}; - in - { - default = pkgs.mkShell { - # plugin-files = ${pkgs.nix-plugins.overrideAttrs (o: { - # buildInputs = [pkgs.nixVersions.latest pkgs.boost]; - # patches = (o.patches or []) ++ [ "${self}/nix/nix-plugins.patch" ]; - # })}/lib/nix/plugins - NIX_CONFIG = '' - plugin-files = ${pkgs.nix-plugins}/lib/nix/plugins - extra-builtins-file = ${self + /nix/extra-builtins.nix} - ''; - inherit (checks.pre-commit-check) shellHook; + checks = lib.swarselsystems.forAllSystems (system: + let + pkgs = lib.swarselsystems.pkgsFor.${system}; + in + import ./checks { inherit self inputs system pkgs; } + ); - buildInputs = checks.pre-commit-check.enabledPackages; - nativeBuildInputs = [ - (builtins.trace "alarm: we pinned nix_2_24 because of https://github.com/shlevy/nix-plugins/issues/20" pkgs.nixVersions.nix_2_24) # Always use the nix version from this flake's nixpkgs version, so that nix-plugins (below) doesn't fail because of different nix versions. - # pkgs.nix - pkgs.home-manager - pkgs.git - pkgs.just - pkgs.age - pkgs.ssh-to-age - pkgs.sops - pkgs.statix - pkgs.deadnix - pkgs.nixpkgs-fmt - ]; - }; - } - ); - - templates = import ./templates { inherit lib; }; - - checks = lib.swarselsystems.forAllSystems (system: - let - pkgs = lib.swarselsystems.pkgsFor.${system}; - in - import ./checks { inherit self inputs system pkgs; } - ); - - diskoConfigurations.default = import .templates/hosts/nixos/disk-config.nix; + diskoConfigurations.default = import .templates/hosts/nixos/disk-config.nix; #+end_src ** Pre-commit-hooks (Checks) @@ -834,7 +834,6 @@ My work machine. Built for more security, this is the gold standard of my config ]; - node.secretsDir = ./secrets; swarselsystems = lib.recursiveUpdate { firewall = lib.mkForce true; @@ -1092,7 +1091,6 @@ This is my main server that I run at home. It handles most tasks that require bi }; - node.secretsDir = ./secrets; swarselsystems = lib.recursiveUpdate { isImpermanence = false; @@ -1329,7 +1327,6 @@ This machine mainly acts as an external sync helper. It manages the following th system.stateVersion = "23.11"; - node.secretsDir = ./secrets; services = { nginx = { virtualHosts = { @@ -1483,7 +1480,19 @@ This machine mainly acts as an external sync helper. It manages the following th tmp.cleanOnBoot = true; }; - environment.etc."issue".text = "\4"; + environment = { + etc."issue".text = "\4"; + + persistence."/persist".directories = lib.mkIf config.swarselsystems.isImpermanence [ + { + directory = "/var/lib/syncthing"; + user = "syncthing"; + group = "syncthing"; + mode = "0700"; + } + ]; + }; + networking = { nftables.enable = lib.mkForce false; @@ -1498,14 +1507,17 @@ This machine mainly acts as an external sync helper. It manages the following th interfaces = { home-vpn = { privateKeyFile = config.sops.secrets.wireguard-private-key.path; - ips = [ "192.168.3.4/24" ]; + ips = [ "192.168.3.4/32" ]; peers = [ { publicKey = "NNGvakADslOTCmN9HJOW/7qiM+oJ3jAlSZGoShg4ZWw="; name = "moonside"; persistentKeepalive = 25; endpoint = "${config.repo.secrets.common.ipv4}:51820"; - allowedIPs = [ "192.168.3.0/24" ]; + allowedIPs = [ + "192.168.3.0/24" + "192.168.1.0/24" + ]; } ]; }; @@ -1519,10 +1531,22 @@ This machine mainly acts as an external sync helper. It manages the following th system.stateVersion = "23.11"; - node.secretsDir = ./secrets; services = { nginx = { virtualHosts = { + # "newway.swarsel.win" = { + # enableACME = true; + # forceSSL = true; + # acmeRoot = null; + # locations = { + # "/" = { + # proxyPass = "http://192.168.1.2:8080"; + # extraConfig = '' + # client_max_body_size 0; + # ''; + # }; + # }; + # }; "syncthing.swarsel.win" = { enableACME = true; forceSSL = true; @@ -2117,8 +2141,31 @@ Also, an initial bash history is provided to allow for a very quick local deploy } ]; - home-manager.users."${primaryUser}" = { - home = { + options.node = { + name = lib.mkOption { + description = "Node Name."; + type = lib.types.str; + }; + secretsDir = lib.mkOption { + description = "Path to the secrets directory for this node."; + type = lib.types.path; + default = ./.; + }; + }; + config = { + node.name = "drugstore"; + home-manager.users."${primaryUser}" = { + home = { + stateVersion = "23.05"; + file = { + ".bash_history" = { + source = self + /programs/bash/.bash_history; + }; + }; + }; + swarselsystems.modules.general = lib.mkForce true; + }; + home-manager.users.root.home = { stateVersion = "23.05"; file = { ".bash_history" = { @@ -2126,89 +2173,79 @@ Also, an initial bash history is provided to allow for a very quick local deploy }; }; }; - swarselsystems.modules.general = lib.mkForce true; - }; - home-manager.users.root.home = { - stateVersion = "23.05"; - file = { - ".bash_history" = { - source = self + /programs/bash/.bash_history; - }; + + # environment.etc."issue".text = "\x1B[32m~SwarselSystems~\x1B[0m\nIP of primary interface: \x1B[31m\\4\x1B[0m\nThe Password for all users & root is '\x1B[31msetup\x1B[0m'.\nInstall the system remotely by running '\x1B[33mbootstrap -n -d [--impermanence] [--encryption]\x1B[0m' on a machine with deployed secrets.\nAlternatively, run '\x1B[33mswarsel-install -d -f \x1B[0m' for a local install.\n"; + environment.etc."issue".source = "${self}/programs/etc/issue"; + networking.dhcpcd.runHook = "${pkgs.utillinux}/bin/agetty --reload"; + + isoImage = { + makeEfiBootable = true; + makeUsbBootable = true; + squashfsCompression = "zstd -Xcompression-level 3"; }; - }; - # environment.etc."issue".text = "\x1B[32m~SwarselSystems~\x1B[0m\nIP of primary interface: \x1B[31m\\4\x1B[0m\nThe Password for all users & root is '\x1B[31msetup\x1B[0m'.\nInstall the system remotely by running '\x1B[33mbootstrap -n -d [--impermanence] [--encryption]\x1B[0m' on a machine with deployed secrets.\nAlternatively, run '\x1B[33mswarsel-install -d -f \x1B[0m' for a local install.\n"; - environment.etc."issue".source = "${self}/programs/etc/issue"; - networking.dhcpcd.runHook = "${pkgs.utillinux}/bin/agetty --reload"; + nixpkgs = { + hostPlatform = lib.mkDefault "x86_64-linux"; + config.allowUnfree = true; + }; - isoImage = { - makeEfiBootable = true; - makeUsbBootable = true; - squashfsCompression = "zstd -Xcompression-level 3"; - }; + services.getty.autologinUser = lib.mkForce primaryUser; - nixpkgs = { - hostPlatform = lib.mkDefault "x86_64-linux"; - config.allowUnfree = true; - }; - - services.getty.autologinUser = lib.mkForce primaryUser; - - users = { - allowNoPasswordLogin = true; - groups.swarsel = { }; users = { - swarsel = { - name = primaryUser; - group = primaryUser; - isNormalUser = true; - password = "setup"; # this is overwritten after install - openssh.authorizedKeys.keys = lib.lists.forEach pubKeys (key: builtins.readFile key); - extraGroups = [ "wheel" ]; - }; - root = { - # password = lib.mkForce config.users.users.swarsel.password; # this is overwritten after install - openssh.authorizedKeys.keys = config.users.users."${primaryUser}".openssh.authorizedKeys.keys; + allowNoPasswordLogin = true; + groups.swarsel = { }; + users = { + swarsel = { + name = primaryUser; + group = primaryUser; + isNormalUser = true; + password = "setup"; # this is overwritten after install + openssh.authorizedKeys.keys = lib.lists.forEach pubKeys (key: builtins.readFile key); + extraGroups = [ "wheel" ]; + }; + root = { + # password = lib.mkForce config.users.users.swarsel.password; # this is overwritten after install + openssh.authorizedKeys.keys = config.users.users."${primaryUser}".openssh.authorizedKeys.keys; + }; }; }; - }; - boot = { - loader.systemd-boot.enable = lib.mkForce true; - loader.efi.canTouchEfiVariables = true; - }; + boot = { + loader.systemd-boot.enable = lib.mkForce true; + loader.efi.canTouchEfiVariables = true; + }; - programs.bash.shellAliases = { - "swarsel-install" = "nix run github:Swarsel/.dotfiles#swarsel-install --"; - }; + programs.bash.shellAliases = { + "swarsel-install" = "nix run github:Swarsel/.dotfiles#swarsel-install --"; + }; - system.activationScripts.cache = { - text = '' - mkdir -p -m=0777 /home/${primaryUser}/.local/state/nix/profiles - mkdir -p -m=0777 /home/${primaryUser}/.local/state/home-manager/gcroots - mkdir -p -m=0777 /home/${primaryUser}/.local/share/nix/ - printf '{\"extra-substituters\":{\"https://nix-community.cachix.org\":true,\"https://nix-community.cachix.org https://cache.ngi0.nixos.org/\":true},\"extra-trusted-public-keys\":{\"nix-community.cachix.org-1:mB9FSh9qf2dCimDSUo8Zy7bkq5CX+/rkCWyvRCYg3Fs=\":true,\"nix-community.cachix.org-1:mB9FSh9qf2dCimDSUo8Zy7bkq5CX+/rkCWyvRCYg3Fs= cache.ngi0.nixos.org-1:KqH5CBLNSyX184S9BKZJo1LxrxJ9ltnY2uAs5c/f1MA=\":true}}' | tee /home/${primaryUser}/.local/share/nix/trusted-settings.json > /dev/null - mkdir -p /root/.local/share/nix/ - printf '{\"extra-substituters\":{\"https://nix-community.cachix.org\":true,\"https://nix-community.cachix.org https://cache.ngi0.nixos.org/\":true},\"extra-trusted-public-keys\":{\"nix-community.cachix.org-1:mB9FSh9qf2dCimDSUo8Zy7bkq5CX+/rkCWyvRCYg3Fs=\":true,\"nix-community.cachix.org-1:mB9FSh9qf2dCimDSUo8Zy7bkq5CX+/rkCWyvRCYg3Fs= cache.ngi0.nixos.org-1:KqH5CBLNSyX184S9BKZJo1LxrxJ9ltnY2uAs5c/f1MA=\":true}}' | tee /root/.local/share/nix/trusted-settings.json > /dev/null - ''; - }; - systemd = { - services.sshd.wantedBy = lib.mkForce [ "multi-user.target" ]; - targets = { - sleep.enable = false; - suspend.enable = false; - hibernate.enable = false; - hybrid-sleep.enable = false; + system.activationScripts.cache = { + text = '' + mkdir -p -m=0777 /home/${primaryUser}/.local/state/nix/profiles + mkdir -p -m=0777 /home/${primaryUser}/.local/state/home-manager/gcroots + mkdir -p -m=0777 /home/${primaryUser}/.local/share/nix/ + printf '{\"extra-substituters\":{\"https://nix-community.cachix.org\":true,\"https://nix-community.cachix.org https://cache.ngi0.nixos.org/\":true},\"extra-trusted-public-keys\":{\"nix-community.cachix.org-1:mB9FSh9qf2dCimDSUo8Zy7bkq5CX+/rkCWyvRCYg3Fs=\":true,\"nix-community.cachix.org-1:mB9FSh9qf2dCimDSUo8Zy7bkq5CX+/rkCWyvRCYg3Fs= cache.ngi0.nixos.org-1:KqH5CBLNSyX184S9BKZJo1LxrxJ9ltnY2uAs5c/f1MA=\":true}}' | tee /home/${primaryUser}/.local/share/nix/trusted-settings.json > /dev/null + mkdir -p /root/.local/share/nix/ + printf '{\"extra-substituters\":{\"https://nix-community.cachix.org\":true,\"https://nix-community.cachix.org https://cache.ngi0.nixos.org/\":true},\"extra-trusted-public-keys\":{\"nix-community.cachix.org-1:mB9FSh9qf2dCimDSUo8Zy7bkq5CX+/rkCWyvRCYg3Fs=\":true,\"nix-community.cachix.org-1:mB9FSh9qf2dCimDSUo8Zy7bkq5CX+/rkCWyvRCYg3Fs= cache.ngi0.nixos.org-1:KqH5CBLNSyX184S9BKZJo1LxrxJ9ltnY2uAs5c/f1MA=\":true}}' | tee /root/.local/share/nix/trusted-settings.json > /dev/null + ''; + }; + systemd = { + services.sshd.wantedBy = lib.mkForce [ "multi-user.target" ]; + targets = { + sleep.enable = false; + suspend.enable = false; + hibernate.enable = false; + hybrid-sleep.enable = false; + }; + }; + + system.stateVersion = lib.mkForce "23.05"; + + networking = { + hostName = "drugstore"; + wireless.enable = false; }; }; - - system.stateVersion = lib.mkForce "23.05"; - - networking = { - hostName = "drugstore"; - wireless.enable = false; - }; - } @@ -4722,6 +4759,7 @@ Modules that need to be loaded on the NixOS level. Note that these will not be a sops = lib.mkDefault true; nginx = lib.mkDefault true; ssh = lib.mkDefault true; + oauth2Proxy = lib.mkDefault true; }; }; }; @@ -5018,6 +5056,10 @@ TODO systemFunc { specialArgs = { inherit inputs outputs lib self; }; modules = [ + { + node.name = host; + node.secretsDir = ../hosts/${type}/${host}/secrets; + } # put inports here that are for all hosts inputs.disko.nixosModules.disko inputs.sops-nix.nixosModules.sops @@ -5215,7 +5257,6 @@ in # Decrypt only if necessary if [[ ! -e $out ]]; then - echo "authenticate:" agekey=$(sudo ssh-to-age -private-key -i /etc/ssh/sops || sudo ssh-to-age -private-key -i /etc/ssh/ssh_host_ed25519_key) SOPS_AGE_KEY="$agekey" sops decrypt --output "$out" "$file" fi @@ -5431,6 +5472,89 @@ A breakdown of the flags being set: } #+end_src +**** Share configuration between nodes + +#+begin_src nix :tangle modules/nixos/common/nodes.nix + { config, lib, outputs, ... }: + let + inherit (lib) + attrNames + concatMap + concatStringsSep + foldl' + getAttrFromPath + mkMerge + mkOption + mkOptionType + optionals + recursiveUpdate + setAttrByPath + types + ; + + nodeName = config.node.name; + mkForwardedOption = + path: + mkOption { + type = mkOptionType { + name = "Same type that the receiving option `${concatStringsSep "." path}` normally accepts."; + merge = + _loc: defs: + builtins.filter (x: builtins.isAttrs x -> ((x._type or "") != "__distributed_config_empty")) ( + map (x: x.value) defs + ); + }; + default = { + _type = "__distributed_config_empty"; + }; + description = '' + Anything specified here will be forwarded to `${concatStringsSep "." path}` + on the given node. Forwarding happens as-is to the raw values, + so validity can only be checked on the receiving node. + ''; + }; + + forwardedOptions = [ + [ + "services" + "nginx" + "upstreams" + ] + [ + "services" + "nginx" + "virtualHosts" + ] + ]; + + attrsForEachOption = + f: foldl' (acc: path: recursiveUpdate acc (setAttrByPath path (f path))) { } forwardedOptions; + in + { + options.nodes = mkOption { + description = "Options forwarded to the given node."; + default = { }; + type = types.attrsOf ( + types.submodule { + options = attrsForEachOption mkForwardedOption; + } + ); + }; + + config = + let + getConfig = + path: otherNode: + let + cfg = outputs.nixosConfigurations.${otherNode}.config.nodes.${nodeName} or null; + in + optionals (cfg != null) (getAttrFromPath path cfg); + mergeConfigFromOthers = path: mkMerge (concatMap (getConfig path) (attrNames outputs.nixosConfigurations)); + in + attrsForEachOption mergeConfigFromOthers; + } +#+end_src + **** System Packages :PROPERTIES: :CUSTOM_ID: h:0e7e8bea-ec58-499c-9731-09dddfc39532 @@ -5606,11 +5730,14 @@ In case of using a fully setup system, this makes also sure that no further user For that reason, make sure that =sops-nix= is properly working before setting the =initialSetup= flag, otherwise you might lose user access. #+begin_src nix :tangle modules/nixos/common/users.nix - { pkgs, config, lib, ... }: + { self, pkgs, config, lib, ... }: + let + sopsFile = self + /secrets/general/secrets.yaml; + in { options.swarselsystems.modules.users = lib.mkEnableOption "user config"; config = lib.mkIf config.swarselsystems.modules.users { - sops.secrets.swarseluser = lib.mkIf (!config.swarselsystems.isPublic) { neededForUsers = true; }; + sops.secrets.swarseluser = lib.mkIf (!config.swarselsystems.isPublic) { inherit sopsFile; neededForUsers = true; }; users = { mutableUsers = lib.mkIf (!config.swarselsystems.initialSetup) false; @@ -6122,6 +6249,10 @@ Setup timezone and locale. I want to use the US layout, but have the rest adapte type = lib.types.path; default = ./.; }; + options.node.name = lib.mkOption { + description = "Node Name."; + type = lib.types.str; + }; } #+end_src @@ -6373,7 +6504,7 @@ Here I disable global completion to prevent redundant compinit calls and cache i id = "O7RWDMD-AEAHPP7-7TAVLKZ-BSWNBTU-2VA44MS-EYGUNBB-SLHKB3C-ZSLMOAA"; }; "moonside (@oracle)" = { - id = "YJLYL4Z-JIYHFKX-554ZR7B-YAF3PNH-CX7JF53-NYUMVGL-4EWWASH-GDAMBQA"; + id = "VPCDZB6-MGVGQZD-Q6DIZW3-IZJRJTO-TCC3QUQ-2BNTL7P-AKE7FBO-N55UNQE"; }; }; folders = { @@ -7483,38 +7614,50 @@ Here I am forcing =startWhenNeeded= to false so that the value will not be set t #+begin_src nix :tangle modules/nixos/server/kavita.nix { pkgs, lib, config, ... }: + let + serviceName = "kavita"; + serviceUser = "kavita"; + serviceDomain = "scroll.swarsel.win"; + servicePort = 8080; + in { - options.swarselsystems.modules.server.kavita = lib.mkEnableOption "enable kavita on server"; - config = lib.mkIf config.swarselsystems.modules.server.kavita { + options.swarselsystems.modules.server."${serviceName}" = lib.mkEnableOption "enable ${serviceName} on server"; + config = lib.mkIf config.swarselsystems.modules.server."${serviceName}" { environment.systemPackages = with pkgs; [ calibre ]; - - users.users.kavita = { + users.users."${serviceUser}" = { extraGroups = [ "users" ]; }; - sops.secrets.kavita = { owner = "kavita"; }; + sops.secrets.kavita = { owner = serviceUser; }; networking.firewall.allowedTCPPorts = [ 8080 ]; services.kavita = { enable = true; - user = "kavita"; - settings.Port = 8080; + user = serviceUser; + settings.Port = servicePort; tokenKeyFile = config.sops.secrets.kavita.path; }; - services.nginx = { + nodes.moonside.services.nginx = { + upstreams = { + "${serviceName}" = { + servers = { + "192.168.1.2:${builtins.toString servicePort}" = { }; + }; + }; + }; virtualHosts = { - "scroll.swarsel.win" = { + "${serviceDomain}" = { enableACME = true; forceSSL = true; acmeRoot = null; locations = { "/" = { - proxyPass = "http://localhost:8080"; + proxyPass = "http://${serviceName}"; extraConfig = '' client_max_body_size 0; ''; @@ -7533,51 +7676,64 @@ Here I am forcing =startWhenNeeded= to false so that the value will not be set t :END: #+begin_src nix :tangle modules/nixos/server/jellyfin.nix - { pkgs, lib, config, ... }: - { - options.swarselsystems.modules.server.jellyfin = lib.mkEnableOption "enable jellyfin on server"; - config = lib.mkIf config.swarselsystems.modules.server.jellyfin { - users.users.jellyfin = { - extraGroups = [ "video" "render" "users" ]; - }; - nixpkgs.config.packageOverrides = pkgs: { - vaapiIntel = pkgs.vaapiIntel.override { enableHybridCodec = true; }; - }; - hardware.graphics = { - enable = true; - extraPackages = with pkgs; [ - intel-media-driver # LIBVA_DRIVER_NAME=iHD - vaapiIntel # LIBVA_DRIVER_NAME=i965 (older but works better for Firefox/Chromium) - vaapiVdpau - libvdpau-va-gl - ]; - }; - services.jellyfin = { - enable = true; - user = "jellyfin"; - openFirewall = true; # this works only for the default ports - }; +{ pkgs, lib, config, ... }: +let + serviceDomain = "screen.swarsel.win"; + servicePort = 8096; + serviceName = "jellyfin"; + serviceUser = "jellyfin"; +in +{ + options.swarselsystems.modules.server."${serviceName}" = lib.mkEnableOption "enable ${serviceName} on server"; + config = lib.mkIf config.swarselsystems.modules.server."${serviceName}" { + users.users."${serviceUser}" = { + extraGroups = [ "video" "render" "users" ]; + }; + nixpkgs.config.packageOverrides = pkgs: { + vaapiIntel = pkgs.vaapiIntel.override { enableHybridCodec = true; }; + }; + hardware.graphics = { + enable = true; + extraPackages = with pkgs; [ + intel-media-driver # LIBVA_DRIVER_NAME=iHD + vaapiIntel # LIBVA_DRIVER_NAME=i965 (older but works better for Firefox/Chromium) + vaapiVdpau + libvdpau-va-gl + ]; + }; + services.jellyfin = { + enable = true; + user = serviceUser; + openFirewall = true; # this works only for the default ports + }; - services.nginx = { - virtualHosts = { - "screen.swarsel.win" = { - enableACME = true; - forceSSL = true; - acmeRoot = null; - locations = { - "/" = { - proxyPass = "http://localhost:8096"; - extraConfig = '' - client_max_body_size 0; - ''; - }; + nodes.moonside.services.nginx = { + upstreams = { + "${serviceName}" = { + servers = { + "192.168.1.2:${builtins.toString servicePort}" = { }; + }; + }; + }; + virtualHosts = { + "${serviceDomain}" = { + enableACME = true; + forceSSL = true; + acmeRoot = null; + locations = { + "/" = { + proxyPass = "http://${serviceName}"; + extraConfig = '' + client_max_body_size 0; + ''; }; }; }; }; }; + }; - } +} #+end_src **** navidrome @@ -7587,9 +7743,16 @@ Here I am forcing =startWhenNeeded= to false so that the value will not be set t #+begin_src nix :tangle modules/nixos/server/navidrome.nix { pkgs, config, lib, ... }: + let + serviceDomain = "sound.swarsel.win"; + servicePort = 4040; + serviceName = "navidrome"; + serviceUser = "navidrome"; + serviceGroup = serviceUser; + in { - options.swarselsystems.modules.server.navidrome = lib.mkEnableOption "enable navidrome on server"; - config = lib.mkIf config.swarselsystems.modules.server.navidrome { + options.swarselsystems.modules.server."${serviceName}" = lib.mkEnableOption "enable ${serviceName} on server"; + config = lib.mkIf config.swarselsystems.modules.server."${serviceName}" { environment.systemPackages = with pkgs; [ pciutils alsa-utils @@ -7598,16 +7761,16 @@ Here I am forcing =startWhenNeeded= to false so that the value will not be set t users = { groups = { - navidrome = { + "$(serviceGroup}" = { gid = 61593; }; }; users = { - navidrome = { + "${serviceUser}" = { isSystemUser = true; uid = 61593; - group = "navidrome"; + group = serviceGroup; extraGroups = [ "audio" "utmp" "users" "pipewire" ]; }; }; @@ -7625,8 +7788,8 @@ Here I am forcing =startWhenNeeded= to false so that the value will not be set t openFirewall = true; settings = { LogLevel = "debug"; - Address = "127.0.0.1"; - Port = 4040; + Address = "0.0.0.0"; + Port = servicePort; MusicFolder = "/Vault/Eternor/Music"; PlaylistsPath = "./Playlists"; EnableSharing = true; @@ -7658,15 +7821,22 @@ Here I am forcing =startWhenNeeded= to false so that the value will not be set t }; }; - services.nginx = { + nodes.moonside.services.nginx = { + upstreams = { + "${serviceName}" = { + servers = { + "192.168.1.2:${builtins.toString servicePort}" = { }; + }; + }; + }; virtualHosts = { - "sound.swarsel.win" = { + "${serviceDomain}" = { enableACME = true; forceSSL = true; acmeRoot = null; locations = { "/" = { - proxyPass = "http://localhost:4040"; + proxyPass = "http://navidrome"; proxyWebsockets = true; extraConfig = '' auth_request /oauth2/auth; @@ -7713,7 +7883,7 @@ Here I am forcing =startWhenNeeded= to false so that the value will not be set t ''; }; "/share" = { - proxyPass = "http://localhost:4040"; + proxyPass = "http://navidrome"; proxyWebsockets = true; extraConfig = '' proxy_redirect http:// https://; @@ -7727,7 +7897,7 @@ Here I am forcing =startWhenNeeded= to false so that the value will not be set t ''; }; "/rest" = { - proxyPass = "http://localhost:4040"; + proxyPass = "http://navidrome"; proxyWebsockets = true; extraConfig = '' proxy_redirect http:// https://; @@ -7890,6 +8060,13 @@ Here I am forcing =startWhenNeeded= to false so that the value will not be set t { config, lib, pkgs, sops, ... }: let matrixDomain = "swatrix.swarsel.win"; + serviceName = "matrix"; + synapsePort = 8008; + synapseUser = "matrix-synapse"; + whatsappPort = 29318; + telegramPort = 29317; + signalPort = 29328; + baseUrl = "https://${matrixDomain}"; clientConfig."m.homeserver".base_url = baseUrl; serverConfig."m.server" = "${matrixDomain}:443"; @@ -7900,8 +8077,8 @@ Here I am forcing =startWhenNeeded= to false so that the value will not be set t ''; in { - options.swarselsystems.modules.server.matrix = lib.mkEnableOption "enable matrix on server"; - config = lib.mkIf config.swarselsystems.modules.server.matrix { + options.swarselsystems.modules.server."${serviceName}" = lib.mkEnableOption "enable ${serviceName} on server"; + config = lib.mkIf config.swarselsystems.modules.server."${serviceName}" { environment.systemPackages = with pkgs; [ matrix-synapse lottieconverter @@ -7910,24 +8087,24 @@ Here I am forcing =startWhenNeeded= to false so that the value will not be set t sops = { secrets = { - matrixsharedsecret = { owner = "matrix-synapse"; }; - mautrixtelegram_as = { owner = "matrix-synapse"; }; - mautrixtelegram_hs = { owner = "matrix-synapse"; }; - mautrixtelegram_api_id = { owner = "matrix-synapse"; }; - mautrixtelegram_api_hash = { owner = "matrix-synapse"; }; + matrixsharedsecret = { owner = synapseUser; }; + mautrixtelegram_as = { owner = synapseUser; }; + mautrixtelegram_hs = { owner = synapseUser; }; + mautrixtelegram_api_id = { owner = synapseUser; }; + mautrixtelegram_api_hash = { owner = synapseUser; }; }; templates = { "matrix_user_register.sh".content = '' - register_new_matrix_user -k ${config.sops.placeholder.matrixsharedsecret} http://localhost:8008 + register_new_matrix_user -k ${config.sops.placeholder.matrixsharedsecret} http://localhost:${builtins.toString synapsePort} ''; matrixshared = { - owner = "matrix-synapse"; + owner = synapseUser; content = '' registration_shared_secret: ${config.sops.placeholder.matrixsharedsecret} ''; }; mautrixtelegram = { - owner = "matrix-synapse"; + owner = synapseUser; content = '' MAUTRIX_TELEGRAM_APPSERVICE_AS_TOKEN=${config.sops.placeholder.mautrixtelegram_as} MAUTRIX_TELEGRAM_APPSERVICE_HS_TOKEN=${config.sops.placeholder.mautrixtelegram_hs} @@ -7938,6 +8115,8 @@ Here I am forcing =startWhenNeeded= to false so that the value will not be set t }; }; + networking.firewall.allowedTCPPorts = [ 8008 8448 ]; + systemd = { timers."restart-bridges" = { wantedBy = [ "timers.target" ]; @@ -8007,9 +8186,9 @@ Here I am forcing =startWhenNeeded= to false so that the value will not be set t public_baseurl = "https://${matrixDomain}"; listeners = [ { - port = 8008; + port = synapsePort; bind_addresses = [ - "127.0.0.1" + "0.0.0.0" # "::1" ]; type = "http"; @@ -8035,13 +8214,13 @@ Here I am forcing =startWhenNeeded= to false so that the value will not be set t registerToSynapse = false; settings = { homeserver = { - address = "http://localhost:8008"; + address = "http://localhost:${builtins.toString synapsePort}"; domain = matrixDomain; }; appservice = { - address = "http://localhost:29317"; - hostname = "localhost"; - port = "29317"; + address = "http://localhost:${builtins.toString telegramPort}"; + hostname = "0.0.0.0"; + port = telegramPort; provisioning.enabled = true; id = "telegram"; # ephemeral_events = true; # not needed due to double puppeting @@ -8081,13 +8260,13 @@ Here I am forcing =startWhenNeeded= to false so that the value will not be set t registerToSynapse = false; settings = { homeserver = { - address = "http://localhost:8008"; + address = "http://localhost:${builtins.toString synapsePort}"; domain = matrixDomain; }; appservice = { - address = "http://localhost:29318"; - hostname = "127.0.0.1"; - port = 29318; + address = "http://localhost:${builtins.toString whatsappPort}"; + hostname = "0.0.0.0"; + port = whatsappPort; database = { type = "postgres"; uri = "postgresql:///mautrix-whatsapp?host=/run/postgresql"; @@ -8128,14 +8307,13 @@ Here I am forcing =startWhenNeeded= to false so that the value will not be set t registerToSynapse = false; settings = { homeserver = { - address = "http://localhost:8008"; + address = "http://localhost:${builtins.toString synapsePort}"; domain = matrixDomain; }; appservice = { - - address = "http://localhost:29328"; - hostname = "127.0.0.1"; - port = 29328; + address = "http://localhost:${builtins.toString signalPort}"; + hostname = "0.0.0.0"; + port = signalPort; database = { type = "postgres"; uri = "postgresql:///mautrix-signal?host=/run/postgresql"; @@ -8154,65 +8332,68 @@ Here I am forcing =startWhenNeeded= to false so that the value will not be set t }; }; }; + }; - # restart the bridges daily. this is done for the signal bridge mainly which stops carrying - # messages out after a while. + # restart the bridges daily. this is done for the signal bridge mainly which stops carrying + # messages out after a while. - nginx = { - virtualHosts = { - "swatrix.swarsel.win" = { - enableACME = true; - forceSSL = true; - acmeRoot = null; - listen = [ - { - addr = "0.0.0.0"; - port = 8448; - ssl = true; - extraParameters = [ - "default_server" - ]; - } - { - addr = "[::0]"; - port = 8448; - ssl = true; - extraParameters = [ - "default_server" - ]; - } - { - addr = "0.0.0.0"; - port = 443; - ssl = true; - } - { - addr = "[::0]"; - port = 443; - ssl = true; - } - ]; - locations = { - "~ ^(/_matrix|/_synapse/client)" = { - # proxyPass = "http://localhost:8008"; - proxyPass = "http://localhost:8008"; - extraConfig = '' - client_max_body_size 0; - ''; - }; - "= /.well-known/matrix/server".extraConfig = mkWellKnown serverConfig; - "= /.well-known/matrix/client".extraConfig = mkWellKnown clientConfig; + nodes.moonside.services.nginx = { + upstreams = { + "${serviceName}" = { + servers = { + "192.168.1.2:${builtins.toString synapsePort}" = { }; + }; + }; + }; + virtualHosts = { + "${matrixDomain}" = { + enableACME = true; + forceSSL = true; + acmeRoot = null; + listen = [ + { + addr = "0.0.0.0"; + port = 8448; + ssl = true; + extraParameters = [ + "default_server" + ]; + } + { + addr = "[::0]"; + port = 8448; + ssl = true; + extraParameters = [ + "default_server" + ]; + } + { + addr = "0.0.0.0"; + port = 443; + ssl = true; + } + { + addr = "[::0]"; + port = 443; + ssl = true; + } + ]; + locations = { + "~ ^(/_matrix|/_synapse/client)" = { + proxyPass = "http://${serviceName}"; + extraConfig = '' + client_max_body_size 0; + ''; }; + "= /.well-known/matrix/server".extraConfig = mkWellKnown serverConfig; + "= /.well-known/matrix/client".extraConfig = mkWellKnown clientConfig; }; }; }; }; }; - - } - #+end_src **** nextcloud @@ -8223,21 +8404,24 @@ Here I am forcing =startWhenNeeded= to false so that the value will not be set t #+begin_src nix :tangle modules/nixos/server/nextcloud.nix { pkgs, lib, config, ... }: let - nextcloudDomain = "stash.swarsel.win"; + serviceDomain = "stash.swarsel.win"; + serviceUser = "nextcloud"; + serviceGroup = serviceUser; + serviceName = "nextcloud"; in { - options.swarselsystems.modules.server.nextcloud = lib.mkEnableOption "enable nextcloud on server"; - config = lib.mkIf config.swarselsystems.modules.server.nextcloud { + options.swarselsystems.modules.server."${serviceName}" = lib.mkEnableOption "enable ${serviceName} on server"; + config = lib.mkIf config.swarselsystems.modules.server."${serviceName}" { sops.secrets = { nextcloudadminpass = { - owner = "nextcloud"; - group = "nextcloud"; + owner = serviceUser; + group = serviceGroup; mode = "0440"; }; kanidm-nextcloud-client = { - owner = "nextcloud"; - group = "nextcloud"; + owner = serviceUser; + group = serviceGroup; mode = "0440"; }; }; @@ -8245,8 +8429,12 @@ Here I am forcing =startWhenNeeded= to false so that the value will not be set t services = { nextcloud = { enable = true; + settings = { + trusted_proxies = [ "0.0.0.0" ]; + overwriteprotocol = "https"; + }; package = pkgs.nextcloud31; - hostName = nextcloudDomain; + hostName = serviceDomain; home = "/Vault/apps/nextcloud"; datadir = "/Vault/data/nextcloud"; https = true; @@ -8262,21 +8450,30 @@ Here I am forcing =startWhenNeeded= to false so that the value will not be set t dbtype = "sqlite"; }; }; + }; - nginx = { - virtualHosts = { - "${nextcloudDomain}" = { - enableACME = true; - forceSSL = true; - acmeRoot = null; - # config is automatically added by nixos nextcloud config. - # hence, only provide certificate + nodes.moonside.services.nginx = { + upstreams = { + "${serviceName}" = { + servers = { + "192.168.1.2:80" = { }; + }; + }; + }; + virtualHosts = { + "${serviceDomain}" = { + enableACME = true; + forceSSL = true; + acmeRoot = null; + locations = { + "/" = { + proxyPass = "http://${serviceName}"; + }; }; }; }; }; }; - } #+end_src @@ -8287,19 +8484,24 @@ Here I am forcing =startWhenNeeded= to false so that the value will not be set t #+begin_src nix :tangle modules/nixos/server/immich.nix { lib, config, ... }: + let + serviceDomain = "shots.swarsel.win"; + servicePort = 3001; + serviceUser = "immich"; + serviceName = "immich"; + in { - options.swarselsystems.modules.server.immich = lib.mkEnableOption "enable immich on server"; - config = lib.mkIf config.swarselsystems.modules.server.immich { + options.swarselsystems.modules.server."${serviceName}" = lib.mkEnableOption "enable ${serviceName} on server"; + config = lib.mkIf config.swarselsystems.modules.server."${serviceName}" { - users.users.immich = { + users.users."${serviceUser}" = { extraGroups = [ "video" "render" "users" ]; }; - # sops.secrets.nextcloudadminpass = { owner = "nextcloud"; }; - services.immich = { enable = true; - port = 3001; + host = "0.0.0.0"; + port = servicePort; openFirewall = true; mediaLocation = "/Vault/Eternor/Immich"; environment = { @@ -8307,16 +8509,24 @@ Here I am forcing =startWhenNeeded= to false so that the value will not be set t }; }; + networking.firewall.allowedTCPPorts = [ 3001 ]; - services.nginx = { + nodes.moonside.services.nginx = { + upstreams = { + "${serviceName}" = { + servers = { + "192.168.1.2:${builtins.toString servicePort}" = { }; + }; + }; + }; virtualHosts = { - "shots.swarsel.win" = { + "${serviceDomain}" = { enableACME = true; forceSSL = true; acmeRoot = null; locations = { "/" = { - proxyPass = "http://localhost:3001"; + proxyPass = "http://${serviceName}"; extraConfig = '' client_max_body_size 0; @@ -8351,32 +8561,41 @@ Also I install Tika and Gotenberg, which are needed to create PDFs out of =.eml= #+begin_src nix :tangle modules/nixos/server/paperless.nix { lib, pkgs, config, ... }: + let + serviceDomain = "scan.swarsel.win"; + servicePort = 28981; + serviceUser = "paperless"; + serviceGroup = serviceUser; + serviceName = "paperless"; + in { - options.swarselsystems.modules.server.paperless = lib.mkEnableOption "enable paperless on server"; - config = lib.mkIf config.swarselsystems.modules.server.paperless { + options.swarselsystems.modules.server."${serviceName}" = lib.mkEnableOption "enable ${serviceName} on server"; + config = lib.mkIf config.swarselsystems.modules.server."${serviceName}" { - users.users.paperless = { + users.users."${serviceUser}" = { extraGroups = [ "users" ]; }; sops.secrets = { - paperless_admin = { owner = "paperless"; }; + paperless_admin = { owner = serviceUser; }; kanidm-paperless-client = { - owner = "paperless"; - group = "paperless"; + owner = serviceUser; + group = serviceGroup; mode = "0440"; }; }; + networking.firewall.allowedTCPPorts = [ servicePort ]; + services = { paperless = { enable = true; mediaDir = "/Vault/Eternor/Paperless"; dataDir = "/Vault/data/paperless"; - user = "paperless"; - port = 28981; + user = serviceUser; + port = servicePort; passwordFile = config.sops.secrets.paperless_admin.path; - address = "127.0.0.1"; + address = "0.0.0.0"; settings = { PAPERLESS_OCR_LANGUAGE = "deu+eng"; PAPERLESS_URL = "https://scan.swarsel.win"; @@ -8436,15 +8655,22 @@ Also I install Tika and Gotenberg, which are needed to create PDFs out of =.eml= ) ''; - services.nginx = { + nodes.moonside.services.nginx = { + upstreams = { + "${serviceName}" = { + servers = { + "192.168.1.2:${builtins.toString servicePort}" = { }; + }; + }; + }; virtualHosts = { - "scan.swarsel.win" = { + "${serviceDomain}" = { enableACME = true; forceSSL = true; acmeRoot = null; locations = { "/" = { - proxyPass = "http://localhost:28981"; + proxyPass = "http://${serviceName}"; extraConfig = '' client_max_body_size 0; proxy_connect_timeout 300; @@ -8613,26 +8839,34 @@ Also I install Tika and Gotenberg, which are needed to create PDFs out of =.eml= { lib, config, ... }: let inherit (config.repo.secrets.common) workHostName; + serviceDomain = "storync.swarsel.win"; + servicePort = 8384; + serviceUser = "syncthing"; + serviceGroup = serviceUser; + serviceName = "syncthing"; in { - options.swarselsystems.modules.server.syncthing = lib.mkEnableOption "enable syncthing on server"; - config = lib.mkIf config.swarselsystems.modules.server.syncthing { + options.swarselsystems.modules.server."${serviceName}" = lib.mkEnableOption "enable ${serviceName} on server"; + config = lib.mkIf config.swarselsystems.modules.server."${serviceName}" { - users.users.syncthing = { + users.users."${serviceUser}" = { extraGroups = [ "users" ]; - group = "syncthing"; + group = serviceGroup; isSystemUser = true; }; - users.groups.syncthing = { }; + users.groups."${serviceGroup}" = { }; + + networking.firewall.allowedTCPPorts = [ servicePort ]; services.syncthing = { enable = true; - user = "swarsel"; + user = serviceUser; + group = serviceGroup; dataDir = "/Vault/data/syncthing"; configDir = "/Vault/apps/syncthing"; - guiAddress = "0.0.0.0:8384"; - openDefaultPorts = true; + guiAddress = "0.0.0.0:${builtins.toString servicePort}"; + openDefaultPorts = true; # opens ports TCP/UDP 22000 and UDP 21027 for discovery relay.enable = false; settings = { urAccepted = -1; @@ -8646,13 +8880,16 @@ Also I install Tika and Gotenberg, which are needed to create PDFs out of =.eml= "${workHostName}" = { id = "YAPV4BV-I26WPTN-SIP32MV-SQP5TBZ-3CHMTCI-Z3D6EP2-MNDQGLP-53FT3AB"; }; + "moonside (@oracle)" = { + id = "VPCDZB6-MGVGQZD-Q6DIZW3-IZJRJTO-TCC3QUQ-2BNTL7P-AKE7FBO-N55UNQE"; + }; }; folders = { "Default Folder" = lib.mkForce { path = "/Vault/data/syncthing/Sync"; type = "receiveonly"; versioning = null; - devices = [ "sync (@oracle)" "magicant" "${workHostName}" ]; + devices = [ "sync (@oracle)" "magicant" "${workHostName}" "moonside (@oracle)" ]; id = "default"; }; "Obsidian" = { @@ -8662,7 +8899,7 @@ Also I install Tika and Gotenberg, which are needed to create PDFs out of =.eml= type = "simple"; params.keep = "5"; }; - devices = [ "sync (@oracle)" "magicant" "${workHostName}" ]; + devices = [ "sync (@oracle)" "magicant" "${workHostName}" "moonside (@oracle)" ]; id = "yjvni-9eaa7"; }; "Org" = { @@ -8672,7 +8909,7 @@ Also I install Tika and Gotenberg, which are needed to create PDFs out of =.eml= type = "simple"; params.keep = "5"; }; - devices = [ "sync (@oracle)" "magicant" "${workHostName}" ]; + devices = [ "sync (@oracle)" "magicant" "${workHostName}" "moonside (@oracle)" ]; id = "a7xnl-zjj3d"; }; "Vpn" = { @@ -8682,7 +8919,7 @@ Also I install Tika and Gotenberg, which are needed to create PDFs out of =.eml= type = "simple"; params.keep = "5"; }; - devices = [ "sync (@oracle)" "magicant" "${workHostName}" ]; + devices = [ "sync (@oracle)" "magicant" "${workHostName}" "moonside (@oracle)" ]; id = "hgp9s-fyq3p"; }; "Documents" = { @@ -8692,27 +8929,29 @@ Also I install Tika and Gotenberg, which are needed to create PDFs out of =.eml= type = "simple"; params.keep = "5"; }; - devices = [ "magicant" "${workHostName}" ]; + devices = [ "magicant" "${workHostName}" "moonside (@oracle)" ]; id = "hgr3d-pfu3w"; }; - # ".elfeed" = { - # path = "/Vault/data/syncthing/.elfeed"; - # devices = [ "sync (@oracle)" "magicant" "${workHostName}" ]; - # id = "h7xbs-fs9v1"; - # }; }; }; }; - services.nginx = { + nodes.moonside.services.nginx = { + upstreams = { + "${serviceName}" = { + servers = { + "192.168.1.2:${builtins.toString servicePort}" = { }; + }; + }; + }; virtualHosts = { - "storync.swarsel.win" = { + "${serviceDomain}" = { enableACME = true; forceSSL = true; acmeRoot = null; locations = { "/" = { - proxyPass = "http://localhost:8384"; + proxyPass = "http://${serviceName}"; extraConfig = '' client_max_body_size 0; ''; @@ -8722,7 +8961,6 @@ Also I install Tika and Gotenberg, which are needed to create PDFs out of =.eml= }; }; }; - } #+end_src @@ -8801,24 +9039,24 @@ This section exposes several metrics that I use to check the health of my server #+begin_src nix :tangle modules/nixos/server/monitoring.nix { self, lib, config, ... }: let - grafanaDomain = "status.swarsel.win"; + serviceDomain = "status.swarsel.win"; + servicePort = 3000; + serviceUser = "grafana"; + serviceGroup = serviceUser; + moduleName = "monitoring"; + grafanaUpstream = "grafana"; + prometheusUpstream = "prometheus"; + prometheusPort = 9090; + prometheusWebRoot = "prometheus"; in { - options.swarselsystems.modules.server.monitoring = lib.mkEnableOption "enable monitoring on server"; - config = lib.mkIf config.swarselsystems.modules.server.monitoring { + options.swarselsystems.modules.server."${moduleName}" = lib.mkEnableOption "enable ${moduleName} on server"; + config = lib.mkIf config.swarselsystems.modules.server."${moduleName}" { sops.secrets = { - grafanaadminpass = { - owner = "grafana"; - }; - prometheusadminpass = { - owner = "grafana"; - }; - kanidm-grafana-client = { - owner = "grafana"; - group = "grafana"; - mode = "0440"; - }; + grafanaadminpass = { owner = serviceUser; group = serviceGroup; mode = "0440"; }; + prometheusadminpass = { owner = serviceUser; group = serviceGroup; mode = "0440"; }; + kanidm-grafana-client = { owner = serviceUser; group = serviceGroup; mode = "0440"; }; }; users = { @@ -8827,12 +9065,14 @@ This section exposes several metrics that I use to check the health of my server extraGroups = [ "nextcloud" ]; }; - grafana = { + "${serviceUser}" = { extraGroups = [ "users" ]; }; }; }; + networking.firewall.allowedTCPPorts = [ servicePort prometheusPort ]; + services = { grafana = { enable = true; @@ -8844,7 +9084,7 @@ This section exposes several metrics that I use to check the health of my server { name = "prometheus"; type = "prometheus"; - url = "https://${grafanaDomain}/prometheus"; + url = "https://${serviceDomain}/prometheus"; editable = false; access = "proxy"; basicAuth = true; @@ -8867,13 +9107,21 @@ This section exposes several metrics that I use to check the health of my server }; settings = { - security.admin_password = "$__file{/run/secrets/grafanaadminpass}"; + analytics.reporting_enabled = false; + users.allow_sign_up = false; + security = { + admin_password = "$__file{/run/secrets/grafanaadminpass}"; + cookie_secure = true; + disable_gravatar = true; + }; server = { - domain = grafanaDomain; - root_url = "https://${grafanaDomain}"; - http_port = 3000; + domain = serviceDomain; + root_url = "https://${serviceDomain}"; + http_port = servicePort; http_addr = "0.0.0.0"; protocol = "http"; + enforce_domain = true; + enable_gzip = true; }; "auth.generic_oauth" = { enabled = true; @@ -8899,9 +9147,9 @@ This section exposes several metrics that I use to check the health of my server prometheus = { enable = true; - webExternalUrl = "https://status.swarsel.win/prometheus"; - port = 9090; - listenAddress = "127.0.0.1"; + webExternalUrl = "https://status.swarsel.win/${prometheusWebRoot}"; + port = prometheusPort; + listenAddress = "0.0.0.0"; globalConfig = { scrape_interval = "10s"; }; @@ -8965,35 +9213,46 @@ This section exposes several metrics that I use to check the health of my server }; }; }; + }; - nginx = { - virtualHosts = { - "${grafanaDomain}" = { - enableACME = true; - forceSSL = true; - acmeRoot = null; - locations = { - "/" = { - proxyPass = "http://localhost:3000"; - proxyWebsockets = true; - extraConfig = '' - client_max_body_size 0; - ''; - }; - "/prometheus" = { - proxyPass = "http://localhost:9090"; - extraConfig = '' - client_max_body_size 0; - ''; - }; + nodes.moonside.services.nginx = { + upstreams = { + "${grafanaUpstream}" = { + servers = { + "192.168.1.2:${builtins.toString servicePort}" = { }; + }; + }; + "${prometheusUpstream}" = { + servers = { + "192.168.1.2:${builtins.toString prometheusPort}" = { }; + }; + }; + }; + virtualHosts = { + "${serviceDomain}" = { + enableACME = true; + forceSSL = true; + acmeRoot = null; + locations = { + "/" = { + proxyPass = "http://${grafanaUpstream}"; + proxyWebsockets = true; + extraConfig = '' + client_max_body_size 0; + ''; + }; + "/${prometheusWebRoot}" = { + proxyPass = "http://${prometheusUpstream}"; + extraConfig = '' + client_max_body_size 0; + ''; }; }; }; }; }; }; - } #+end_src @@ -9084,6 +9343,9 @@ FreshRSS claims to support HTTP header auth, but at least it does not work with #+begin_src nix :tangle modules/nixos/server/freshrss.nix { lib, config, ... }: + let + serviceName = "freshrss"; + in { options.swarselsystems.modules.server.freshrss = lib.mkEnableOption "enable freshrss on server"; config = lib.mkIf config.swarselsystems.modules.server.freshrss { @@ -9137,7 +9399,14 @@ FreshRSS claims to support HTTP header auth, but at least it does not work with # config.sops.templates.freshrss-env.path # ]; - services.nginx = { + nodes.moonside.services.nginx = { + upstreams = { + "${serviceName}" = { + servers = { + "192.168.1.2:80" = { }; + }; + }; + }; virtualHosts = { "signpost.swarsel.win" = { enableACME = true; @@ -9145,6 +9414,7 @@ FreshRSS claims to support HTTP header auth, but at least it does not work with acmeRoot = null; locations = { "/" = { + proxyPass = "http://${serviceName}"; extraConfig = '' auth_request /oauth2/auth; error_page 401 = /oauth2/sign_in; @@ -9394,7 +9664,7 @@ FreshRSS claims to support HTTP header auth, but at least it does not work with } #+end_src -**** IDM (kanidm + oauth2-proxy) +**** kanidm The forgejo configuration is a little broken and will show a 500 error when signing in through kanidm. However, when pressing back and refreshing the page, I am logged in. Currently I cannot be bothered to fix this. @@ -9407,62 +9677,52 @@ To get other URLs (token, etc.), use https:///oauth2/openid//oauth2/openid//oauth2/openid//oauth2/openid//oauth2/openid//oauth2/openid//oauth2/openid//oauth2/openid//oauth2/openid//oauth2/openid//oauth2/openid/ /dev/null - mkdir -p /root/.local/share/nix/ - printf '{\"extra-substituters\":{\"https://nix-community.cachix.org\":true,\"https://nix-community.cachix.org https://cache.ngi0.nixos.org/\":true},\"extra-trusted-public-keys\":{\"nix-community.cachix.org-1:mB9FSh9qf2dCimDSUo8Zy7bkq5CX+/rkCWyvRCYg3Fs=\":true,\"nix-community.cachix.org-1:mB9FSh9qf2dCimDSUo8Zy7bkq5CX+/rkCWyvRCYg3Fs= cache.ngi0.nixos.org-1:KqH5CBLNSyX184S9BKZJo1LxrxJ9ltnY2uAs5c/f1MA=\":true}}' | tee /root/.local/share/nix/trusted-settings.json > /dev/null - ''; - }; - systemd = { - services.sshd.wantedBy = lib.mkForce [ "multi-user.target" ]; - targets = { - sleep.enable = false; - suspend.enable = false; - hibernate.enable = false; - hybrid-sleep.enable = false; + system.activationScripts.cache = { + text = '' + mkdir -p -m=0777 /home/${primaryUser}/.local/state/nix/profiles + mkdir -p -m=0777 /home/${primaryUser}/.local/state/home-manager/gcroots + mkdir -p -m=0777 /home/${primaryUser}/.local/share/nix/ + printf '{\"extra-substituters\":{\"https://nix-community.cachix.org\":true,\"https://nix-community.cachix.org https://cache.ngi0.nixos.org/\":true},\"extra-trusted-public-keys\":{\"nix-community.cachix.org-1:mB9FSh9qf2dCimDSUo8Zy7bkq5CX+/rkCWyvRCYg3Fs=\":true,\"nix-community.cachix.org-1:mB9FSh9qf2dCimDSUo8Zy7bkq5CX+/rkCWyvRCYg3Fs= cache.ngi0.nixos.org-1:KqH5CBLNSyX184S9BKZJo1LxrxJ9ltnY2uAs5c/f1MA=\":true}}' | tee /home/${primaryUser}/.local/share/nix/trusted-settings.json > /dev/null + mkdir -p /root/.local/share/nix/ + printf '{\"extra-substituters\":{\"https://nix-community.cachix.org\":true,\"https://nix-community.cachix.org https://cache.ngi0.nixos.org/\":true},\"extra-trusted-public-keys\":{\"nix-community.cachix.org-1:mB9FSh9qf2dCimDSUo8Zy7bkq5CX+/rkCWyvRCYg3Fs=\":true,\"nix-community.cachix.org-1:mB9FSh9qf2dCimDSUo8Zy7bkq5CX+/rkCWyvRCYg3Fs= cache.ngi0.nixos.org-1:KqH5CBLNSyX184S9BKZJo1LxrxJ9ltnY2uAs5c/f1MA=\":true}}' | tee /root/.local/share/nix/trusted-settings.json > /dev/null + ''; + }; + systemd = { + services.sshd.wantedBy = lib.mkForce [ "multi-user.target" ]; + targets = { + sleep.enable = false; + suspend.enable = false; + hibernate.enable = false; + hybrid-sleep.enable = false; + }; + }; + + system.stateVersion = lib.mkForce "23.05"; + + networking = { + hostName = "drugstore"; + wireless.enable = false; }; }; - - system.stateVersion = lib.mkForce "23.05"; - - networking = { - hostName = "drugstore"; - wireless.enable = false; - }; - } diff --git a/hosts/nixos/moonside/default.nix b/hosts/nixos/moonside/default.nix index 58a4e76..c0f6267 100644 --- a/hosts/nixos/moonside/default.nix +++ b/hosts/nixos/moonside/default.nix @@ -26,7 +26,19 @@ in tmp.cleanOnBoot = true; }; - environment.etc."issue".text = "\4"; + environment = { + etc."issue".text = "\4"; + + persistence."/persist".directories = lib.mkIf config.swarselsystems.isImpermanence [ + { + directory = "/var/lib/syncthing"; + user = "syncthing"; + group = "syncthing"; + mode = "0700"; + } + ]; + }; + networking = { nftables.enable = lib.mkForce false; @@ -41,14 +53,17 @@ in interfaces = { home-vpn = { privateKeyFile = config.sops.secrets.wireguard-private-key.path; - ips = [ "192.168.3.4/24" ]; + ips = [ "192.168.3.4/32" ]; peers = [ { publicKey = "NNGvakADslOTCmN9HJOW/7qiM+oJ3jAlSZGoShg4ZWw="; name = "moonside"; persistentKeepalive = 25; endpoint = "${config.repo.secrets.common.ipv4}:51820"; - allowedIPs = [ "192.168.3.0/24" ]; + allowedIPs = [ + "192.168.3.0/24" + "192.168.1.0/24" + ]; } ]; }; @@ -62,10 +77,22 @@ in system.stateVersion = "23.11"; - node.secretsDir = ./secrets; services = { nginx = { virtualHosts = { + # "newway.swarsel.win" = { + # enableACME = true; + # forceSSL = true; + # acmeRoot = null; + # locations = { + # "/" = { + # proxyPass = "http://192.168.1.2:8080"; + # extraConfig = '' + # client_max_body_size 0; + # ''; + # }; + # }; + # }; "syncthing.swarsel.win" = { enableACME = true; forceSSL = true; diff --git a/hosts/nixos/nbl-imba-2/default.nix b/hosts/nixos/nbl-imba-2/default.nix index 91aac3d..d77dbaa 100644 --- a/hosts/nixos/nbl-imba-2/default.nix +++ b/hosts/nixos/nbl-imba-2/default.nix @@ -22,7 +22,6 @@ in ]; - node.secretsDir = ./secrets; swarselsystems = lib.recursiveUpdate { firewall = lib.mkForce true; diff --git a/hosts/nixos/nbl-imba-2/secrets/pii.nix.enc b/hosts/nixos/nbl-imba-2/secrets/pii.nix.enc index fb8bd0f..5c7fdf1 100644 --- a/hosts/nixos/nbl-imba-2/secrets/pii.nix.enc +++ b/hosts/nixos/nbl-imba-2/secrets/pii.nix.enc @@ -4,15 +4,19 @@ "age": [ { "recipient": "age16lnmuuxfuxxtty3atnhut8wseppwnhp7rdhmxqd5tdvs9qnjffjq42sqyy", - "enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBQVXVBVndUU2tDdnlWd3Bu\ndi9DMzFseEtGUVFEWnVEMndWTk9GSGl2SFFjCk9QbnpYS2dYVElJQ28yWGw4Umd0\nS1k0Wk9Yc2hrUUc3dkpGb05EYkFHdVEKLS0tIDYvMUh3NEtlY3FWYVdJbTFRaXlW\neU80R1B0aHprSlI5NkJzRldOSFNMTmcKD4DCuREVbI/Qy3sEyEEWtjW/KbIPuN76\nqoteCCN4mGIR7241e5NwMRlFqxgHyod5mpJfwnUbkYBZZZ/u9PDGmw==\n-----END AGE ENCRYPTED FILE-----\n" + "enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBjb21CZ0tQZlNKZkxKMGEz\nUlpMV3lSa1h5TXFNaEpvbWp3ZzZsMUFLd2hnCm9xQlo5Q3RsdW1tSFMxZjVKbjhM\nLzBaS3E1Z0lSQ2lQZEhtclBocE9CcXMKLS0tIHpaYjFIVVRWc2QyQ3hDWmNPODJR\nOFpPQlcwOERMYzhWV3J4ZmpIVUFXcGMKq/CmiIaBFfcx9Muj5LaTQ//ELHmC6WSG\ncJWyfZfrKcPDlXrz7+o9qufLogw3VIkCsTghqsbK6HOKGC5/FbnGSg==\n-----END AGE ENCRYPTED FILE-----\n" + }, + { + "recipient": "age18quey88vge7xytclg2nuq4ncme86dg04lxwczqxczmdchnjg3p0saehsnh", + "enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSA0Z2tONmQxTUhZUW12Z2Jm\nUnoxSnpYcnZDNGNzSko1ckl2RDh3NG1VS2dFCmIwUXhmSk1OUk02S0JPVDR5UWJ4\na0gwWlg0V005ZWxYa29PZ0laS2VqM0kKLS0tIHN5SU9pQ090eHljeXJGWm5hRFQ4\nZ001Nzkyb29RYkNUMDNDNlo4YnVQeTQK34bNIBgxId2+DHKQNVV3Iro3KGkE03Sp\niB1+dADT6nRvGvoyPqnLq/NYfw7eQ6XqYt55zkdCta8v6L1UNUkw8g==\n-----END AGE ENCRYPTED FILE-----\n" } ], "lastmodified": "2025-06-11T13:48:16Z", "mac": "ENC[AES256_GCM,data:6WiY/gpT7V+xQCuotG41Mh+dTSjYT/sg/14Gt7Z7PsrG+WRR33N1OhBV3EVdXeeE8NXkvvoZL/wypgQTWk7wfWpzwhWH478OXc3yaVx7G/nTsDhX/XjKvajpKnXLdn/s2xt9vhPmYuJidR7JYoHN4iv1Lv1eC1mAYKpW4i+sNJk=,iv:ThUxocoeMC1GAfSSeDF9P+m4BZpNuiyWiBrwDPhvNe0=,tag:AxvMKzkG1HBdUqPbbz4Qqg==,type:str]", "pgp": [ { - "created_at": "2025-06-11T09:18:35Z", - "enc": "-----BEGIN PGP MESSAGE-----\n\nhQIMAwDh3VI7VctTARAAzg39i9TFW/qilR+HdUpNlgp3KXnW0kwYk7CI8Ie7RJOz\nAop/ak/nokwooxlLGJOiNsFS1//5PxiwOyxZzPmGvTTH8o8tUNZQSULhDnBKHUWG\n44KkerCk2CjbgOrcL7SzaZsFufGRJRcW1700EGatl8D3U1o94isYbArzQqjVXu7Z\nC3VRE80zV25TO9FzxCWCPOj/ML+vo+gq/rgUNQi4JKKBf01Ti142nlJ8hcMX23cb\n2KZkT0VOTz0uouc1J5hXiYmBLVEfsrKUTcamUE1S/dAGuaMe41F8oHt9Rw0YxP+g\nj1PjVuk/F44CRnVVNo8ScihNmvX+ex6+2n1JWmSFkCHtx054bMHTBiVMf86gYiy6\nUqbhuQw52U4/p3U8h7gYjU8yBuHMnCxxL3u1362lz2fDIOxyKtvMH0NGhw8cp7/+\nZbJ6fAUezn8xCXyzhl88XVYNXvM4Vjq6D3qBjjlyDJe9wXXsoPSAUNuVqBDbfnm0\ngOCnT6yOPj1Zv39IvQR+k73ISwBJySpqGgIYvjRtH0JGkXt2exayvWCqeRArkSQ4\nBITQKHFmSrBxo4ndnsTYWC+5v9VBLSUFEXpwrRZY9L5Zqw9Gyqj6hThzTMJiyaiV\ngMzK1JbGaEOd0f8QDfJfwn6VmmhW67w775V98n2wSejWb4WfogDXKe8DbIqrxp6F\nAgwDC9FRLmchgYQBEACPCA/rrYva4WKx9RrDiVkqi0sUM+xHEC17a9FyVXH+grwK\nwB+7prQjx9P4z2/qqlASuBjBjE8MvG4SIgJ6lziLstqrWpNHDuPJoXCTwdYbiqME\nb2V2VPC+PmulvUNcWDVEv4PWIYnKmvlhC/pxsyGtSfxRWgNYGCCx4eTa2OfYgswd\nnHnS+qT+cC6RTjqyeftJxlII2ocMduNpqFr9pVnPlNq3C++6bw/g/Il/YhGFJmr2\nvOl2WPhExh5CSux+oKjXdzsim1Ltz8KOmkSXNCEdI0v/X6OPNfGhnsKLYxaQMJst\nYfu8PIiVHPOYao2kVMstOeH5d/9LLV8MChKLTUelkZWrl1US0yBoCambl77Ooxx3\n14pTXosVSlShSBTGvGjlQS9Jnp+s75TMr4YoBe9UuK22iwtyq69ZKgNiAv+j0LIA\nOWSazSkbwikPsfFLmBuUWJjb5nvM9TUocDdwQIUE2AmmsXNnhnzd8CMnTRE05Go3\n4IVJXKHlKuiW53ji0b2GjPyT/WR9cLIpXRkh/ruTMQ7unljRLY9Ln92spbipg9wW\n4LXxRQ1pJcSOfMuDspLo12fts+gWaxQnkaHxRFoXORDmUmv1la1fHqFCeJRuNKIl\n+u0a9J2ra5S3f1rN2jsHcX4qLe+uq9rH/hKjPmE3CdMv0m9uifP7DfQiTnJcCdJc\nAR4qlFAxNnJyV3zavOuY410oYQYR9s9lqDWI20k1Gkgf8K668hrIPr9FeTuSCuGf\nCqjQ15D9MmBihKbB2gaMuJ6hV6+cAW6QEqUABMu7jT8oFixTHh42F8PFyxc=\n=lm7F\n-----END PGP MESSAGE-----", + "created_at": "2025-06-14T22:31:01Z", + "enc": "-----BEGIN PGP MESSAGE-----\n\nhQIMAwDh3VI7VctTARAA3TBZeXf6RLph9szeqCtmoXyXDMS1l7NRjhmM85YyxcRo\nTuJQrXA8gmIAen7iVjO/FnndAqd86ddCirpBr/aEKtB9v7Poxx6A/kubV2/EurY7\ngbjWsvY/x6Cqv8IMCTkVdolZNOIYlw4bK3RqERoeWXnvCEXVK2c8fqxmcVoNv6yR\n5leIyApzs7dihbdhK+8nTunIMFJSfP+HQY/wgyowgp3cFVjPe+eTUk8T1xkrir7+\ngfddOHNKnbQWpZRBVj2NE/0dwcKX/rxPHU1sCxOg1TW05jTxavsf8x1+2ST5VLI8\nvttzB8H58OMpDZ1xgoMN7SGSWdTN7BgNcLG4rsGb/GW4+2bxJQ3hS+4aTa59ugXG\nGpqY4ooUopRyOh/hE9xqZ4CXy7IEAGbiBKnwJH+CFlXNygPSURoz9wCH5sgqQ1eA\nGfHrXcGNe2flx9gHZ3g2FUKeORs45CFQLxn2HDSuzVqn9nZfWUFddk9v7G4jSsRg\ntVrSevOXTSFzaSQr5GTQocQILG8HHkg67gKXWMNnk5CiUMVojTljcCej1F5s4Lwg\nljTfTWJMUXfD3Djc2Ap/L+PfxO/Zr0Z5glAndSFQB7aijFaQOR+TVQznRNv90UOk\nwQdF6XANcFMiK3yKQ3xZ6d7lXNTCPlLi5ngakpXhMM1lP0/xFuMWB15IL4yA1FmF\nAgwDC9FRLmchgYQBEADAz9QQ92i1rObvnk3utRhxqizU1SIKhZHEzkdJ+M/9AUQl\nDqj4ge191QMWlEh9jo5ln1abxfVMEjDbomtniPsM5kxPw9qK20M2873ibkps0yNZ\nTdqI2hhB8qBtdEOD/gKq3M27/0c3O7rpsIv8kxxdnmZ9GlRjG9c+SmVqdmZ+PLcP\nOrC+Fq8kQKhINaYdpPoT6x85FW0YLvNiR72grHOKDofqBrFChxapf4HKK6T44TX4\nPKw9G2o/XtN9Z1sfh/R44XsNwTjG8EHrwQLsFYoH3+L7UoNkkNtcwleAl0tkjyVZ\nkq4g0nJKO0KbB1HAM0opamYKOsCUaXQ1MLbXKAmIKy1wuKJR9ibH7E+2Ne41fHJv\n0v243FBnebJP5wlrDY6aBNBX5lPeJBF2q9njp2OnkHWktQD47EyhPhI0hUxN3vzL\n0dSE9/LFgWtvzXqVWIYBWMHToBBiqJRgspw3Jf4Fg0l7Q9p7u2/rwgqbIWMLIDt+\n4tn0ySuiV9jV9dVG3Ho/X7owgr57PPetTvUcU6Ph8Yiv6riLZ+qBy636iGmQd9Zz\n/8nG0BRAnU0YOdWUtvOvBvI+JC5DIs2Trj7Th0AJvlAVLiiR1+0dKk+BdNo/LGE5\nRNNgJIwGHMOZXJonuYfYe15Qy+Qcx3J/NI9VOOfSmzl7A4s8NqtuAt8FNm1cDNJc\nAZp7gi3i3PxxsEXefNMtbFDLe+5yQ4lHro47BxnNAyvnYwKC/VAiwatow9kZGNWn\nc9J/PZinOYPfalwqOl0Zn+pem0hIestNplin7v6ynxa23Cg4g1xUou0ve14=\n=UG0o\n-----END PGP MESSAGE-----", "fp": "4BE7925262289B476DBBC17B76FD3810215AE097" } ], diff --git a/hosts/nixos/sync/default.nix b/hosts/nixos/sync/default.nix index 02f5920..70186ce 100644 --- a/hosts/nixos/sync/default.nix +++ b/hosts/nixos/sync/default.nix @@ -51,7 +51,6 @@ in system.stateVersion = "23.11"; - node.secretsDir = ./secrets; services = { nginx = { virtualHosts = { diff --git a/hosts/nixos/winters/default.nix b/hosts/nixos/winters/default.nix index 8cc6b37..7150250 100644 --- a/hosts/nixos/winters/default.nix +++ b/hosts/nixos/winters/default.nix @@ -28,7 +28,6 @@ in }; - node.secretsDir = ./secrets; swarselsystems = lib.recursiveUpdate { isImpermanence = false; diff --git a/lib/default.nix b/lib/default.nix index 740bcdf..16642af 100644 --- a/lib/default.nix +++ b/lib/default.nix @@ -54,6 +54,10 @@ in systemFunc { specialArgs = { inherit inputs outputs lib self; }; modules = [ + { + node.name = host; + node.secretsDir = ../hosts/${type}/${host}/secrets; + } # put inports here that are for all hosts inputs.disko.nixosModules.disko inputs.sops-nix.nixosModules.sops diff --git a/modules/nixos/common/meta.nix b/modules/nixos/common/meta.nix index 5beaeec..d416302 100644 --- a/modules/nixos/common/meta.nix +++ b/modules/nixos/common/meta.nix @@ -5,4 +5,8 @@ type = lib.types.path; default = ./.; }; + options.node.name = lib.mkOption { + description = "Node Name."; + type = lib.types.str; + }; } diff --git a/modules/nixos/common/nodes.nix b/modules/nixos/common/nodes.nix new file mode 100644 index 0000000..34bd1d3 --- /dev/null +++ b/modules/nixos/common/nodes.nix @@ -0,0 +1,78 @@ +{ config, lib, outputs, ... }: +let + inherit (lib) + attrNames + concatMap + concatStringsSep + foldl' + getAttrFromPath + mkMerge + mkOption + mkOptionType + optionals + recursiveUpdate + setAttrByPath + types + ; + + nodeName = config.node.name; + mkForwardedOption = + path: + mkOption { + type = mkOptionType { + name = "Same type that the receiving option `${concatStringsSep "." path}` normally accepts."; + merge = + _loc: defs: + builtins.filter (x: builtins.isAttrs x -> ((x._type or "") != "__distributed_config_empty")) ( + map (x: x.value) defs + ); + }; + default = { + _type = "__distributed_config_empty"; + }; + description = '' + Anything specified here will be forwarded to `${concatStringsSep "." path}` + on the given node. Forwarding happens as-is to the raw values, + so validity can only be checked on the receiving node. + ''; + }; + + forwardedOptions = [ + [ + "services" + "nginx" + "upstreams" + ] + [ + "services" + "nginx" + "virtualHosts" + ] + ]; + + attrsForEachOption = + f: foldl' (acc: path: recursiveUpdate acc (setAttrByPath path (f path))) { } forwardedOptions; +in +{ + options.nodes = mkOption { + description = "Options forwarded to the given node."; + default = { }; + type = types.attrsOf ( + types.submodule { + options = attrsForEachOption mkForwardedOption; + } + ); + }; + + config = + let + getConfig = + path: otherNode: + let + cfg = outputs.nixosConfigurations.${otherNode}.config.nodes.${nodeName} or null; + in + optionals (cfg != null) (getAttrFromPath path cfg); + mergeConfigFromOthers = path: mkMerge (concatMap (getConfig path) (attrNames outputs.nixosConfigurations)); + in + attrsForEachOption mergeConfigFromOthers; +} diff --git a/modules/nixos/common/syncthing.nix b/modules/nixos/common/syncthing.nix index 11bc550..027beb4 100644 --- a/modules/nixos/common/syncthing.nix +++ b/modules/nixos/common/syncthing.nix @@ -23,7 +23,7 @@ in id = "O7RWDMD-AEAHPP7-7TAVLKZ-BSWNBTU-2VA44MS-EYGUNBB-SLHKB3C-ZSLMOAA"; }; "moonside (@oracle)" = { - id = "YJLYL4Z-JIYHFKX-554ZR7B-YAF3PNH-CX7JF53-NYUMVGL-4EWWASH-GDAMBQA"; + id = "VPCDZB6-MGVGQZD-Q6DIZW3-IZJRJTO-TCC3QUQ-2BNTL7P-AKE7FBO-N55UNQE"; }; }; folders = { diff --git a/modules/nixos/common/users.nix b/modules/nixos/common/users.nix index 0baf845..e205a15 100644 --- a/modules/nixos/common/users.nix +++ b/modules/nixos/common/users.nix @@ -1,8 +1,11 @@ -{ pkgs, config, lib, ... }: +{ self, pkgs, config, lib, ... }: +let + sopsFile = self + /secrets/general/secrets.yaml; +in { options.swarselsystems.modules.users = lib.mkEnableOption "user config"; config = lib.mkIf config.swarselsystems.modules.users { - sops.secrets.swarseluser = lib.mkIf (!config.swarselsystems.isPublic) { neededForUsers = true; }; + sops.secrets.swarseluser = lib.mkIf (!config.swarselsystems.isPublic) { inherit sopsFile; neededForUsers = true; }; users = { mutableUsers = lib.mkIf (!config.swarselsystems.initialSetup) false; diff --git a/modules/nixos/optional/work.nix b/modules/nixos/optional/work.nix index aab2c7b..3cbc8b4 100644 --- a/modules/nixos/optional/work.nix +++ b/modules/nixos/optional/work.nix @@ -175,7 +175,7 @@ in id = "O7RWDMD-AEAHPP7-7TAVLKZ-BSWNBTU-2VA44MS-EYGUNBB-SLHKB3C-ZSLMOAA"; }; "moonside (@oracle)" = { - id = "YJLYL4Z-JIYHFKX-554ZR7B-YAF3PNH-CX7JF53-NYUMVGL-4EWWASH-GDAMBQA"; + id = "VPCDZB6-MGVGQZD-Q6DIZW3-IZJRJTO-TCC3QUQ-2BNTL7P-AKE7FBO-N55UNQE"; }; folders = { "Documents" = { diff --git a/modules/nixos/server/firefly-iii.nix b/modules/nixos/server/firefly-iii.nix index edaaa13..9c648e9 100644 --- a/modules/nixos/server/firefly-iii.nix +++ b/modules/nixos/server/firefly-iii.nix @@ -3,6 +3,7 @@ let cfg = config.services.firefly-iii; fireflyDomain = "stonks.swarsel.win"; fireflyUser = "firefly-iii"; + serviceName = "firefly"; in { options.swarselsystems.modules.server.firefly = lib.mkEnableOption "enable firefly-iii on server"; @@ -31,6 +32,7 @@ in APP_KEY_FILE = config.sops.secrets.firefly-iii-app-key.path; APP_ENV = "local"; DB_CONNECTION = "sqlite"; + TRUSTED_PROXIES = "**"; # AUTHENTICATION_GUARD = "remote_user_guard"; # AUTHENTICATION_GUARD_HEADER = "X-User"; # AUTHENTICATION_GUARD_EMAIL = "X-Email"; @@ -42,52 +44,7 @@ in nginx = { virtualHosts = { "${fireflyDomain}" = { - enableACME = true; - forceSSL = true; - acmeRoot = null; - # main config is automatically added by nixos firefly config. - # hence, only provide certificate locations = { - "/" = { - extraConfig = '' - auth_request /oauth2/auth; - error_page 401 = /oauth2/sign_in; - - # pass information via X-User and X-Email headers to backend, - # requires running with --set-xauthrequest flag (done by NixOS) - auth_request_set $user $upstream_http_x_auth_request_user; - auth_request_set $email $upstream_http_x_auth_request_email; - proxy_set_header X-User $user; - proxy_set_header X-Email $email; - - # if you enabled --pass-access-token, this will pass the token to the backend - auth_request_set $token $upstream_http_x_auth_request_access_token; - proxy_set_header X-Access-Token $token; - - # if you enabled --cookie-refresh, this is needed for it to work with auth_request - auth_request_set $auth_cookie $upstream_http_set_cookie; - add_header Set-Cookie $auth_cookie; - ''; - }; - "/oauth2/" = { - proxyPass = "http://oauth2-proxy"; - extraConfig = '' - - proxy_set_header X-Scheme $scheme; - proxy_set_header X-Auth-Request-Redirect $scheme://$host$request_uri; - ''; - }; - "= /oauth2/auth" = { - proxyPass = "http://oauth2-proxy/oauth2/auth"; - extraConfig = '' - internal; - - proxy_set_header X-Scheme $scheme; - # nginx auth_request includes headers but not body - proxy_set_header Content-Length ""; - proxy_pass_request_body off; - ''; - }; "/api" = { extraConfig = '' index index.php; @@ -102,5 +59,70 @@ in }; }; }; + + nodes.moonside.services.nginx = { + upstreams = { + "${serviceName}" = { + servers = { + "192.168.1.2:80" = { }; + }; + }; + }; + virtualHosts = { + "${fireflyDomain}" = { + enableACME = true; + forceSSL = true; + acmeRoot = null; + # main config is automatically added by nixos firefly config. + # hence, only provide certificate + locations = { + "/" = { + proxyPass = "http://${serviceName}"; + extraConfig = '' + auth_request /oauth2/auth; + error_page 401 = /oauth2/sign_in; + + # pass information via X-User and X-Email headers to backend, + # requires running with --set-xauthrequest flag (done by NixOS) + auth_request_set $user $upstream_http_x_auth_request_user; + auth_request_set $email $upstream_http_x_auth_request_email; + proxy_set_header X-User $user; + proxy_set_header X-Email $email; + + # if you enabled --pass-access-token, this will pass the token to the backend + auth_request_set $token $upstream_http_x_auth_request_access_token; + proxy_set_header X-Access-Token $token; + + # if you enabled --cookie-refresh, this is needed for it to work with auth_request + auth_request_set $auth_cookie $upstream_http_set_cookie; + add_header Set-Cookie $auth_cookie; + ''; + }; + "/oauth2/" = { + proxyPass = "http://oauth2-proxy"; + extraConfig = '' + + proxy_set_header X-Scheme $scheme; + proxy_set_header X-Auth-Request-Redirect $scheme://$host$request_uri; + ''; + }; + "= /oauth2/auth" = { + proxyPass = "http://oauth2-proxy/oauth2/auth"; + extraConfig = '' + internal; + + proxy_set_header X-Scheme $scheme; + # nginx auth_request includes headers but not body + proxy_set_header Content-Length ""; + proxy_pass_request_body off; + ''; + }; + "/api" = { + proxyPass = "http://${serviceName}"; + }; + }; + }; + }; + }; }; } diff --git a/modules/nixos/server/freshrss.nix b/modules/nixos/server/freshrss.nix index 9076e1b..6cadab9 100644 --- a/modules/nixos/server/freshrss.nix +++ b/modules/nixos/server/freshrss.nix @@ -1,4 +1,7 @@ { lib, config, ... }: +let + serviceName = "freshrss"; +in { options.swarselsystems.modules.server.freshrss = lib.mkEnableOption "enable freshrss on server"; config = lib.mkIf config.swarselsystems.modules.server.freshrss { @@ -52,7 +55,14 @@ # config.sops.templates.freshrss-env.path # ]; - services.nginx = { + nodes.moonside.services.nginx = { + upstreams = { + "${serviceName}" = { + servers = { + "192.168.1.2:80" = { }; + }; + }; + }; virtualHosts = { "signpost.swarsel.win" = { enableACME = true; @@ -60,6 +70,7 @@ acmeRoot = null; locations = { "/" = { + proxyPass = "http://${serviceName}"; extraConfig = '' auth_request /oauth2/auth; error_page 401 = /oauth2/sign_in; diff --git a/modules/nixos/server/immich.nix b/modules/nixos/server/immich.nix index 4ea8be8..a41e738 100644 --- a/modules/nixos/server/immich.nix +++ b/modules/nixos/server/immich.nix @@ -1,17 +1,22 @@ { lib, config, ... }: +let + serviceDomain = "shots.swarsel.win"; + servicePort = 3001; + serviceUser = "immich"; + serviceName = "immich"; +in { - options.swarselsystems.modules.server.immich = lib.mkEnableOption "enable immich on server"; - config = lib.mkIf config.swarselsystems.modules.server.immich { + options.swarselsystems.modules.server."${serviceName}" = lib.mkEnableOption "enable ${serviceName} on server"; + config = lib.mkIf config.swarselsystems.modules.server."${serviceName}" { - users.users.immich = { + users.users."${serviceUser}" = { extraGroups = [ "video" "render" "users" ]; }; - # sops.secrets.nextcloudadminpass = { owner = "nextcloud"; }; - services.immich = { enable = true; - port = 3001; + host = "0.0.0.0"; + port = servicePort; openFirewall = true; mediaLocation = "/Vault/Eternor/Immich"; environment = { @@ -19,16 +24,24 @@ }; }; + networking.firewall.allowedTCPPorts = [ 3001 ]; - services.nginx = { + nodes.moonside.services.nginx = { + upstreams = { + "${serviceName}" = { + servers = { + "192.168.1.2:${builtins.toString servicePort}" = { }; + }; + }; + }; virtualHosts = { - "shots.swarsel.win" = { + "${serviceDomain}" = { enableACME = true; forceSSL = true; acmeRoot = null; locations = { "/" = { - proxyPass = "http://localhost:3001"; + proxyPass = "http://${serviceName}"; extraConfig = '' client_max_body_size 0; diff --git a/modules/nixos/server/jellyfin.nix b/modules/nixos/server/jellyfin.nix index fed9749..3018abc 100644 --- a/modules/nixos/server/jellyfin.nix +++ b/modules/nixos/server/jellyfin.nix @@ -1,8 +1,14 @@ { pkgs, lib, config, ... }: +let + serviceDomain = "screen.swarsel.win"; + servicePort = 8096; + serviceName = "jellyfin"; + serviceUser = "jellyfin"; +in { - options.swarselsystems.modules.server.jellyfin = lib.mkEnableOption "enable jellyfin on server"; - config = lib.mkIf config.swarselsystems.modules.server.jellyfin { - users.users.jellyfin = { + options.swarselsystems.modules.server."${serviceName}" = lib.mkEnableOption "enable ${serviceName} on server"; + config = lib.mkIf config.swarselsystems.modules.server."${serviceName}" { + users.users."${serviceUser}" = { extraGroups = [ "video" "render" "users" ]; }; nixpkgs.config.packageOverrides = pkgs: { @@ -19,19 +25,26 @@ }; services.jellyfin = { enable = true; - user = "jellyfin"; + user = serviceUser; openFirewall = true; # this works only for the default ports }; - services.nginx = { + nodes.moonside.services.nginx = { + upstreams = { + "${serviceName}" = { + servers = { + "192.168.1.2:${builtins.toString servicePort}" = { }; + }; + }; + }; virtualHosts = { - "screen.swarsel.win" = { + "${serviceDomain}" = { enableACME = true; forceSSL = true; acmeRoot = null; locations = { "/" = { - proxyPass = "http://localhost:8096"; + proxyPass = "http://${serviceName}"; extraConfig = '' client_max_body_size 0; ''; diff --git a/modules/nixos/server/kanidm.nix b/modules/nixos/server/kanidm.nix index 353d7c6..187b3a1 100644 --- a/modules/nixos/server/kanidm.nix +++ b/modules/nixos/server/kanidm.nix @@ -1,62 +1,52 @@ { self, lib, pkgs, config, ... }: let certsSopsFile = self + /secrets/certs/secrets.yaml; - kanidmDomain = "sso.swarsel.win"; + serviceDomain = "sso.swarsel.win"; + servicePort = 8300; + serviceUser = "kanidm"; + serviceGroup = serviceUser; + serviceName = "kanidm"; oauth2ProxyDomain = "soauth.swarsel.win"; - kanidmPort = 8300; - oauth2ProxyPort = 3004; in { - options.swarselsystems.modules.server.kanidm = lib.mkEnableOption "enable kanidm on server"; - config = lib.mkIf config.swarselsystems.modules.server.kanidm { + options.swarselsystems.modules.server."${serviceName}" = lib.mkEnableOption "enable ${serviceName} on server"; + config = lib.mkIf config.swarselsystems.modules.server."${serviceName}" { - users.users.kanidm = { - group = "kanidm"; + users.users."${serviceUser}" = { + group = serviceGroup; isSystemUser = true; }; - users.groups.kanidm = { }; + users.groups."${serviceGroup}" = { }; sops = { secrets = { - "oauth2-cookie-secret" = { owner = "oauth2-proxy"; group = "oauth2-proxy"; mode = "0440"; }; - "kanidm-self-signed-crt" = { sopsFile = certsSopsFile; owner = "kanidm"; group = "kanidm"; mode = "0440"; }; - "kanidm-self-signed-key" = { sopsFile = certsSopsFile; owner = "kanidm"; group = "kanidm"; mode = "0440"; }; - "kanidm-admin-pw" = { owner = "kanidm"; group = "kanidm"; mode = "0440"; }; - "kanidm-idm-admin-pw" = { owner = "kanidm"; group = "kanidm"; mode = "0440"; }; - "kanidm-immich" = { owner = "kanidm"; group = "kanidm"; mode = "0440"; }; - "kanidm-paperless" = { owner = "kanidm"; group = "kanidm"; mode = "0440"; }; - "kanidm-forgejo" = { owner = "kanidm"; group = "kanidm"; mode = "0440"; }; - "kanidm-grafana" = { owner = "kanidm"; group = "kanidm"; mode = "0440"; }; - "kanidm-nextcloud" = { owner = "kanidm"; group = "kanidm"; mode = "0440"; }; - "kanidm-freshrss" = { owner = "kanidm"; group = "kanidm"; mode = "0440"; }; - "kanidm-oauth2-proxy" = { owner = "kanidm"; group = "kanidm"; mode = "0440"; }; - "kanidm-oauth2-proxy-client" = { owner = "oauth2-proxy"; group = "oauth2-proxy"; mode = "0440"; }; - }; - - templates = { - "kanidm-oauth2-proxy-client-env" = { - content = '' - OAUTH2_PROXY_CLIENT_SECRET="${config.sops.placeholder.kanidm-oauth2-proxy-client}" - OAUTH2_PROXY_COOKIE_SECRET=${config.sops.placeholder.oauth2-cookie-secret} - ''; - owner = "oauth2-proxy"; - group = "oauth2-proxy"; - mode = "0440"; - }; + "kanidm-self-signed-crt" = { sopsFile = certsSopsFile; owner = serviceUser; group = serviceGroup; mode = "0440"; }; + "kanidm-self-signed-key" = { sopsFile = certsSopsFile; owner = serviceUser; group = serviceGroup; mode = "0440"; }; + "kanidm-admin-pw" = { owner = serviceUser; group = serviceGroup; mode = "0440"; }; + "kanidm-idm-admin-pw" = { owner = serviceUser; group = serviceGroup; mode = "0440"; }; + "kanidm-immich" = { owner = serviceUser; group = serviceGroup; mode = "0440"; }; + "kanidm-paperless" = { owner = serviceUser; group = serviceGroup; mode = "0440"; }; + "kanidm-forgejo" = { owner = serviceUser; group = serviceGroup; mode = "0440"; }; + "kanidm-grafana" = { owner = serviceUser; group = serviceGroup; mode = "0440"; }; + "kanidm-nextcloud" = { owner = serviceUser; group = serviceGroup; mode = "0440"; }; + "kanidm-freshrss" = { owner = serviceUser; group = serviceGroup; mode = "0440"; }; + "kanidm-oauth2-proxy" = { owner = serviceUser; group = serviceGroup; mode = "0440"; }; }; }; + networking.firewall.allowedTCPPorts = [ servicePort ]; + services = { kanidm = { package = pkgs.kanidmWithSecretProvisioning; enableServer = true; serverSettings = { - domain = kanidmDomain; - origin = "https://${kanidmDomain}"; + domain = serviceDomain; + origin = "https://${serviceDomain}"; tls_chain = config.sops.secrets.kanidm-self-signed-crt.path; tls_key = config.sops.secrets.kanidm-self-signed-key.path; - bindaddress = "0.0.0.0:${toString kanidmPort}"; + bindaddress = "0.0.0.0:${toString servicePort}"; trust_x_forward_for = true; }; enableClient = true; @@ -177,19 +167,6 @@ in }; }; }; - # freshrss = { - # displayName = "FreshRSS"; - # originUrl = "https://signpost.swarsel.win/apps/sociallogin/custom_oidc/kanidm"; - # originLanding = "https://signpost.swarsel.win/"; - # basicSecretFile = config.sops.secrets.kanidm-freshrss.path; - # allowInsecureClientDisablePkce = true; - # scopeMaps."freshrss.access" = [ - # "openid" - # "email" - # "profile" - # ]; - # preferShortUsername = true; - # }; oauth2-proxy = { displayName = "Oauth2-Proxy"; originUrl = "https://${oauth2ProxyDomain}/oauth2/callback"; @@ -226,96 +203,34 @@ in }; }; }; - oauth2-proxy = { - enable = true; - cookie = { - domain = ".swarsel.win"; - secure = true; - expire = "900m"; - secret = null; # set by service EnvironmentFile - }; - clientSecret = null; # set by service EnvironmentFile - reverseProxy = true; - httpAddress = "0.0.0.0:${builtins.toString oauth2ProxyPort}"; - redirectURL = "https://${oauth2ProxyDomain}/oauth2/callback"; - setXauthrequest = true; - extraConfig = { - code-challenge-method = "S256"; - whitelist-domain = ".swarsel.win"; - set-authorization-header = true; - pass-access-token = true; - skip-jwt-bearer-tokens = true; - upstream = "static://202"; - oidc-issuer-url = "https://${kanidmDomain}/oauth2/openid/oauth2-proxy"; - provider-display-name = "Kanidm"; - }; - provider = "oidc"; - scope = "openid email"; - loginURL = "https://${kanidmDomain}/ui/oauth2"; - redeemURL = "https://${kanidmDomain}/oauth2/token"; - validateURL = "https://${kanidmDomain}/oauth2/openid/oauth2-proxy/userinfo"; - clientID = "oauth2-proxy"; - email.domains = [ "*" ]; - }; }; systemd.services = { kanidm.serviceConfig.RestartSec = "30"; - oauth2-proxy = { - after = [ "kanidm.service" ]; - serviceConfig = { - RuntimeDirectory = "oauth2-proxy"; - RuntimeDirectoryMode = "0750"; - UMask = "007"; # TODO remove once https://github.com/oauth2-proxy/oauth2-proxy/issues/2141 is fixed - RestartSec = "60"; # Retry every minute - EnvironmentFile = [ - config.sops.templates.kanidm-oauth2-proxy-client-env.path - ]; - }; - }; }; - services.nginx = { + nodes.moonside.services.nginx = { upstreams = { - kanidm = { + "${serviceName}" = { servers = { - "192.168.1.2:${builtins.toString kanidmPort}" = { }; - }; - }; - oauth2-proxy = { - servers = { - "192.168.1.2:${builtins.toString oauth2ProxyPort}" = { }; + "192.168.1.2:${builtins.toString servicePort}" = { }; }; }; }; virtualHosts = { - "${kanidmDomain}" = { + "${serviceDomain}" = { enableACME = true; forceSSL = true; acmeRoot = null; locations = { "/" = { - proxyPass = "https://kanidm"; + proxyPass = "https://${serviceName}"; }; }; extraConfig = '' proxy_ssl_verify off; ''; }; - "${oauth2ProxyDomain}" = { - enableACME = true; - forceSSL = true; - acmeRoot = null; - locations = { - "/" = { - proxyPass = "http://oauth2-proxy"; - }; - }; - extraConfig = '' - proxy_set_header X-Scheme $scheme; - proxy_set_header X-Auth-Request-Redirect $scheme://$host$request_uri; - ''; - }; }; }; }; diff --git a/modules/nixos/server/kavita.nix b/modules/nixos/server/kavita.nix index 8faba9e..42178a7 100644 --- a/modules/nixos/server/kavita.nix +++ b/modules/nixos/server/kavita.nix @@ -1,36 +1,48 @@ { pkgs, lib, config, ... }: +let + serviceName = "kavita"; + serviceUser = "kavita"; + serviceDomain = "scroll.swarsel.win"; + servicePort = 8080; +in { - options.swarselsystems.modules.server.kavita = lib.mkEnableOption "enable kavita on server"; - config = lib.mkIf config.swarselsystems.modules.server.kavita { + options.swarselsystems.modules.server."${serviceName}" = lib.mkEnableOption "enable ${serviceName} on server"; + config = lib.mkIf config.swarselsystems.modules.server."${serviceName}" { environment.systemPackages = with pkgs; [ calibre ]; - - users.users.kavita = { + users.users."${serviceUser}" = { extraGroups = [ "users" ]; }; - sops.secrets.kavita = { owner = "kavita"; }; + sops.secrets.kavita = { owner = serviceUser; }; networking.firewall.allowedTCPPorts = [ 8080 ]; services.kavita = { enable = true; - user = "kavita"; - settings.Port = 8080; + user = serviceUser; + settings.Port = servicePort; tokenKeyFile = config.sops.secrets.kavita.path; }; - services.nginx = { + nodes.moonside.services.nginx = { + upstreams = { + "${serviceName}" = { + servers = { + "192.168.1.2:${builtins.toString servicePort}" = { }; + }; + }; + }; virtualHosts = { - "scroll.swarsel.win" = { + "${serviceDomain}" = { enableACME = true; forceSSL = true; acmeRoot = null; locations = { "/" = { - proxyPass = "http://localhost:8080"; + proxyPass = "http://${serviceName}"; extraConfig = '' client_max_body_size 0; ''; diff --git a/modules/nixos/server/koillection.nix b/modules/nixos/server/koillection.nix index adb9014..36eaad9 100644 --- a/modules/nixos/server/koillection.nix +++ b/modules/nixos/server/koillection.nix @@ -55,7 +55,7 @@ in }; }; - networking.firewall.allowedTCPPorts = [ postgresPort ]; + networking.firewall.allowedTCPPorts = [ servicePort postgresPort ]; systemd.services.postgresql.postStart = let @@ -86,17 +86,24 @@ in host ${serviceDB} ${serviceDB} 10.88.0.0/16 scram-sha-256 ''; }; + }; - nginx = { - virtualHosts = { - "${serviceDomain}" = { - enableACME = true; - forceSSL = true; - acmeRoot = null; - locations = { - "/" = { - proxyPass = "http://localhost:${toString servicePort}"; - }; + nodes.moonside.services.nginx = { + upstreams = { + "${serviceName}" = { + servers = { + "192.168.1.2:${builtins.toString servicePort}" = { }; + }; + }; + }; + virtualHosts = { + "${serviceDomain}" = { + enableACME = true; + forceSSL = true; + acmeRoot = null; + locations = { + "/" = { + proxyPass = "http://${serviceName}"; }; }; }; diff --git a/modules/nixos/server/matrix.nix b/modules/nixos/server/matrix.nix index f566541..c5f8808 100644 --- a/modules/nixos/server/matrix.nix +++ b/modules/nixos/server/matrix.nix @@ -1,6 +1,13 @@ { config, lib, pkgs, sops, ... }: let matrixDomain = "swatrix.swarsel.win"; + serviceName = "matrix"; + synapsePort = 8008; + synapseUser = "matrix-synapse"; + whatsappPort = 29318; + telegramPort = 29317; + signalPort = 29328; + baseUrl = "https://${matrixDomain}"; clientConfig."m.homeserver".base_url = baseUrl; serverConfig."m.server" = "${matrixDomain}:443"; @@ -11,8 +18,8 @@ let ''; in { - options.swarselsystems.modules.server.matrix = lib.mkEnableOption "enable matrix on server"; - config = lib.mkIf config.swarselsystems.modules.server.matrix { + options.swarselsystems.modules.server."${serviceName}" = lib.mkEnableOption "enable ${serviceName} on server"; + config = lib.mkIf config.swarselsystems.modules.server."${serviceName}" { environment.systemPackages = with pkgs; [ matrix-synapse lottieconverter @@ -21,24 +28,24 @@ in sops = { secrets = { - matrixsharedsecret = { owner = "matrix-synapse"; }; - mautrixtelegram_as = { owner = "matrix-synapse"; }; - mautrixtelegram_hs = { owner = "matrix-synapse"; }; - mautrixtelegram_api_id = { owner = "matrix-synapse"; }; - mautrixtelegram_api_hash = { owner = "matrix-synapse"; }; + matrixsharedsecret = { owner = synapseUser; }; + mautrixtelegram_as = { owner = synapseUser; }; + mautrixtelegram_hs = { owner = synapseUser; }; + mautrixtelegram_api_id = { owner = synapseUser; }; + mautrixtelegram_api_hash = { owner = synapseUser; }; }; templates = { "matrix_user_register.sh".content = '' - register_new_matrix_user -k ${config.sops.placeholder.matrixsharedsecret} http://localhost:8008 + register_new_matrix_user -k ${config.sops.placeholder.matrixsharedsecret} http://localhost:${builtins.toString synapsePort} ''; matrixshared = { - owner = "matrix-synapse"; + owner = synapseUser; content = '' registration_shared_secret: ${config.sops.placeholder.matrixsharedsecret} ''; }; mautrixtelegram = { - owner = "matrix-synapse"; + owner = synapseUser; content = '' MAUTRIX_TELEGRAM_APPSERVICE_AS_TOKEN=${config.sops.placeholder.mautrixtelegram_as} MAUTRIX_TELEGRAM_APPSERVICE_HS_TOKEN=${config.sops.placeholder.mautrixtelegram_hs} @@ -49,6 +56,8 @@ in }; }; + networking.firewall.allowedTCPPorts = [ 8008 8448 ]; + systemd = { timers."restart-bridges" = { wantedBy = [ "timers.target" ]; @@ -118,9 +127,9 @@ in public_baseurl = "https://${matrixDomain}"; listeners = [ { - port = 8008; + port = synapsePort; bind_addresses = [ - "127.0.0.1" + "0.0.0.0" # "::1" ]; type = "http"; @@ -146,13 +155,13 @@ in registerToSynapse = false; settings = { homeserver = { - address = "http://localhost:8008"; + address = "http://localhost:${builtins.toString synapsePort}"; domain = matrixDomain; }; appservice = { - address = "http://localhost:29317"; - hostname = "localhost"; - port = "29317"; + address = "http://localhost:${builtins.toString telegramPort}"; + hostname = "0.0.0.0"; + port = telegramPort; provisioning.enabled = true; id = "telegram"; # ephemeral_events = true; # not needed due to double puppeting @@ -192,13 +201,13 @@ in registerToSynapse = false; settings = { homeserver = { - address = "http://localhost:8008"; + address = "http://localhost:${builtins.toString synapsePort}"; domain = matrixDomain; }; appservice = { - address = "http://localhost:29318"; - hostname = "127.0.0.1"; - port = 29318; + address = "http://localhost:${builtins.toString whatsappPort}"; + hostname = "0.0.0.0"; + port = whatsappPort; database = { type = "postgres"; uri = "postgresql:///mautrix-whatsapp?host=/run/postgresql"; @@ -239,14 +248,13 @@ in registerToSynapse = false; settings = { homeserver = { - address = "http://localhost:8008"; + address = "http://localhost:${builtins.toString synapsePort}"; domain = matrixDomain; }; appservice = { - - address = "http://localhost:29328"; - hostname = "127.0.0.1"; - port = 29328; + address = "http://localhost:${builtins.toString signalPort}"; + hostname = "0.0.0.0"; + port = signalPort; database = { type = "postgres"; uri = "postgresql:///mautrix-signal?host=/run/postgresql"; @@ -265,61 +273,65 @@ in }; }; }; + }; - # restart the bridges daily. this is done for the signal bridge mainly which stops carrying - # messages out after a while. + # restart the bridges daily. this is done for the signal bridge mainly which stops carrying + # messages out after a while. - nginx = { - virtualHosts = { - "swatrix.swarsel.win" = { - enableACME = true; - forceSSL = true; - acmeRoot = null; - listen = [ - { - addr = "0.0.0.0"; - port = 8448; - ssl = true; - extraParameters = [ - "default_server" - ]; - } - { - addr = "[::0]"; - port = 8448; - ssl = true; - extraParameters = [ - "default_server" - ]; - } - { - addr = "0.0.0.0"; - port = 443; - ssl = true; - } - { - addr = "[::0]"; - port = 443; - ssl = true; - } - ]; - locations = { - "~ ^(/_matrix|/_synapse/client)" = { - # proxyPass = "http://localhost:8008"; - proxyPass = "http://localhost:8008"; - extraConfig = '' - client_max_body_size 0; - ''; - }; - "= /.well-known/matrix/server".extraConfig = mkWellKnown serverConfig; - "= /.well-known/matrix/client".extraConfig = mkWellKnown clientConfig; + nodes.moonside.services.nginx = { + upstreams = { + "${serviceName}" = { + servers = { + "192.168.1.2:${builtins.toString synapsePort}" = { }; + }; + }; + }; + virtualHosts = { + "${matrixDomain}" = { + enableACME = true; + forceSSL = true; + acmeRoot = null; + listen = [ + { + addr = "0.0.0.0"; + port = 8448; + ssl = true; + extraParameters = [ + "default_server" + ]; + } + { + addr = "[::0]"; + port = 8448; + ssl = true; + extraParameters = [ + "default_server" + ]; + } + { + addr = "0.0.0.0"; + port = 443; + ssl = true; + } + { + addr = "[::0]"; + port = 443; + ssl = true; + } + ]; + locations = { + "~ ^(/_matrix|/_synapse/client)" = { + proxyPass = "http://${serviceName}"; + extraConfig = '' + client_max_body_size 0; + ''; }; + "= /.well-known/matrix/server".extraConfig = mkWellKnown serverConfig; + "= /.well-known/matrix/client".extraConfig = mkWellKnown clientConfig; }; }; }; }; }; - - } diff --git a/modules/nixos/server/monitoring.nix b/modules/nixos/server/monitoring.nix index ed21b34..19628c0 100644 --- a/modules/nixos/server/monitoring.nix +++ b/modules/nixos/server/monitoring.nix @@ -1,23 +1,23 @@ { self, lib, config, ... }: let - grafanaDomain = "status.swarsel.win"; + serviceDomain = "status.swarsel.win"; + servicePort = 3000; + serviceUser = "grafana"; + serviceGroup = serviceUser; + moduleName = "monitoring"; + grafanaUpstream = "grafana"; + prometheusUpstream = "prometheus"; + prometheusPort = 9090; + prometheusWebRoot = "prometheus"; in { - options.swarselsystems.modules.server.monitoring = lib.mkEnableOption "enable monitoring on server"; - config = lib.mkIf config.swarselsystems.modules.server.monitoring { + options.swarselsystems.modules.server."${moduleName}" = lib.mkEnableOption "enable ${moduleName} on server"; + config = lib.mkIf config.swarselsystems.modules.server."${moduleName}" { sops.secrets = { - grafanaadminpass = { - owner = "grafana"; - }; - prometheusadminpass = { - owner = "grafana"; - }; - kanidm-grafana-client = { - owner = "grafana"; - group = "grafana"; - mode = "0440"; - }; + grafanaadminpass = { owner = serviceUser; group = serviceGroup; mode = "0440"; }; + prometheusadminpass = { owner = serviceUser; group = serviceGroup; mode = "0440"; }; + kanidm-grafana-client = { owner = serviceUser; group = serviceGroup; mode = "0440"; }; }; users = { @@ -26,12 +26,14 @@ in extraGroups = [ "nextcloud" ]; }; - grafana = { + "${serviceUser}" = { extraGroups = [ "users" ]; }; }; }; + networking.firewall.allowedTCPPorts = [ servicePort prometheusPort ]; + services = { grafana = { enable = true; @@ -43,7 +45,7 @@ in { name = "prometheus"; type = "prometheus"; - url = "https://${grafanaDomain}/prometheus"; + url = "https://${serviceDomain}/prometheus"; editable = false; access = "proxy"; basicAuth = true; @@ -66,13 +68,21 @@ in }; settings = { - security.admin_password = "$__file{/run/secrets/grafanaadminpass}"; + analytics.reporting_enabled = false; + users.allow_sign_up = false; + security = { + admin_password = "$__file{/run/secrets/grafanaadminpass}"; + cookie_secure = true; + disable_gravatar = true; + }; server = { - domain = grafanaDomain; - root_url = "https://${grafanaDomain}"; - http_port = 3000; + domain = serviceDomain; + root_url = "https://${serviceDomain}"; + http_port = servicePort; http_addr = "0.0.0.0"; protocol = "http"; + enforce_domain = true; + enable_gzip = true; }; "auth.generic_oauth" = { enabled = true; @@ -98,9 +108,9 @@ in prometheus = { enable = true; - webExternalUrl = "https://status.swarsel.win/prometheus"; - port = 9090; - listenAddress = "127.0.0.1"; + webExternalUrl = "https://status.swarsel.win/${prometheusWebRoot}"; + port = prometheusPort; + listenAddress = "0.0.0.0"; globalConfig = { scrape_interval = "10s"; }; @@ -164,33 +174,44 @@ in }; }; }; + }; - nginx = { - virtualHosts = { - "${grafanaDomain}" = { - enableACME = true; - forceSSL = true; - acmeRoot = null; - locations = { - "/" = { - proxyPass = "http://localhost:3000"; - proxyWebsockets = true; - extraConfig = '' - client_max_body_size 0; - ''; - }; - "/prometheus" = { - proxyPass = "http://localhost:9090"; - extraConfig = '' - client_max_body_size 0; - ''; - }; + nodes.moonside.services.nginx = { + upstreams = { + "${grafanaUpstream}" = { + servers = { + "192.168.1.2:${builtins.toString servicePort}" = { }; + }; + }; + "${prometheusUpstream}" = { + servers = { + "192.168.1.2:${builtins.toString prometheusPort}" = { }; + }; + }; + }; + virtualHosts = { + "${serviceDomain}" = { + enableACME = true; + forceSSL = true; + acmeRoot = null; + locations = { + "/" = { + proxyPass = "http://${grafanaUpstream}"; + proxyWebsockets = true; + extraConfig = '' + client_max_body_size 0; + ''; + }; + "/${prometheusWebRoot}" = { + proxyPass = "http://${prometheusUpstream}"; + extraConfig = '' + client_max_body_size 0; + ''; }; }; }; }; }; }; - } diff --git a/modules/nixos/server/navidrome.nix b/modules/nixos/server/navidrome.nix index 3c97a50..6e90478 100644 --- a/modules/nixos/server/navidrome.nix +++ b/modules/nixos/server/navidrome.nix @@ -1,7 +1,14 @@ { pkgs, config, lib, ... }: +let + serviceDomain = "sound.swarsel.win"; + servicePort = 4040; + serviceName = "navidrome"; + serviceUser = "navidrome"; + serviceGroup = serviceUser; +in { - options.swarselsystems.modules.server.navidrome = lib.mkEnableOption "enable navidrome on server"; - config = lib.mkIf config.swarselsystems.modules.server.navidrome { + options.swarselsystems.modules.server."${serviceName}" = lib.mkEnableOption "enable ${serviceName} on server"; + config = lib.mkIf config.swarselsystems.modules.server."${serviceName}" { environment.systemPackages = with pkgs; [ pciutils alsa-utils @@ -10,16 +17,16 @@ users = { groups = { - navidrome = { + "$(serviceGroup}" = { gid = 61593; }; }; users = { - navidrome = { + "${serviceUser}" = { isSystemUser = true; uid = 61593; - group = "navidrome"; + group = serviceGroup; extraGroups = [ "audio" "utmp" "users" "pipewire" ]; }; }; @@ -37,8 +44,8 @@ openFirewall = true; settings = { LogLevel = "debug"; - Address = "127.0.0.1"; - Port = 4040; + Address = "0.0.0.0"; + Port = servicePort; MusicFolder = "/Vault/Eternor/Music"; PlaylistsPath = "./Playlists"; EnableSharing = true; @@ -70,15 +77,22 @@ }; }; - services.nginx = { + nodes.moonside.services.nginx = { + upstreams = { + "${serviceName}" = { + servers = { + "192.168.1.2:${builtins.toString servicePort}" = { }; + }; + }; + }; virtualHosts = { - "sound.swarsel.win" = { + "${serviceDomain}" = { enableACME = true; forceSSL = true; acmeRoot = null; locations = { "/" = { - proxyPass = "http://localhost:4040"; + proxyPass = "http://navidrome"; proxyWebsockets = true; extraConfig = '' auth_request /oauth2/auth; @@ -125,7 +139,7 @@ ''; }; "/share" = { - proxyPass = "http://localhost:4040"; + proxyPass = "http://navidrome"; proxyWebsockets = true; extraConfig = '' proxy_redirect http:// https://; @@ -139,7 +153,7 @@ ''; }; "/rest" = { - proxyPass = "http://localhost:4040"; + proxyPass = "http://navidrome"; proxyWebsockets = true; extraConfig = '' proxy_redirect http:// https://; diff --git a/modules/nixos/server/nextcloud.nix b/modules/nixos/server/nextcloud.nix index d5fa06d..d452e61 100644 --- a/modules/nixos/server/nextcloud.nix +++ b/modules/nixos/server/nextcloud.nix @@ -1,20 +1,23 @@ { pkgs, lib, config, ... }: let - nextcloudDomain = "stash.swarsel.win"; + serviceDomain = "stash.swarsel.win"; + serviceUser = "nextcloud"; + serviceGroup = serviceUser; + serviceName = "nextcloud"; in { - options.swarselsystems.modules.server.nextcloud = lib.mkEnableOption "enable nextcloud on server"; - config = lib.mkIf config.swarselsystems.modules.server.nextcloud { + options.swarselsystems.modules.server."${serviceName}" = lib.mkEnableOption "enable ${serviceName} on server"; + config = lib.mkIf config.swarselsystems.modules.server."${serviceName}" { sops.secrets = { nextcloudadminpass = { - owner = "nextcloud"; - group = "nextcloud"; + owner = serviceUser; + group = serviceGroup; mode = "0440"; }; kanidm-nextcloud-client = { - owner = "nextcloud"; - group = "nextcloud"; + owner = serviceUser; + group = serviceGroup; mode = "0440"; }; }; @@ -22,8 +25,12 @@ in services = { nextcloud = { enable = true; + settings = { + trusted_proxies = [ "0.0.0.0" ]; + overwriteprotocol = "https"; + }; package = pkgs.nextcloud31; - hostName = nextcloudDomain; + hostName = serviceDomain; home = "/Vault/apps/nextcloud"; datadir = "/Vault/data/nextcloud"; https = true; @@ -39,19 +46,28 @@ in dbtype = "sqlite"; }; }; + }; - nginx = { - virtualHosts = { - "${nextcloudDomain}" = { - enableACME = true; - forceSSL = true; - acmeRoot = null; - # config is automatically added by nixos nextcloud config. - # hence, only provide certificate + nodes.moonside.services.nginx = { + upstreams = { + "${serviceName}" = { + servers = { + "192.168.1.2:80" = { }; + }; + }; + }; + virtualHosts = { + "${serviceDomain}" = { + enableACME = true; + forceSSL = true; + acmeRoot = null; + locations = { + "/" = { + proxyPass = "http://${serviceName}"; + }; }; }; }; }; }; - } diff --git a/modules/nixos/server/oauth2-proxy.nix b/modules/nixos/server/oauth2-proxy.nix new file mode 100644 index 0000000..38fb212 --- /dev/null +++ b/modules/nixos/server/oauth2-proxy.nix @@ -0,0 +1,107 @@ +{ lib, config, ... }: +let + kanidmDomain = "sso.swarsel.win"; + oauth2ProxyDomain = "soauth.swarsel.win"; + oauth2ProxyPort = 3004; +in +{ + options.swarselsystems.modules.server.oauth2Proxy = lib.mkEnableOption "enable oauth2-proxy on server"; + config = lib.mkIf config.swarselsystems.modules.server.oauth2Proxy { + + sops = { + secrets = { + "oauth2-cookie-secret" = { owner = "oauth2-proxy"; group = "oauth2-proxy"; mode = "0440"; }; + "kanidm-oauth2-proxy-client" = { owner = "oauth2-proxy"; group = "oauth2-proxy"; mode = "0440"; }; + }; + + templates = { + "kanidm-oauth2-proxy-client-env" = { + content = '' + OAUTH2_PROXY_CLIENT_SECRET="${config.sops.placeholder.kanidm-oauth2-proxy-client}" + OAUTH2_PROXY_COOKIE_SECRET=${config.sops.placeholder.oauth2-cookie-secret} + ''; + owner = "oauth2-proxy"; + group = "oauth2-proxy"; + mode = "0440"; + }; + }; + }; + + networking.firewall.allowedTCPPorts = [ oauth2ProxyPort ]; + + services = { + oauth2-proxy = { + enable = true; + cookie = { + domain = ".swarsel.win"; + secure = true; + expire = "900m"; + secret = null; # set by service EnvironmentFile + }; + clientSecret = null; # set by service EnvironmentFile + reverseProxy = true; + httpAddress = "0.0.0.0:${builtins.toString oauth2ProxyPort}"; + redirectURL = "https://${oauth2ProxyDomain}/oauth2/callback"; + setXauthrequest = true; + extraConfig = { + code-challenge-method = "S256"; + whitelist-domain = ".swarsel.win"; + set-authorization-header = true; + pass-access-token = true; + skip-jwt-bearer-tokens = true; + upstream = "static://202"; + oidc-issuer-url = "https://${kanidmDomain}/oauth2/openid/oauth2-proxy"; + provider-display-name = "Kanidm"; + }; + provider = "oidc"; + scope = "openid email"; + loginURL = "https://${kanidmDomain}/ui/oauth2"; + redeemURL = "https://${kanidmDomain}/oauth2/token"; + validateURL = "https://${kanidmDomain}/oauth2/openid/oauth2-proxy/userinfo"; + clientID = "oauth2-proxy"; + email.domains = [ "*" ]; + }; + }; + + systemd.services = { + oauth2-proxy = { + # after = [ "kanidm.service" ]; + serviceConfig = { + RuntimeDirectory = "oauth2-proxy"; + RuntimeDirectoryMode = "0750"; + UMask = "007"; # TODO remove once https://github.com/oauth2-proxy/oauth2-proxy/issues/2141 is fixed + RestartSec = "60"; # Retry every minute + EnvironmentFile = [ + config.sops.templates.kanidm-oauth2-proxy-client-env.path + ]; + }; + }; + }; + + services.nginx = { + upstreams = { + oauth2-proxy = { + servers = { + "localhost:${builtins.toString oauth2ProxyPort}" = { }; + }; + }; + }; + virtualHosts = { + "${oauth2ProxyDomain}" = { + enableACME = true; + forceSSL = true; + acmeRoot = null; + locations = { + "/" = { + proxyPass = "http://oauth2-proxy"; + }; + }; + extraConfig = '' + proxy_set_header X-Scheme $scheme; + proxy_set_header X-Auth-Request-Redirect $scheme://$host$request_uri; + ''; + }; + }; + }; + }; +} diff --git a/modules/nixos/server/paperless.nix b/modules/nixos/server/paperless.nix index 90d6eb0..44458e8 100644 --- a/modules/nixos/server/paperless.nix +++ b/modules/nixos/server/paperless.nix @@ -1,30 +1,39 @@ { lib, pkgs, config, ... }: +let + serviceDomain = "scan.swarsel.win"; + servicePort = 28981; + serviceUser = "paperless"; + serviceGroup = serviceUser; + serviceName = "paperless"; +in { - options.swarselsystems.modules.server.paperless = lib.mkEnableOption "enable paperless on server"; - config = lib.mkIf config.swarselsystems.modules.server.paperless { + options.swarselsystems.modules.server."${serviceName}" = lib.mkEnableOption "enable ${serviceName} on server"; + config = lib.mkIf config.swarselsystems.modules.server."${serviceName}" { - users.users.paperless = { + users.users."${serviceUser}" = { extraGroups = [ "users" ]; }; sops.secrets = { - paperless_admin = { owner = "paperless"; }; + paperless_admin = { owner = serviceUser; }; kanidm-paperless-client = { - owner = "paperless"; - group = "paperless"; + owner = serviceUser; + group = serviceGroup; mode = "0440"; }; }; + networking.firewall.allowedTCPPorts = [ servicePort ]; + services = { paperless = { enable = true; mediaDir = "/Vault/Eternor/Paperless"; dataDir = "/Vault/data/paperless"; - user = "paperless"; - port = 28981; + user = serviceUser; + port = servicePort; passwordFile = config.sops.secrets.paperless_admin.path; - address = "127.0.0.1"; + address = "0.0.0.0"; settings = { PAPERLESS_OCR_LANGUAGE = "deu+eng"; PAPERLESS_URL = "https://scan.swarsel.win"; @@ -84,15 +93,22 @@ ) ''; - services.nginx = { + nodes.moonside.services.nginx = { + upstreams = { + "${serviceName}" = { + servers = { + "192.168.1.2:${builtins.toString servicePort}" = { }; + }; + }; + }; virtualHosts = { - "scan.swarsel.win" = { + "${serviceDomain}" = { enableACME = true; forceSSL = true; acmeRoot = null; locations = { "/" = { - proxyPass = "http://localhost:28981"; + proxyPass = "http://${serviceName}"; extraConfig = '' client_max_body_size 0; proxy_connect_timeout 300; diff --git a/modules/nixos/server/syncthing.nix b/modules/nixos/server/syncthing.nix index 5cf7e1f..c1053ce 100644 --- a/modules/nixos/server/syncthing.nix +++ b/modules/nixos/server/syncthing.nix @@ -1,26 +1,34 @@ { lib, config, ... }: let inherit (config.repo.secrets.common) workHostName; + serviceDomain = "storync.swarsel.win"; + servicePort = 8384; + serviceUser = "syncthing"; + serviceGroup = serviceUser; + serviceName = "syncthing"; in { - options.swarselsystems.modules.server.syncthing = lib.mkEnableOption "enable syncthing on server"; - config = lib.mkIf config.swarselsystems.modules.server.syncthing { + options.swarselsystems.modules.server."${serviceName}" = lib.mkEnableOption "enable ${serviceName} on server"; + config = lib.mkIf config.swarselsystems.modules.server."${serviceName}" { - users.users.syncthing = { + users.users."${serviceUser}" = { extraGroups = [ "users" ]; - group = "syncthing"; + group = serviceGroup; isSystemUser = true; }; - users.groups.syncthing = { }; + users.groups."${serviceGroup}" = { }; + + networking.firewall.allowedTCPPorts = [ servicePort ]; services.syncthing = { enable = true; - user = "swarsel"; + user = serviceUser; + group = serviceGroup; dataDir = "/Vault/data/syncthing"; configDir = "/Vault/apps/syncthing"; - guiAddress = "0.0.0.0:8384"; - openDefaultPorts = true; + guiAddress = "0.0.0.0:${builtins.toString servicePort}"; + openDefaultPorts = true; # opens ports TCP/UDP 22000 and UDP 21027 for discovery relay.enable = false; settings = { urAccepted = -1; @@ -34,13 +42,16 @@ in "${workHostName}" = { id = "YAPV4BV-I26WPTN-SIP32MV-SQP5TBZ-3CHMTCI-Z3D6EP2-MNDQGLP-53FT3AB"; }; + "moonside (@oracle)" = { + id = "VPCDZB6-MGVGQZD-Q6DIZW3-IZJRJTO-TCC3QUQ-2BNTL7P-AKE7FBO-N55UNQE"; + }; }; folders = { "Default Folder" = lib.mkForce { path = "/Vault/data/syncthing/Sync"; type = "receiveonly"; versioning = null; - devices = [ "sync (@oracle)" "magicant" "${workHostName}" ]; + devices = [ "sync (@oracle)" "magicant" "${workHostName}" "moonside (@oracle)" ]; id = "default"; }; "Obsidian" = { @@ -50,7 +61,7 @@ in type = "simple"; params.keep = "5"; }; - devices = [ "sync (@oracle)" "magicant" "${workHostName}" ]; + devices = [ "sync (@oracle)" "magicant" "${workHostName}" "moonside (@oracle)" ]; id = "yjvni-9eaa7"; }; "Org" = { @@ -60,7 +71,7 @@ in type = "simple"; params.keep = "5"; }; - devices = [ "sync (@oracle)" "magicant" "${workHostName}" ]; + devices = [ "sync (@oracle)" "magicant" "${workHostName}" "moonside (@oracle)" ]; id = "a7xnl-zjj3d"; }; "Vpn" = { @@ -70,7 +81,7 @@ in type = "simple"; params.keep = "5"; }; - devices = [ "sync (@oracle)" "magicant" "${workHostName}" ]; + devices = [ "sync (@oracle)" "magicant" "${workHostName}" "moonside (@oracle)" ]; id = "hgp9s-fyq3p"; }; "Documents" = { @@ -80,27 +91,29 @@ in type = "simple"; params.keep = "5"; }; - devices = [ "magicant" "${workHostName}" ]; + devices = [ "magicant" "${workHostName}" "moonside (@oracle)" ]; id = "hgr3d-pfu3w"; }; - # ".elfeed" = { - # path = "/Vault/data/syncthing/.elfeed"; - # devices = [ "sync (@oracle)" "magicant" "${workHostName}" ]; - # id = "h7xbs-fs9v1"; - # }; }; }; }; - services.nginx = { + nodes.moonside.services.nginx = { + upstreams = { + "${serviceName}" = { + servers = { + "192.168.1.2:${builtins.toString servicePort}" = { }; + }; + }; + }; virtualHosts = { - "storync.swarsel.win" = { + "${serviceDomain}" = { enableACME = true; forceSSL = true; acmeRoot = null; locations = { "/" = { - proxyPass = "http://localhost:8384"; + proxyPass = "http://${serviceName}"; extraConfig = '' client_max_body_size 0; ''; @@ -110,5 +123,4 @@ in }; }; }; - } diff --git a/nix/sops-decrypt-and-cache.sh b/nix/sops-decrypt-and-cache.sh index b63f51d..e851db1 100755 --- a/nix/sops-decrypt-and-cache.sh +++ b/nix/sops-decrypt-and-cache.sh @@ -28,7 +28,6 @@ mkdir -p "$(dirname "$out")" # Decrypt only if necessary if [[ ! -e $out ]]; then - echo "authenticate:" agekey=$(sudo ssh-to-age -private-key -i /etc/ssh/sops || sudo ssh-to-age -private-key -i /etc/ssh/ssh_host_ed25519_key) SOPS_AGE_KEY="$agekey" sops decrypt --output "$out" "$file" fi diff --git a/profiles/nixos/moonside/default.nix b/profiles/nixos/moonside/default.nix index 7b4f267..f7d6385 100644 --- a/profiles/nixos/moonside/default.nix +++ b/profiles/nixos/moonside/default.nix @@ -18,6 +18,7 @@ sops = lib.mkDefault true; nginx = lib.mkDefault true; ssh = lib.mkDefault true; + oauth2Proxy = lib.mkDefault true; }; }; }; diff --git a/secrets/general/secrets.yaml b/secrets/general/secrets.yaml index 8eaf6e9..aa61880 100644 --- a/secrets/general/secrets.yaml +++ b/secrets/general/secrets.yaml @@ -26,79 +26,93 @@ gitlabforgeuser: ENC[AES256_GCM,data:SrQw69bvtYUcVSePCg==,iv:PlaTHDWJRMtf0HQCG/f gitlabforgepass: ENC[AES256_GCM,data:WvUFqQtBqqlWvUWhF7x46RcjqA3RPnKSgbd3ZIr1kHO+Vmh5zUh+LA==,iv:+n2VPdLdxFFVHlzRdMCi1lyqGLH+U3RRZX/qfs42I0s=,tag:1iBorR1N1HDRtrqcAcSmvA==,type:str] u2f_keys: ENC[AES256_GCM,data:jk1IDfO778V3MCQ8fGoO87lCmqj2Dw+vNRfT4JuWXZ6cB/ARYblnGIpEfogciXJbmYWc4MiKHcO2PkXFdCynpniU3pf3stvNYjTV/TdUpNXkAyho1OjBXwisOMFMcqF3I8yI/XpaMr+5aL6tyMLZ4wIsa0tP4FH74BxCt426uhH8YKLCXREaLRy2PFEQS2MVwKL8i41LDhrkVaJIEMZJ34rvHQqsjckjvwEtCHzBh8XVqdJXAKPq1EgR+9gTVhixwvceDsoSAC0/q2RkSfKhqhOFnj6e09GM7i+o1e98INyABHmd3OHxzTydYk6nrcJHFWIBZlushSgVI0qn+JL+e+2CF8NFtshHH7CGI7ws23n1DZz/BkjQtcfjZEnJv5uAZ9oOt4R0hOSpXn0rGQRNgo5JSMGR37ywyJlaDHmRolS6lRk/7pEdO3jCEMSwjjitWK1/iNDSgEExclQZ/cSL2svPZmwiTKrf0wm/+gbGrd+BxzJmHCopFyNG47kweyR7iMcknF/4+iJj9t2Mi+xOxYdqmQB+I6140DOqcMz9sA0tzqV+Ou6Jf4H4w9sqvI10pnw2sK7OuvFZQ442H+iLelRiZLA/ZCzDCieddLJBtqSsmgEJtJpRsiJXUzDn4CzaAFWrNvNaU/MKAAZwsPeJywmwKgjOUSdHz3YKVDhP/TDqvlzvjKYDte7+6baAYKjVNPJpMy4aQ4/m2FnUEcgRdwct3G8JCe1CORIZSFbO9fkgEgJK6WN3XyQn1nAcDGZdmS95O5Ajmj6a1f5nZQ==,iv:B/Nf1lS0gKW43Nq8QuwJD6GCzzvx35LBw1q1OmZMfF8=,tag:gVNKbyq514J1eoM03JoQYg==,type:str] sops: - kms: [] - gcp_kms: [] - azure_kv: [] - hc_vault: [] age: - recipient: age1h72072slm2pthn9m2qwjsyy2dsazc6hz97kpzh4gksvv0r2jqecqul8w63 enc: | -----BEGIN AGE ENCRYPTED FILE----- - YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBLbm9WeGd0U0NEMzhpTDhE - SzBpRG5Xc1VUeFdSaXRjMHBKNVltNTY4dHcwCm5DRzFSdG9ML2h2QVlYNm5pUC9Z - TTh4TDB2bjhWdWFNQ2ozN09sZWw1WTAKLS0tIDUrcHVmWUc3dkxSS3MrZXB6ZHNi - QzZVR3p2VlRyZjNqZk9ZTDBXOWdxYnMK3ZT951oj6lSP+3a1sQL88GUE/jlhfoWy - tkoKh2wNofg3BX9jMCgWm2LFcYxX1fMOoxhXxK2XNEV5et8gxHIxEw== + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSAybmk3azNkM1A0MHBJZElF + Y244UzIvQmtSWThPbksrVmNnVEErSldLM3hFCmUxZ3hNaTkxQStNNkwxV2pkdWEr + bVQ3U2kzL0ZlOGp1NDJIaTNMYVRZd28KLS0tIFFZUENYdkRIVW1Gb2pjMjdFcG5h + TGRYcFpicXpFdjU4ZEk4RVpnODdBVE0Kq/i8NDtYB3L+kBs0q3NYlzRa22mWG7hi + lZZtwXjxTpoWacZgkNnxr/YjiOZLV7wt22TpFSKew1sfs77HvosPRw== -----END AGE ENCRYPTED FILE----- - recipient: age16vzhcvz8tyxj8e0f47fy0z4p3dsg0ak4vl52ut3l07a0tz465cxslmhevl enc: | -----BEGIN AGE ENCRYPTED FILE----- - YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBiZTlsOG02b2h3a1FaVW03 - RTFHOXhnaU94elNxNU5jV3hYUWczS25NOGdNClFRYUdoN2pDeEQyenhyYTNDMGxE - U3Z1elFwVlRXNCtpSlF6TmNYMEgyem8KLS0tIHYrZjB2NVhUdFFXcmFVNnJyd3NM - eHpZOStRRWZROU9qd3FZUXU5amhsWjgKIx6s5IpwAkcdRgqjlmMqQTGgx7abZ7OU - C5BWpFIARLNUcBOKdORT8fT1m1EnmXKawxitVPHrhAJibvi9XuZIWw== + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBoQmFSM3lPRHN3eE9Gd0Jr + T2hVb2t2NTEwbVVlNGNhZFZCekRrOEVSbmlvClAra2pnS0NPTXE5aTArZnQrcXNQ + bVY2cnhUeCt0N1ZQRGNDYTZETDFMVmsKLS0tIDRsV1hDM05KcWRFbE5ITGttVk9u + ek8rTHZYenNzbXVVYnhIUU1DY3h3VEUK5iRHq7pIa4tbYo4mrFUwPT50CWzCLnqK + X8Je+8lzkrVZ/M4RNXlgFxyD62LHycOZx342KVVdgl2b8w83xVud1Q== -----END AGE ENCRYPTED FILE----- - recipient: age1zlnxraee6tddr07xn59mx5rdexw8qxryd53eqlsajasfhfy78fkq705dfg enc: | -----BEGIN AGE ENCRYPTED FILE----- - YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBsNm5GWTZabmx0Lzd4VFNH - cFRRYUpCeTMxQ01LOThNRzY1T1FiWmt2TUVjClNWbDBnQk9lSmE1MVhieXh0ZENw - TjN0NnZlTlFMYmoyRTh0NDJHWTRUU2sKLS0tIEVCZElydnI3V0pBQ205b1hqV1U3 - aDdsUWc0bkdrcFBZeHhFc3hHeGhvL3MKt1sJlwjY4zc07tIp6qihcGu8UMdgr968 - KYSO3fGr6XfRWwfzVb9h7FBsWK8ttar0tCK1JF9Hjjp0W9Oqu+AQGA== + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBoNGxsQU1wcFpIYUxLcnFK + bjhubFRxMGwzQlpqeWpIbnZBNTQ1cGxVb1M4CmNFTFlCczJMUXJpd09zT3phMHRm + OE9sRC8zQ3FDUXoraG9jNUFITHVOYzAKLS0tIEtPSmhVVFNRdEd3d1RobEZMUlhV + OU9tWkNlSTZWcVZZbk00SjkxSEFZeGMK9Uq8oBYa7TJiaSOv5AIfPqnfH+lM8jeY + QEvT/llQqNHo2h1PbzoCd0W+WN81/yVvWhweJUO5GcA4cqE0Ed15yQ== -----END AGE ENCRYPTED FILE----- - recipient: age16lnmuuxfuxxtty3atnhut8wseppwnhp7rdhmxqd5tdvs9qnjffjq42sqyy enc: | -----BEGIN AGE ENCRYPTED FILE----- - YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSB2cFFqMDJ5SUQrT1c0VHRH - MmhYbFJBcjZJTjlFNHBtTk9uWTl0dnNud0Q0ClJBVkhzWXNqdGZIWE9DR3pzMDdq - cXBwWWJKWlhwM2RVTCtHbU4yZjdCdVEKLS0tIEFwZFIzakNHT2ovNmoxUGtXTUFD - RVdWbGt0aHcrUGlNWTdUZ2xMa25mYlUKY6AOmHg9+ApJXeoyliXxvqtjwaVLSjH0 - 6cuZSd05iOSHpR2vbg9jvRiXKXBS6DSN/BoIn+JUif8jY8cTQCMqDQ== + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBYK3FyVzkwZEZLNU5hamMr + d0ViS3FnVHVjcEtYVlM3VFp5S2dlNXQwQ1EwCjQ5dmhJenpFZmt3aUZsM0J0UFJY + SXhNdHVRbjNYZ2YrYmF1QVVMS1hBbnMKLS0tIDUyRkhTSjVhUnhBTEdtNGNqS2Vi + cWIrcmxRUFpKM3V3d2ZwVm1STGlpSFkK+VMJXgzdehOUhdevVIfO68wo6VF0Lfj1 + gsHJHH6GmQbUsCt+F+fPaXUlrdN+BlCnk4ZMNKutTm2g4thAeiAeng== + -----END AGE ENCRYPTED FILE----- + - recipient: age1glge4e97vgqzh332mqs5990vteezu2m8k4wq3z35jk0q8czw3gks2d7a3h + enc: | + -----BEGIN AGE ENCRYPTED FILE----- + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSB4RVRBOHo0ekVGakVadHBZ + SWhKcDVjNHNUcGhlYkxkenovcDdpWUpwdFNzCkt6SlVCaHgxK28xQmtrR045T3Br + MEJjbXhKUTRSREV6YUo5d1RKenR2TUkKLS0tIHhnZW85VHRraWRXZjhWMHI4SUpD + SUp3cUNwN1NXaXpjSm05UkFCcGw2d00K7Ai/uCOnqonQCy20hNjV8YALVlFZFbac + C8QIpfo5FEiONRZNOB2tlr7+ziGC+1ia1DXRvobHOKzgVfmW0VP86A== + -----END AGE ENCRYPTED FILE----- + - recipient: age18quey88vge7xytclg2nuq4ncme86dg04lxwczqxczmdchnjg3p0saehsnh + enc: | + -----BEGIN AGE ENCRYPTED FILE----- + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBzeUVtUXZuTVl2SEhVMWdl + RTNsNU1pWmZVeTZ4YzR6RkVwSUc0YVo1VzE0CjNvKzl0QTROUEVnOWNObnFNLzRm + aStSOVIvNC8rOEE4WnRoUHlwV29hTFEKLS0tIG5NM1F5OVIwQUtraURRdW1hT0Ji + azY5dGFTUWhiQ083VlBzdVRrSmZFNTQKqoJy8eP+beb/86Dg7BLaYEmZJG2oMS/I + y1tSw+Ij5TfghzbtKcK++88L7ZPJLRocnKXftFbjutHNKmWW3+oW7Q== -----END AGE ENCRYPTED FILE----- lastmodified: "2024-12-18T22:08:25Z" mac: ENC[AES256_GCM,data:vU+7/VLEzwDOrScD/HTo9JBf4ixtmcBmjtSUEtaVHwZuPMJ0OpydwcBPYKvhvU6z9xNecCcuiY7beJ5sq7fnv8XY66TOZWq/2tTZPXdJwpfAyHqBhf7uoCiOmSl53tpWzUFbfT8fQQwjKmBO1079Op24WNWzG3w0i9BsoYTYrpY=,iv:9bLlRg28paoitcK1lFc4ipsgMVvr/zECNozwXU2qJTM=,tag:uRviXeIlwUnvJqHwWuoYcA==,type:str] pgp: - - created_at: "2024-12-24T14:59:46Z" + - created_at: "2025-06-14T18:15:57Z" enc: |- -----BEGIN PGP MESSAGE----- - hQIMAwDh3VI7VctTAQ//cov1yOeIduJaYdeIBJI50V7bh1XSLOQ9JG7xoYEDIiE+ - a8ud6HP7hD+EmAqMLXFL1A/H0ELds+5qvVv3N/F7e3nkPdB/8/DHoBwpndFQ+DVQ - wJDUfchB5edzpKxRB2LfKGKiOG+yQXu2gf9s19yIrsLF/P8pXwjBRv+O4VmNvanh - hGq/+jVGGyXw8q9hjKpKNozNfsLQy0vXUZSi7b+CB9Uu0pWig+eAj9jsKC3ah6qq - Ahokko8bbLgor4cOLpNI48CDwA2gWZ3FxNHS34k+dQddXCOUF8/WcCFq4iFpWUaG - o+ZhyNFfnx3xIybPOfDZTIVLL0vBQcSC4hQFQoJ1TILtnPhTOJl/oTCfNuZ2WUDQ - LeJvicx0tAB4N8Luvpx8wPYkm7CvhXzEfztAOZZNBps3FNDKcM5d/LfraxHvwVlP - jzWfdz9jLhZiGMyZmgk6E4mA0AD4jpntmr4bpH4qpIdw9UNSNxivGa5K13hctIe2 - RM33UetGvvJxvheBQKCgonozsnq0dmNIk1nFum4mb4eUKWM45yLqfLH5dhtmqGdY - 5D2o8fSH7Gmp2oba/+cFxYXn7UY3rKITpMCSAFrl0OofMn+xefHG4Tu1L95kkr2I - iqCOAPmdfHIFhLNX908LTnU36vocLAH6HvT18sx5b1/tfQlws974s53wLFX4m0iF - AgwDC9FRLmchgYQBD/95NdfcrvDd6SE30FsJEXmiQhAYMzw75TiDeD07MtadbFlW - xDylS9J9Ej5a95oWv1PGwIRpF0F0FRbcQZY610F+D5CQYYEh2VdYXTKrI+Bd2UrJ - HGhB7vd2wpgrgaApmfDyKfsyxZvmUrHEnx7wyYjk86qU+wv/qNf71QNCbgi/eLhp - bS+lWB1/QvbqTWi/M9uymmmR5x+vo8QYjlDZBsSn6ukm4YzwQaf8RBxMsPGE3PI6 - UXWmN9jNcHfkIisVY0JkFxsAwq/216f5V50xEPaaD48Dk5cO/QADdr8UsrNx9XZB - NWV9G44wl0UscXqWG/mpKDs7mnK4HsZSFF7VyYT6qq7ZySpGwN06WrfyGybYfjpn - AZ0IQlJW5dDtNpvLODDDJkSaMWSbe9LqIUHnbPIQHn3/bgk70wYCu7C9xhif+dzl - cczt8DASz1H9AnMquB4gamn2YdHK4UDgkOtmh0FhSkiw/XCJg+Mp5EpSShSofdnL - am8i4utT+8AOGCzEPeoQlRUGcwVmN4594SUhhXWk/bnrzxLkoz1PMD3LiD175CA8 - CQ37mmAVHirpgMQY6OoaEMRTe18Y96keHQOaAUYFD5fKjlS8dMes7r8Oe79vH1fQ - Gkb1o9/QZOa9M7dErP6bhfhlb4GUpdFfZSxVhL6x+Y55sC7Jax39B2H9TNoBqdJe - AUEbEnvgoh2J7hgYibS4eGKZcDJnb5k0jKLGY/mMEJWLsKHYtQN4JIgG2Yj0bCc1 - Xsv8AzgIAKtWxkl9E9CAb5dg4PB7yZDolFvnoKlcS0+4yqOWJZLjemu+ZwGGYw== - =pQM4 + hQIMAwDh3VI7VctTAQ/+JiUgauFwbjrUsmGPseQJMraVr3cILCN05ufXeZLWXeuj + ZJV+7IecJa4BpCtaMD/xhvXiH7KNjlvlbN04AOHX/gGgJ3mENxHGtNOPb41RBzrH + 5FK1icAGt8xaXi8VdEwEDitKhRBnP2VzVC8ETrD+aQjVQM5DkJtvijvU3i0qsDnY + Y/oE56IWhldeXZcsXylW8x3NfskGbOQQ4hOmRamvi5ubrfAVkMlbzCS01rXTP4tu + 8MMbHtjZZcAeWrsj3rzlRw8SG/GRubn3lEd5nI7gfxHzyK6uv4sdaapw+5Y1vjbv + hB0wESidhzheIQmKeuLGTe6S+RTo+G8RNIqmrMXawFdmBoexKMFtJMXCca4LNawK + TE2UWbniQqMX53XM31EW1MrkjvM325E0p5TWz3JcA3JPqkmTJQSyccuJizvf2Bdi + M6stq6RPl9n5feSJJSfROP1IX1+fpQOLfToOJpOm5MPCrm0YhY5h1uSTKemfVGkO + cV1B2SGkN+w80eEhUX/EskNagROZBHn5cuZXldCcBzEIsA4G2ZsIuVujXTcL8wmn + EL/HiEB6UQ8P5TrAREbNw6wOXVdlfkUovyfmI02NFL6wr0xY07a3Nn9qADKQzhpE + 5fFudXWe6mLx/bRcuhl2ozCBk9fTcVkb5SF43Pp5fmQKzKvqN8GjEHtdFrN5vfuF + AgwDC9FRLmchgYQBD/wNVDcCYqGdZ/J4wt7BEx3bG/QOkpacnQXGqo0Xv69BjOi0 + tOsylTe+Nqge2ImCgu2lNlOYMjfhHCcnLILdriZX0KpEiEM4lzbpB2ntm+p2wMjg + TqMhzupy7iPZbPg12rtr71Mc7pLYKn6DRTBYv+HsMY8E24T3bMnGPOn31VP1N+0k + U0rySjg6Tuqo/F1Usi5wMG/zvLqSTJ5Sev0tHj0K8yKcmoHmSy62SdkrOd5S9xBt + KtGqHmJrPnKKb84BdSQThp+WfK1E3Vmsj7bd4TdqYlvo2GWMBj/bV7CuCOQvonnB + x27GEOCoFOn4ySIyTn3LrqGOVyRmQBELLXXCQASwWBKeruh70GN1XsfPYVxBXjWQ + ydOTCZNqBufQzakUFdly6WyaBOr1m6p9rbW0icA17ot7tVqgC5DsvVkPlgqXgI1W + oMhq8KvURlsflLJJ8ovI4wrpNZfDmIXZiFGTSVRcdJF6jDEYbypN34IRi5Idf9rg + SsH3tSLemJG5FZdztmStGTX9zWnfsCk7ivqJJpIgj7feWIr3WD1Y9Rt9KRZpJ05c + zHnGaXJYLX378q6L03C3klBhGfzBLTikApo/dmEy3DMSgsrtQt5vF7B6w4aHd318 + Gn+neiFXDxOsUVA+nFKkEPSFVR3XKzWE3TeO8AYJ80KYoywDAqeB9//p/MefeNJe + AZlxqdyhUqqzW2/95RC7sznoU/zVYvQ9ORfZ1K85xjAvahGWn50q2w4OKIs/gLBE + W7s8fkHqU71bMp7Al6Mx6RFK67x3OM1srb+jAR1OCFy4WTqPDkW7bSbQTNsAkQ== + =NdF8 -----END PGP MESSAGE----- fp: 4BE7925262289B476DBBC17B76FD3810215AE097 unencrypted_suffix: _unencrypted diff --git a/secrets/moonside/secrets.yaml b/secrets/moonside/secrets.yaml index 1f208a4..e7f59ac 100644 --- a/secrets/moonside/secrets.yaml +++ b/secrets/moonside/secrets.yaml @@ -2,6 +2,9 @@ swarsel: ENC[AES256_GCM,data:AnxZLN+3ta2Dmg0=,iv:S25Xbbj5K3tWynO4/7XGRp/+XexxoUo dnstokenfull: ENC[AES256_GCM,data:z9gi0pwfbDyHkKw8rhiGOIlaLUzepAAxQfAH4esla2NkSCx/S0VAiQ==,iv:qtCE+V4vHImViCquHwUEADEzl6dj7PB16PoRqYEgQ6o=,tag:jVfWgt3cx+bpYeMuyesjrA==,type:str] swarseluser: ENC[AES256_GCM,data:s09lyp9yRPJaSsDXj19s1mosF3O39Fk7Eg==,iv:tVBEFqTQPreul617EU6CfBUhz3Fmt37VAi3GzezeEmA=,tag:9sbJ465VxKoW3/q6ju7hpg==,type:str] wireguard-private-key: ENC[AES256_GCM,data:z5TV66YW4FqBVi/3uyE+r9Nkx9vVUOEgwVBXxqi32pecR9dQyLHW9QtFF/A=,iv:+qpRvDlF5v7hQo/S2oYGQ1MDHnxT3yHny1S1SVCainw=,tag:90pIiVx1lSXsin0b2M2SeA==,type:str] +#ENC[AES256_GCM,data:u/O2rHXqOoTNpOSm,iv:hqhZC9R76P3sPkpQMximrvcTC15IM99QaRZErC9AIc4=,tag:wc2w7iwtfazlwWpnQJV63w==,type:comment] +oauth2-cookie-secret: ENC[AES256_GCM,data:cbNVAkBAWJCN4fLmkYUFhy8v9iE5fB30hFI3nTpZuVIFCnmXPBtlftI58Zg=,iv:q9xjUDOH9M4pW+9YB9dEYSqEu9gpsezbxcGbpORNljU=,tag:KoGNcssD608huewmHeJOxw==,type:str] +kanidm-oauth2-proxy-client: ENC[AES256_GCM,data:wUTfb0r9d7nRb1wmQEOjXwDTM8V56DmOGw==,iv:OMXiObgt4AbKmovT62+P99r0UzGELj37FX+lqW38F0g=,tag:lksIWm0cSLydTZvlxliXgA==,type:str] sops: age: - recipient: age18quey88vge7xytclg2nuq4ncme86dg04lxwczqxczmdchnjg3p0saehsnh @@ -13,8 +16,8 @@ sops: bURRem1aY203VW0ya0tZWUY3WTJLQ3MKonflaevgNP91G1cVgzoE6/K800kyG6BK Goe81HCYFfm86pzv5wV3/38j7fTZNeZnKwPFkMgEUueF1kA8J9V5CA== -----END AGE ENCRYPTED FILE----- - lastmodified: "2025-06-13T22:13:23Z" - mac: ENC[AES256_GCM,data:5iAnRO8VNMf9lg9vrxFROKlMBYOavxND0m7tY91IY7TNy3Hegms72iwFYsRYagOsdNj5udD+jLGGuJTS1thSzpeZJIzDRW8p+Lzr2KNk94aGJKGNnlKPDpthryDJJ/xLonTfovIpJQHPwG26FI2eIVGp1CUh9UXKGOqqZUDMwNQ=,iv:AzZsgeIbmd0xN8adj/hs+VtEFXYaKiXXeQi5kqRQ4E4=,tag:tG5/O4RPcy7wmsu0C2iQ/w==,type:str] + lastmodified: "2025-06-15T09:26:29Z" + mac: ENC[AES256_GCM,data:IcDG5eTj7QQQdsQ7/lhHpJL+L6s0XJltng5yvyG6/sEIRzy4lrUMeR/9BcEiAw0vgz1jWlZR8pNaWZJHc4lEOmMax8rfEhz/3IrWh7MxvCkSSp1Y+JE8xewxzDE57+tR7BxYXjyjmrbQ0C1kiDfUAMVrkXTmV7hA/eY2xFezxXg=,iv:mfyVv5QyRWbCFOmYDsdcmnb7TBFD+5RE84UYc9+j4Yk=,tag:47XAmRcoI2XdQNb2tsL/4Q==,type:str] pgp: - created_at: "2025-06-13T21:18:31Z" enc: |- diff --git a/secrets/repo/pii.nix.enc b/secrets/repo/pii.nix.enc index 9295802..152d9d0 100644 --- a/secrets/repo/pii.nix.enc +++ b/secrets/repo/pii.nix.enc @@ -1,5 +1,5 @@ { - "data": "ENC[AES256_GCM,data:1+srGBXtYZCAsE32yEhH+1Ab3uebTDITbY8oQDIDkrqNMSGpfFH8i9nS0gmGHD35CKxn+2da+LxzWd7cjDwPre92D5+1K55RzrvWHwnq/0gYdNqvJZGKyJ71HJyr0wPSjK5Ne+fOPiYw+L4vwVukPTJcJHhe7H58Ia6rItnvdBe/RmUbVkTuVB1WEG9AYN1paQorNobSdNTTSCSXRIGTSaQfjk0xJ8B2wOALOXHoxBFUGR0SXIdk9M1CJ48uYU4JQ/RQguB3fG+PAbFYwm8B53SCo9zEnfonwmnFVe27Qm3Lz275stI0NuQiHuSJrcaXVyBX+So7xKPAMI2AyzPVhCukanPZxYwWMtFBYn5jgGL4P3aidsoqo0u0+PdIAr7U3dcDrpTnCQHiX71mG5h3CpKIs2yRhHmcnI27EEpVQv6LilZBHjT8tMUeS7H0UJlWsyj7lDzVl2WO6d7TeA8nnrNH5YWVzsAKCIsjvFYwwIJhdLWaVK9aI2VXJQEJAhQLbBKZ5pJwajw4GpeFu0ISyqo/foIzvaGvnW2fuxWwLYeGDlzPrqogT5433kFEambwXbdHGGdzuYqiWMLrysE+3AEPpOhwFuDpncFgGkHoZV+gZVcpG8TRTmKD9W4IK37sJqDrGGeWxvB2+/HE6ZbQqU05tdbyjXdHsXvAXSnSrLwqXVrds1zYk3g0bKjlZSwCBwKOhGU7JKsq1eBvJ1NgvBl7+JWtpCYBjCGaWM5whqxEkW0MR/7Xxkf0d5X5SDJEVUC8zAABiagNRfbyH8uix4NZCQyJeSFqeYMMWbXr3Z2XGyPXuKKwZC+vK6Kd,iv:D3wUi87sNqZG33GGlDnB1msJF3xvy7dMqQ/8gE5fpZU=,tag:cBqADzZhfiMGMKCUGTpHUg==,type:str]", + "data": "ENC[AES256_GCM,data:+CYlqWYF5RJ8/uzhGEG5uA638DmLc9vCMwRBiBZVFkUzb7Ja+jAZ5GVy6Sxw5SwqJsmZEdqKdGCV2TzTO1vcDBixJlwQlCQcwFDdi3W7ZokzEMdOP03vgx5qgd3kwwe0fEuBS7byragm6rt4Vg3bkBa4uwq1cnQEjKmGa69UTaG0FScKHBeFkEHLBUwIPgH0H52JRQurd8eCF1MPYKNTulpta8pDFb/OuM11zjdNfxJaoqtTN7I0PvS/RHTTuLtuNOi3vv8rJ+PeR3xj3B6mgBwWAews7MdlyfTrgOMd9BWFgnRrWBK4WcPa9gfOgEF4A1jkrh7l23lRo1xpWZFYhGEOl/zVQn6KsPwKtS8VU1e7gLi8EOSUMMkBPyAMfGu0SpRDUwISU0joVzeEvOZ5CrteB683qUYf16jWWfAx1v/7/gr2H01UGOpUsc/z4CPv5jeYzr2mBEa76wSBqSm9KjDS4uea6bHMFvLyVGDwg+ljzM+L5sAMEOoBSY2Pojb3lZuOwve6NI9R6aRRoKbuhLyHgcIH6dk1Dc9+scvrOeDMbzp2oppqLfW2uiG6mTcfvE5leJxQeeUV23LXhZsCkK2+UU5JfVj9JWLp6EBZWZdpTjOHDrMUdPBJtXvrirUu4W1s3Ny36o05d0esav4m+qEhwJEO3iDSAMRzQMFGdZhQOKgAgqCXyg3wUh47qdx54SMeyyLhQIHkz9AmeCeYmALnOxGrUrNGfnytNvPOA41qlmwD4e4yLeiwAowuWnVfw7GC5UGU9O5/B42VWN4WdsNgY6SdjBaRUaotil/UuDVISTczcwI3+NWqLtC5,iv:WmrLJN951DRaXKDVi7KHURWRRRusPisETUy+BH5U6/s=,tag:u36D+o4sA94D5W7CmjAizw==,type:str]", "sops": { "age": [ { @@ -27,8 +27,8 @@ "enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBtU240VjVRZmJ5TGsrclJF\nRXRLbTRCZURtR0Z3d2E2eDNNeGRDODlXVEY4CllTeVFYbDJQWlRSS1RFLzAxSnlM\nZi9NU1c3cWo3YWRLcUJ2U2ZFWFBBVEEKLS0tIGtmZU9qSWdBT3RDeStaaFFDSWtk\ndkUzZXJwZUl4LzVxYXdidmxXRnNnclUKyAMZqCKSY/RQvTR4bbjLaPnGKwdBcHXc\nvtiVSrLdIdzMa6id/J07TJH5UesUmcp0wjU41MDa4aMBLy+cXhuBHA==\n-----END AGE ENCRYPTED FILE-----\n" } ], - "lastmodified": "2025-06-13T22:20:13Z", - "mac": "ENC[AES256_GCM,data:W+k2UGDwWcS7/rBZQZE8ruU7ma429CdzmbtINtLF2DGz7Ofzj2EwkrVQeEtbUt9k+psSzsxnXD9hnrPzjgId7DGXlKPG55kwL++zuPvAe6qvJ05UhRahJfxBgpD+xcBHkCkQjgQcafOXha+BRKq2u5iSbB6aLxHq0i30xOq/n0E=,iv:g8xtWd6nDCs6WWx1CQRQAFExGFH9YQmgGBzyQNS9q2I=,tag:b9tLJz/JOFnegPQR8h5Zuw==,type:str]", + "lastmodified": "2025-06-14T20:56:55Z", + "mac": "ENC[AES256_GCM,data:03b5V3zO7mmoP050rrgBaZqR7ik3eioW3PJt0dKab85zOaOXwyq22Ps7vftRV6tQ5S83dSXsAnXvYmdUQ3F3h0Z4zqHB680r1uJG24kJLik+9Pl1a8SwQFB0/yWCaXfKqCZhXIoektl83oBaoWFoCpTuOtYmdoF3rt2mVounIHM=,iv:vAzVQRgQyIMUbwWCG/r4n/QXP/67QN7B651tIzU4TpU=,tag:zcgKO/8g1VmhXHfU7XyeYA==,type:str]", "pgp": [ { "created_at": "2025-06-13T20:13:06Z",