From 48a734ed82596aee9c79fd63cbfdd1c66dbc7c4b Mon Sep 17 00:00:00 2001 From: "sascha.koenig" Date: Fri, 1 Aug 2025 08:43:04 +0200 Subject: [PATCH] first commit --- README.md | 0 flake.lock | 422 +++++++++++++++++++ flake.nix | 107 +++++ home/common/default.nix | 42 ++ home/sascha.koenig/AZ-CLD-1.nix | 1 + home/sascha.koenig/home.nix | 82 ++++ hosts/AZ-CLD-1/configuration.nix | 129 ++++++ hosts/AZ-CLD-1/default.nix | 8 + hosts/AZ-CLD-1/disko-config.nix | 39 ++ hosts/AZ-CLD-1/hardware-configuration.nix | 28 ++ hosts/AZ-CLD-1/secrets.nix | 26 ++ hosts/AZ-CLD-1/services/default.nix | 9 + hosts/AZ-CLD-1/services/gitea.nix | 37 ++ hosts/AZ-CLD-1/services/n8n.nix | 26 ++ hosts/AZ-CLD-1/services/outline.nix | 36 ++ hosts/AZ-CLD-1/services/postgres.nix | 66 +++ hosts/AZ-CLD-1/services/traefik.nix | 74 ++++ hosts/common/default.nix | 60 +++ hosts/common/users/default.nix | 1 + hosts/common/users/sascha.koenig.nix | 27 ++ overlays/default.nix | 21 + overlays/mods/n8n.nix | 25 ++ pkgs/default.nix | 4 + pkgs/my-package/default.nix | 2 + secrets.nix | 18 + secrets/hetzner-s3-az-intern-access-key.age | 11 + secrets/hetzner-s3-az-intern-secret-key.age | 12 + secrets/hetzner-s3-az-intern-secretekey.age | 7 + secrets/librechat-env.age | 30 ++ secrets/n8n-env.age | 31 ++ secrets/outline-env.age | 16 + secrets/traefik-env.age | 14 + secrets/vaultwarden-env.age | 443 ++++++++++++++++++++ terraform/main.tf | 28 ++ terraform/terraform.tfstate | 1 + terraform/terraform.tfvars | 4 + terraform/variables.tf | 22 + terraform/vms.tf | 135 ++++++ 38 files changed, 2044 insertions(+) create mode 100644 README.md create mode 100644 flake.lock create mode 100644 flake.nix create mode 100644 home/common/default.nix create mode 100644 home/sascha.koenig/AZ-CLD-1.nix create mode 100644 home/sascha.koenig/home.nix create mode 100644 hosts/AZ-CLD-1/configuration.nix create mode 100644 hosts/AZ-CLD-1/default.nix create mode 100644 hosts/AZ-CLD-1/disko-config.nix create mode 100644 hosts/AZ-CLD-1/hardware-configuration.nix create mode 100644 hosts/AZ-CLD-1/secrets.nix create mode 100644 hosts/AZ-CLD-1/services/default.nix create mode 100644 hosts/AZ-CLD-1/services/gitea.nix create mode 100644 hosts/AZ-CLD-1/services/n8n.nix create mode 100644 hosts/AZ-CLD-1/services/outline.nix create mode 100644 hosts/AZ-CLD-1/services/postgres.nix create mode 100644 hosts/AZ-CLD-1/services/traefik.nix create mode 100644 hosts/common/default.nix create mode 100644 hosts/common/users/default.nix create mode 100644 hosts/common/users/sascha.koenig.nix create mode 100644 overlays/default.nix create mode 100644 overlays/mods/n8n.nix create mode 100644 pkgs/default.nix create mode 100644 pkgs/my-package/default.nix create mode 100644 secrets.nix create mode 100644 secrets/hetzner-s3-az-intern-access-key.age create mode 100644 secrets/hetzner-s3-az-intern-secret-key.age create mode 100644 secrets/hetzner-s3-az-intern-secretekey.age create mode 100644 secrets/librechat-env.age create mode 100644 secrets/n8n-env.age create mode 100644 secrets/outline-env.age create mode 100644 secrets/traefik-env.age create mode 100644 secrets/vaultwarden-env.age create mode 100644 terraform/main.tf create mode 100644 terraform/terraform.tfstate create mode 100644 terraform/terraform.tfvars create mode 100644 terraform/variables.tf create mode 100644 terraform/vms.tf diff --git a/README.md b/README.md new file mode 100644 index 0000000..e69de29 diff --git a/flake.lock b/flake.lock new file mode 100644 index 0000000..fe7183e --- /dev/null +++ b/flake.lock @@ -0,0 +1,422 @@ +{ + "nodes": { + "agenix": { + "inputs": { + "darwin": "darwin", + "home-manager": "home-manager", + "nixpkgs": "nixpkgs", + "systems": "systems" + }, + "locked": { + "lastModified": 1750173260, + "narHash": "sha256-9P1FziAwl5+3edkfFcr5HeGtQUtrSdk/MksX39GieoA=", + "owner": "ryantm", + "repo": "agenix", + "rev": "531beac616433bac6f9e2a19feb8e99a22a66baf", + "type": "github" + }, + "original": { + "owner": "ryantm", + "repo": "agenix", + "type": "github" + } + }, + "darwin": { + "inputs": { + "nixpkgs": [ + "agenix", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1744478979, + "narHash": "sha256-dyN+teG9G82G+m+PX/aSAagkC+vUv0SgUw3XkPhQodQ=", + "owner": "lnl7", + "repo": "nix-darwin", + "rev": "43975d782b418ebf4969e9ccba82466728c2851b", + "type": "github" + }, + "original": { + "owner": "lnl7", + "ref": "master", + "repo": "nix-darwin", + "type": "github" + } + }, + "deploy-rs": { + "inputs": { + "flake-compat": "flake-compat", + "nixpkgs": "nixpkgs_2", + "utils": "utils" + }, + "locked": { + "lastModified": 1749105467, + "narHash": "sha256-hXh76y/wDl15almBcqvjryB50B0BaiXJKk20f314RoE=", + "owner": "serokell", + "repo": "deploy-rs", + "rev": "6bc76b872374845ba9d645a2f012b764fecd765f", + "type": "github" + }, + "original": { + "owner": "serokell", + "repo": "deploy-rs", + "type": "github" + } + }, + "disko": { + "inputs": { + "nixpkgs": [ + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1753140376, + "narHash": "sha256-7lrVrE0jSvZHrxEzvnfHFE/Wkk9DDqb+mYCodI5uuB8=", + "owner": "nix-community", + "repo": "disko", + "rev": "545aba02960caa78a31bd9a8709a0ad4b6320a5c", + "type": "github" + }, + "original": { + "owner": "nix-community", + "repo": "disko", + "type": "github" + } + }, + "disko_2": { + "inputs": { + "nixpkgs": [ + "nixos-anywhere", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1749200714, + "narHash": "sha256-W8KiJIrVwmf43JOPbbTu5lzq+cmdtRqaNbOsZigjioY=", + "owner": "nix-community", + "repo": "disko", + "rev": "17d08c65c241b1d65b3ddf79e3fac1ddc870b0f6", + "type": "github" + }, + "original": { + "owner": "nix-community", + "ref": "master", + "repo": "disko", + "type": "github" + } + }, + "flake-compat": { + "flake": false, + "locked": { + "lastModified": 1733328505, + "narHash": "sha256-NeCCThCEP3eCl2l/+27kNNK7QrwZB1IJCrXfrbv5oqU=", + "owner": "edolstra", + "repo": "flake-compat", + "rev": "ff81ac966bb2cae68946d5ed5fc4994f96d0ffec", + "type": "github" + }, + "original": { + "owner": "edolstra", + "repo": "flake-compat", + "type": "github" + } + }, + "flake-parts": { + "inputs": { + "nixpkgs-lib": [ + "nixos-anywhere", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1748821116, + "narHash": "sha256-F82+gS044J1APL0n4hH50GYdPRv/5JWm34oCJYmVKdE=", + "owner": "hercules-ci", + "repo": "flake-parts", + "rev": "49f0870db23e8c1ca0b5259734a02cd9e1e371a1", + "type": "github" + }, + "original": { + "owner": "hercules-ci", + "repo": "flake-parts", + "type": "github" + } + }, + "home-manager": { + "inputs": { + "nixpkgs": [ + "agenix", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1745494811, + "narHash": "sha256-YZCh2o9Ua1n9uCvrvi5pRxtuVNml8X2a03qIFfRKpFs=", + "owner": "nix-community", + "repo": "home-manager", + "rev": "abfad3d2958c9e6300a883bd443512c55dfeb1be", + "type": "github" + }, + "original": { + "owner": "nix-community", + "repo": "home-manager", + "type": "github" + } + }, + "home-manager_2": { + "inputs": { + "nixpkgs": [ + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1753288231, + "narHash": "sha256-WcMW9yUDfER8kz4NdCaaI/ep0Ef91L+Nf7MetNzHZc4=", + "owner": "nix-community", + "repo": "home-manager", + "rev": "7b5a978e00273b8676c530c03d315f5b75fae564", + "type": "github" + }, + "original": { + "owner": "nix-community", + "ref": "release-25.05", + "repo": "home-manager", + "type": "github" + } + }, + "nix-vm-test": { + "inputs": { + "nixpkgs": [ + "nixos-anywhere", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1748765518, + "narHash": "sha256-vftOR+7zwnMWl5UpG32GL1VBeNGTDZZT0hv+2uNuBGw=", + "owner": "Mic92", + "repo": "nix-vm-test", + "rev": "d6642fbaf42fc98883d84bab66cd0ec720d9dd0c", + "type": "github" + }, + "original": { + "owner": "Mic92", + "repo": "nix-vm-test", + "type": "github" + } + }, + "nixos-anywhere": { + "inputs": { + "disko": "disko_2", + "flake-parts": "flake-parts", + "nix-vm-test": "nix-vm-test", + "nixos-images": "nixos-images", + "nixos-stable": "nixos-stable", + "nixpkgs": [ + "nixpkgs" + ], + "treefmt-nix": "treefmt-nix" + }, + "locked": { + "lastModified": 1753176709, + "narHash": "sha256-nkfLkqFdV5XUV2fCibvkKpEg0c+s5UP6VErL4NWT4t4=", + "owner": "nix-community", + "repo": "nixos-anywhere", + "rev": "37cd5408a443cbba2e377d634e8b161b9a7af64f", + "type": "github" + }, + "original": { + "owner": "nix-community", + "repo": "nixos-anywhere", + "type": "github" + } + }, + "nixos-images": { + "inputs": { + "nixos-stable": [ + "nixos-anywhere", + "nixos-stable" + ], + "nixos-unstable": [ + "nixos-anywhere", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1749086071, + "narHash": "sha256-4+fY7i+q78F3t6APz0cMC4kRxsyCb+UTyfhbckkCd7Q=", + "owner": "nix-community", + "repo": "nixos-images", + "rev": "aa38dbbdf0e955baef7e03dfc4265ae3fdac4808", + "type": "github" + }, + "original": { + "owner": "nix-community", + "repo": "nixos-images", + "type": "github" + } + }, + "nixos-stable": { + "locked": { + "lastModified": 1749086602, + "narHash": "sha256-DJcgJMekoxVesl9kKjfLPix2Nbr42i7cpEHJiTnBUwU=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "4792576cb003c994bd7cc1edada3129def20b27d", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixos-25.05", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs": { + "locked": { + "lastModified": 1745391562, + "narHash": "sha256-sPwcCYuiEopaafePqlG826tBhctuJsLx/mhKKM5Fmjo=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "8a2f738d9d1f1d986b5a4cd2fd2061a7127237d7", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixos-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs-unstable": { + "locked": { + "lastModified": 1753250450, + "narHash": "sha256-i+CQV2rPmP8wHxj0aq4siYyohHwVlsh40kV89f3nw1s=", + "owner": "nixos", + "repo": "nixpkgs", + "rev": "fc02ee70efb805d3b2865908a13ddd4474557ecf", + "type": "github" + }, + "original": { + "owner": "nixos", + "ref": "nixos-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs_2": { + "locked": { + "lastModified": 1743014863, + "narHash": "sha256-jAIUqsiN2r3hCuHji80U7NNEafpIMBXiwKlSrjWMlpg=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "bd3bac8bfb542dbde7ffffb6987a1a1f9d41699f", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixpkgs-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs_3": { + "locked": { + "lastModified": 1753115646, + "narHash": "sha256-yLuz5cz5Z+sn8DRAfNkrd2Z1cV6DaYO9JMrEz4KZo/c=", + "owner": "nixos", + "repo": "nixpkgs", + "rev": "92c2e04a475523e723c67ef872d8037379073681", + "type": "github" + }, + "original": { + "owner": "nixos", + "ref": "nixos-25.05", + "repo": "nixpkgs", + "type": "github" + } + }, + "root": { + "inputs": { + "agenix": "agenix", + "deploy-rs": "deploy-rs", + "disko": "disko", + "home-manager": "home-manager_2", + "nixos-anywhere": "nixos-anywhere", + "nixpkgs": "nixpkgs_3", + "nixpkgs-unstable": "nixpkgs-unstable" + } + }, + "systems": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } + }, + "systems_2": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } + }, + "treefmt-nix": { + "inputs": { + "nixpkgs": [ + "nixos-anywhere", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1749194973, + "narHash": "sha256-eEy8cuS0mZ2j/r/FE0/LYBSBcIs/MKOIVakwHVuqTfk=", + "owner": "numtide", + "repo": "treefmt-nix", + "rev": "a05be418a1af1198ca0f63facb13c985db4cb3c5", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "treefmt-nix", + "type": "github" + } + }, + "utils": { + "inputs": { + "systems": "systems_2" + }, + "locked": { + "lastModified": 1731533236, + "narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "11707dc2f618dd54ca8739b309ec4fc024de578b", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/flake.nix b/flake.nix new file mode 100644 index 0000000..4f2b22e --- /dev/null +++ b/flake.nix @@ -0,0 +1,107 @@ +{ + description = '' + For questions just DM me on X: https://twitter.com/@m3tam3re + There is also some NIXOS content on my YT channel: https://www.youtube.com/@m3tam3re + + One of the best ways to learn NIXOS is to read other peoples configurations. I have personally learned a lot from Gabriel Fontes configs: + https://github.com/Misterio77/nix-starter-configs + https://github.com/Misterio77/nix-config + + Please also check out the starter configs mentioned above. + ''; + + inputs = { + home-manager = { + url = "github:nix-community/home-manager/release-25.05"; + inputs.nixpkgs.follows = "nixpkgs"; + }; + nixpkgs.url = "github:nixos/nixpkgs/nixos-25.05"; + nixpkgs-unstable.url = "github:nixos/nixpkgs/nixos-unstable"; + + disko = { + url = "github:nix-community/disko"; + inputs.nixpkgs.follows = "nixpkgs"; + }; + + agenix.url = "github:ryantm/agenix"; + + deploy-rs.url = "github:serokell/deploy-rs"; + + nixos-anywhere = { + url = "github:nix-community/nixos-anywhere"; + inputs.nixpkgs.follows = "nixpkgs"; + }; + }; + + outputs = { + self, + agenix, + deploy-rs, + home-manager, + nixpkgs, + ... + } @ inputs: let + inherit (self) outputs; + systems = [ + "aarch64-linux" + "i686-linux" + "x86_64-linux" + "aarch64-darwin" + "x86_64-darwin" + ]; + forAllSystems = nixpkgs.lib.genAttrs systems; + in { + packages = + forAllSystems (system: import ./pkgs nixpkgs.legacyPackages.${system}); + overlays = import ./overlays {inherit inputs;}; + + # Development shell + devShells = forAllSystems (system: let + pkgs = import nixpkgs { + inherit system; + config.allowUnfree = true; # Allow unfree packages in devShell + }; + in { + default = pkgs.mkShell { + buildInputs = with pkgs; [ + opentofu + openssh + agenix.packages.${system}.default + ]; + + shellHook = '' + echo "🚀 NixOS Infrastructure Development Shell" + echo "Available tools:" + echo " - opentofu: Infrastructure as Code" + echo " - agenix: Secret management" + echo "" + echo "Quick start:" + echo " cd terraform && tofu init init" + echo "" + ''; + }; + }); + + nixosConfigurations = { + AZ-CLD-1 = nixpkgs.lib.nixosSystem { + specialArgs = {inherit inputs outputs;}; + modules = [ + ./hosts/AZ-CLD-1 + agenix.nixosModules.default + inputs.disko.nixosModules.disko + ]; + }; + }; + + deploy.nodes.AZ-CLD-1 = { + hostname = "AZ-CLD-1"; + profiles.system = { + sshUser = "sascha.koenig"; + interactiveSudo = false; + sshOpts = [ "-tt" ]; + remoteBuild = true; + path = deploy-rs.lib.x86_64-linux.activate.nixos self.nixosConfigurations.AZ-CLD-1; + }; + }; + }; +} diff --git a/home/common/default.nix b/home/common/default.nix new file mode 100644 index 0000000..a2df9a9 --- /dev/null +++ b/home/common/default.nix @@ -0,0 +1,42 @@ +{ + config, + lib, + outputs, + pkgs, + ... +}: { + nixpkgs = { + # You can add overlays here + overlays = [ + # Add overlays your own flake exports (from overlays and pkgs dir): + outputs.overlays.additions + outputs.overlays.modifications + outputs.overlays.unstable-packages + + # You can also add overlays exported from other flakes: + # neovim-nightly-overlay.overlays.default + + # Or define it inline, for example: + # (final: prev: { + # hi = final.hello.overrideAttrs (oldAttrs: { + # patches = [ ./change-hello-to-hi.patch ]; + # }); + # }) + ]; + # Configure your nixpkgs instance + config = { + # Disable if you don't want unfree packages + allowUnfree = true; + # Workaround for https://github.com/nix-community/home-manager/issues/2942 + allowUnfreePredicate = _: true; + }; + }; + + nix = { + package = lib.mkDefault pkgs.nix; + settings = { + experimental-features = ["nix-command" "flakes"]; + warn-dirty = false; + }; + }; +} diff --git a/home/sascha.koenig/AZ-CLD-1.nix b/home/sascha.koenig/AZ-CLD-1.nix new file mode 100644 index 0000000..7e288ee --- /dev/null +++ b/home/sascha.koenig/AZ-CLD-1.nix @@ -0,0 +1 @@ +{ config, ... }: { imports = [ ./home.nix ../common ]; } diff --git a/home/sascha.koenig/home.nix b/home/sascha.koenig/home.nix new file mode 100644 index 0000000..8ad6243 --- /dev/null +++ b/home/sascha.koenig/home.nix @@ -0,0 +1,82 @@ +# This is a default home.nix generated by the follwing hone-manager command +# +# home-manager init ./ +{ + config, + lib, + pkgs, + ... +}: { + # Home Manager needs a bit of information about you and the paths it should + # manage. + home.username = lib.mkDefault "your-name"; + home.homeDirectory = lib.mkDefault "/home/${config.home.username}"; + + # This value determines the Home Manager release that your configuration is + # compatible with. This helps avoid breakage when a new Home Manager release + # introduces backwards incompatible changes. + # + # You should not change this value, even if you update Home Manager. If you do + # want to update the value, then make sure to first check the Home Manager + # release notes. + home.stateVersion = "25.05"; # Please read the comment before changing. + + # The home.packages option allows you to install Nix packages into your + # environment. + home.packages = with pkgs; [ + neovim + # # Adds the 'hello' command to your environment. It prints a friendly + # # "Hello, world!" when run. + # pkgs.hello + + # # It is sometimes useful to fine-tune packages, for example, by applying + # # overrides. You can do that directly here, just don't forget the + # # parentheses. Maybe you want to install Nerd Fonts with a limited number of + # # fonts? + # (pkgs.nerdfonts.override { fonts = [ "FantasqueSansMono" ]; }) + + # # You can also create simple shell scripts directly inside your + # # configuration. For example, this adds a command 'my-hello' to your + # # environment: + # (pkgs.writeShellScriptBin "my-hello" '' + # echo "Hello, ${config.home.username}!" + # '') + ]; + + # Home Manager is pretty good at managing dotfiles. The primary way to manage + # plain files is through 'home.file'. + home.file = { + # # Building this configuration will create a copy of 'dotfiles/screenrc' in + # # the Nix store. Activating the configuration will then make '~/.screenrc' a + # # symlink to the Nix store copy. + # ".screenrc".source = dotfiles/screenrc; + + # # You can also set the file content immediately. + # ".gradle/gradle.properties".text = '' + # org.gradle.console=verbose + # org.gradle.daemon.idletimeout=3600000 + # ''; + }; + + # Home Manager can also manage your environment variables through + # 'home.sessionVariables'. If you don't want to manage your shell through Home + # Manager then you have to manually source 'hm-session-vars.sh' located at + # either + # + # ~/.nix-profile/etc/profile.d/hm-session-vars.sh + # + # or + # + # ~/.local/state/nix/profiles/profile/etc/profile.d/hm-session-vars.sh + # + # or + # + # /etc/profiles/per-user/m3tam3re/etc/profile.d/hm-session-vars.sh + # + home.sessionVariables = { + # EDITOR = "emacs"; + }; + + # Let Home Manager install and manage itself. + programs.home-manager.enable = true; +} diff --git a/hosts/AZ-CLD-1/configuration.nix b/hosts/AZ-CLD-1/configuration.nix new file mode 100644 index 0000000..2f94b7f --- /dev/null +++ b/hosts/AZ-CLD-1/configuration.nix @@ -0,0 +1,129 @@ +# Edit this configuration file to define what should be installed on +# your system. Help is available in the configuration.nix(5) man page, on +# https://search.nixos.org/options and in the NixOS manual (`nixos-help`). +{ + config, + lib, + pkgs, + ... +}: { + imports = [ + # Include the results of the hardware scan. + ./hardware-configuration.nix + ./disko-config.nix + ]; + + boot.loader.grub = { + efiSupport = true; + efiInstallAsRemovable = true; + }; + + networking.hostName = "AZ-CLD-1"; # Define your hostname. + # Pick only one of the below networking options. + # networking.wireless.enable = true; # Enables wireless support via wpa_supplicant. + networking.networkmanager.enable = true; # Easiest to use and most distros use this by default. + + # Set your time zone. + time.timeZone = "Europe/Berlin"; + + # Configure network proxy if necessary + # networking.proxy.default = "http://user:password@proxy:port/"; + # networking.proxy.noProxy = "127.0.0.1,localhost,internal.domain"; + + # Select internationalisation properties. + i18n.defaultLocale = "de_DE.UTF-8"; + # console = { + # font = "Lat2-Terminus16"; + # keyMap = "us"; + # useXkbConfig = true; # use xkb.options in tty. + # }; + + # Enable the X11 windowing system. + # services.xserver.enable = true; + + # Configure keymap in X11 + # services.xserver.xkb.layout = "us"; + # services.xserver.xkb.options = "eurosign:e,caps:escape"; + + # Enable CUPS to print documents. + # services.printing.enable = true; + + # Enable sound. + # services.pulseaudio.enable = true; + # OR + # services.pipewire = { + # enable = true; + # pulse.enable = true; + # }; + + # Enable touchpad support (enabled default in most desktopManager). + # services.libinput.enable = true; + + # Define a user account. Don't forget to set a password with ‘passwd’. + # users.users.alice = { + # isNormalUser = true; + # extraGroups = [ "wheel" ]; # Enable ‘sudo’ for the user. + # packages = with pkgs; [ + # tree + # ]; + # }; + + # programs.firefox.enable = true; + + # List packages installed in system profile. + # You can use https://search.nixos.org/ to find more packages (and options). + environment.systemPackages = with pkgs; [ + neovim # Do not forget to add an editor to edit configuration.nix! The Nano editor is also installed by default. + git + ]; + + # Some programs need SUID wrappers, can be configured further or are + # started in user sessions. + # programs.mtr.enable = true; + programs.gnupg.agent = { + enable = true; + enableSSHSupport = true; + }; + + # List services that you want to enable: + + # Enable the OpenSSH daemon. + services.openssh = { + enable = true; + ports = [2022]; + settings = { + PermitRootLogin = "no"; + PasswordAuthentication = false; + }; + }; + + # Open ports in the firewall. + networking.firewall.allowedTCPPorts = [ 587 ]; + # networking.firewall.allowedUDPPorts = [ ... ]; + # Or disable the firewall altogether. + # networking.firewall.enable = false; + + # Copy the NixOS configuration file and link it from the resulting system + # (/run/current-system/configuration.nix). This is useful in case you + # accidentally delete configuration.nix. + # system.copySystemConfiguration = true; + + # This option defines the first version of NixOS you have installed on this particular machine, + # and is used to maintain compatibility with application data (e.g. databases) created on older NixOS versions. + # + # Most users should NEVER change this value after the initial install, for any reason, + # even if you've upgraded your system to a new NixOS release. + # + # This value does NOT affect the Nixpkgs version your packages and OS are pulled from, + # so changing it will NOT upgrade your system - see https://nixos.org/manual/nixos/stable/#sec-upgrading for how + # to actually do that. + # + # This value being lower than the current NixOS release does NOT mean your system is + # out of date, out of support, or vulnerable. + # + # Do NOT change this value unless you have manually inspected all the changes it would make to your configuration, + # and migrated your data accordingly. + # + # For more information, see `man configuration.nix` or https://nixos.org/manual/nixos/stable/options#opt-system.stateVersion . + system.stateVersion = "25.05"; # Did you read the comment? +} diff --git a/hosts/AZ-CLD-1/default.nix b/hosts/AZ-CLD-1/default.nix new file mode 100644 index 0000000..66a8eb9 --- /dev/null +++ b/hosts/AZ-CLD-1/default.nix @@ -0,0 +1,8 @@ +{ + imports = [ + ../common + ./configuration.nix + ./secrets.nix + ./services + ]; +} diff --git a/hosts/AZ-CLD-1/disko-config.nix b/hosts/AZ-CLD-1/disko-config.nix new file mode 100644 index 0000000..74cb823 --- /dev/null +++ b/hosts/AZ-CLD-1/disko-config.nix @@ -0,0 +1,39 @@ +{ + disko.devices = { + disk = { + main = { + type = "disk"; + device = "/dev/vda"; # CHANGE ME + content = { + type = "gpt"; + partitions = { + boot = { + size = "1M"; + type = "EF02"; # for GRUB MBR + priority = 1; + }; + esp = { + size = "512M"; + type = "EF00"; + content = { + type = "filesystem"; + format = "vfat"; + mountpoint = "/boot"; + mountOptions = ["defaults" "umask=0077"]; + }; + }; + root = { + size = "100%"; + content = { + type = "filesystem"; + format = "ext4"; + mountpoint = "/"; + mountOptions = ["noatime" "nodiratime" "discard"]; + }; + }; + }; + }; + }; + }; + }; +} diff --git a/hosts/AZ-CLD-1/hardware-configuration.nix b/hosts/AZ-CLD-1/hardware-configuration.nix new file mode 100644 index 0000000..7caa8fe --- /dev/null +++ b/hosts/AZ-CLD-1/hardware-configuration.nix @@ -0,0 +1,28 @@ +# Do not modify this file! It was generated by ‘nixos-generate-config’ +# and may be overwritten by future invocations. Please make changes +# to /etc/nixos/configuration.nix instead. +{ + config, + lib, + pkgs, + modulesPath, + ... +}: { + imports = [ + (modulesPath + "/profiles/qemu-guest.nix") + ]; + + boot.initrd.availableKernelModules = ["ata_piix" "uhci_hcd" "virtio_pci" "virtio_scsi" "sd_mod" "sr_mod"]; + boot.initrd.kernelModules = []; + boot.kernelModules = []; + boot.extraModulePackages = []; + + # Enables DHCP on each ethernet and wireless interface. In case of scripted networking + # (the default) this is the recommended approach. When using systemd-networkd it's + # still possible to use this option, but it's recommended to use it in conjunction + # with explicit per-interface declarations with `networking.interfaces..useDHCP`. + networking.useDHCP = lib.mkDefault true; + # networking.interfaces.ens18.useDHCP = lib.mkDefault true; + + nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux"; +} diff --git a/hosts/AZ-CLD-1/secrets.nix b/hosts/AZ-CLD-1/secrets.nix new file mode 100644 index 0000000..ac4329b --- /dev/null +++ b/hosts/AZ-CLD-1/secrets.nix @@ -0,0 +1,26 @@ +{ + age = { + secrets = { + traefik-env = { + file = ../../secrets/traefik-env.age; + }; + n8n-env = { + file = ../../secrets/n8n-env.age; + }; + outline-env = { + file = ../../secrets/outline-env.age; + owner = "outline"; + }; + vaultwarden-env = { + file = ../../secrets/vaultwarden-env.age; + }; + hetzner-s3-az-intern-secret-key = { + file = ../../secrets/hetzner-s3-az-intern-secret-key.age; + owner = "outline"; + }; + hetzner-s3-az-intern-access-key = { + file = ../../secrets/hetzner-s3-az-intern-access-key.age; + }; + }; + }; +} diff --git a/hosts/AZ-CLD-1/services/default.nix b/hosts/AZ-CLD-1/services/default.nix new file mode 100644 index 0000000..2d49972 --- /dev/null +++ b/hosts/AZ-CLD-1/services/default.nix @@ -0,0 +1,9 @@ +{ + imports = [ + ./gitea.nix + ./n8n.nix + ./outline.nix + ./postgres.nix + ./traefik.nix + ]; +} diff --git a/hosts/AZ-CLD-1/services/gitea.nix b/hosts/AZ-CLD-1/services/gitea.nix new file mode 100644 index 0000000..e57b48f --- /dev/null +++ b/hosts/AZ-CLD-1/services/gitea.nix @@ -0,0 +1,37 @@ +{ + services.gitea = { + enable = true; + settings = { + server = { + ROOT_URL = "https://git.az-gruppe.com"; + HTTP_PORT = 3030; + }; + mailer.SENDMAIL_PATH = "/run/wrappers/bin/sendmail"; + service.DISABLE_REGISTRATION = true; + }; + lfs.enable = true; + dump = { + enable = true; + type = "tar.gz"; + interval = "03:30:00"; + backupDir = "/var/backup/gitea"; + }; + }; + # Traefik configuration specific to gitea + services.traefik.dynamicConfigOptions.http = { + services.gitea.loadBalancer.servers = [ + { + url = "http://localhost:3030/"; + } + ]; + + routers.gitea = { + rule = "Host(`git.az-gruppe.com`)"; + tls = { + certResolver = "ionos"; + }; + service = "gitea"; + entrypoints = "websecure"; + }; + }; +} diff --git a/hosts/AZ-CLD-1/services/n8n.nix b/hosts/AZ-CLD-1/services/n8n.nix new file mode 100644 index 0000000..041e198 --- /dev/null +++ b/hosts/AZ-CLD-1/services/n8n.nix @@ -0,0 +1,26 @@ +{config, ...}: { + services.n8n = { + enable = true; + webhookUrl = "https://wf.az-group.com"; + }; + systemd.services.n8n.serviceConfig = { + EnvironmentFile = ["${config.age.secrets.n8n-env.path}"]; + }; + # Traefik configuration specific to n8n + services.traefik.dynamicConfigOptions.http = { + services.n8n.loadBalancer.servers = [ + { + url = "http://localhost:5678/"; + } + ]; + + routers.n8n = { + rule = "Host(`wf.az-gruppe.com`)"; + tls = { + certResolver = "ionos"; + }; + service = "n8n"; + entrypoints = "websecure"; + }; + }; +} diff --git a/hosts/AZ-CLD-1/services/outline.nix b/hosts/AZ-CLD-1/services/outline.nix new file mode 100644 index 0000000..df37b10 --- /dev/null +++ b/hosts/AZ-CLD-1/services/outline.nix @@ -0,0 +1,36 @@ +{config, ...}: { + services.outline = { + enable = true; + port = 3031; + publicUrl = "https://wiki.az-gruppe.com"; + databaseUrl = "postgresql://outline:outline@127.0.0.1:5432/outline"; + storage = { + storageType = "s3"; + region = "eu-central"; + uploadBucketUrl = "https://nbg1.your-objectstorage.com"; + uploadBucketName = "az-wiki"; + secretKeyFile = config.age.secrets.hetzner-s3-az-intern-secret-key.path; + accessKey = "CRT7V4HR5CG9NHICD2WW"; + }; + }; + systemd.services.outline.serviceConfig = { + EnvironmentFile = ["${config.age.secrets.outline-env.path}"]; + }; + # Traefik configuration specific to littlelink + services.traefik.dynamicConfigOptions.http = { + services.outline.loadBalancer.servers = [ + { + url = "http://localhost:3031/"; + } + ]; + + routers.outline = { + rule = "Host(`wiki.az-gruppe.com`)"; + tls = { + certResolver = "ionos"; + }; + service = "outline"; + entrypoints = "websecure"; + }; + }; +} diff --git a/hosts/AZ-CLD-1/services/postgres.nix b/hosts/AZ-CLD-1/services/postgres.nix new file mode 100644 index 0000000..2fd560e --- /dev/null +++ b/hosts/AZ-CLD-1/services/postgres.nix @@ -0,0 +1,66 @@ +{pkgs, ...}: { + services.postgresql = { + enable = true; + enableTCPIP = true; + package = pkgs.postgresql_17; + settings = { + ssl = true; + }; + extensions = with pkgs.postgresql17Packages; [ + pgvector + ]; + initialScript = pkgs.writeText "backend-initScript" '' + CREATE USER baserow WITH ENCRYPTED PASSWORD 'baserow'; + CREATE DATABASE baserow; + ALTER DATABASE baserow OWNER to baserow; + + CREATE USER kestra WITH ENCRYPTED PASSWORD 'kestra'; + CREATE DATABASE kestra; + ALTER DATABASE kestra OWNER to kestra; + + CREATE USER n8n WITH ENCRYPTED PASSWORD 'n8n'; + CREATE DATABASE n8n; + ALTER DATABASE n8n OWNER to n8n; + + CREATE USER outline WITH ENCRYPTED PASSWORD 'outline'; + CREATE DATABASE outline; + ALTER DATABASE outline OWNER to outline; + ''; + authentication = pkgs.lib.mkOverride 10 '' + # Local connections (Unix socket) + local all postgres peer + local outline outline scram-sha-256 + local n8n n8n scram-sha-256 + + # Localhost connections (IPv4 and IPv6) + host all postgres 127.0.0.1/32 scram-sha-256 + host all postgres ::1/128 scram-sha-256 + + host outline outline 127.0.0.1/32 scram-sha-256 + host outline outline ::1/128 scram-sha-256 + + host n8n n8n 127.0.0.1/32 scram-sha-256 + host n8n n8n ::1/128 scram-sha-256 + + # Podman network connections for Baserow + host baserow baserow 10.89.0.0/24 scram-sha-256 + host kestra kestra 10.89.0.0/24 scram-sha-256 + + # Deny all other connections + local all all reject + host all all 0.0.0.0/0 reject + host all all ::/0 reject + ''; + }; + services.postgresqlBackup = { + enable = true; + startAt = "03:10:00"; + databases = ["baserow" "kestra" "n8n" "outline"]; + }; + networking.firewall = { + extraCommands = '' + iptables -A INPUT -p tcp -s 127.0.0.1 --dport 5432 -j ACCEPT + iptables -A INPUT -p tcp -s 10.89.0.0/24 --dport 5432 -j ACCEPT + ''; + }; +} diff --git a/hosts/AZ-CLD-1/services/traefik.nix b/hosts/AZ-CLD-1/services/traefik.nix new file mode 100644 index 0000000..cfc35a1 --- /dev/null +++ b/hosts/AZ-CLD-1/services/traefik.nix @@ -0,0 +1,74 @@ +{config, ...}: { + services.traefik = { + enable = true; + staticConfigOptions = { + log = {level = "WARN";}; + certificatesResolvers = { + ionos = { + acme = { + email = "sascha.koenig@azintec.com"; + storage = "/var/lib/traefik/acme.json"; + caserver = "https://acme-v02.api.letsencrypt.org/directory"; + dnsChallenge = { + provider = "ionos"; + resolvers = ["1.1.1.1:53" "8.8.8.8:53"]; + propagation = { + delayBeforeChecks = 60; + disableChecks = true; + }; + }; + }; + }; + }; + api = {}; + entryPoints = { + web = { + address = ":80"; + http.redirections.entryPoint = { + to = "websecure"; + scheme = "https"; + }; + }; + websecure = { + address = ":443"; + }; + }; + }; + dynamicConfigOptions = { + http = { + services = { + dummy = { + loadBalancer.servers = [ + {url = "http://192.168.0.1";} # Diese URL wird nie verwendet + ]; + }; + }; + middlewares = { + auth = { + basicAuth = { + users = ["sascha.koenig:$apr1$1xqdta2b$DIVNvvp5iTUGNccJjguKh."]; + }; + }; + }; + + routers = { + api = { + rule = "Host(`r.az-gruppe.com`)"; + service = "api@internal"; + middlewares = ["auth"]; + entrypoints = ["websecure"]; + tls = { + certResolver = "ionos"; + }; + }; + }; + }; + }; + }; + + systemd.services.traefik.serviceConfig = { + EnvironmentFile = ["${config.age.secrets.traefik-env.path}"]; + }; + + networking.firewall.allowedTCPPorts = [80 443]; +} diff --git a/hosts/common/default.nix b/hosts/common/default.nix new file mode 100644 index 0000000..6e716d9 --- /dev/null +++ b/hosts/common/default.nix @@ -0,0 +1,60 @@ +# Common configuration for all hosts +{ + lib, + inputs, + outputs, + ... +}: { + imports = [ + ./users + inputs.home-manager.nixosModules.home-manager + ]; + + home-manager = { + useUserPackages = true; + extraSpecialArgs = {inherit inputs outputs;}; + }; + nixpkgs = { + # You can add overlays here + overlays = [ + # Add overlays your own flake exports (from overlays and pkgs dir): + outputs.overlays.additions + outputs.overlays.modifications + outputs.overlays.unstable-packages + + # You can also add overlays exported from other flakes: + # neovim-nightly-overlay.overlays.default + + # Or define it inline, for example: + # (final: prev: { + # hi = final.hello.overrideAttrs (oldAttrs: { + # patches = [ ./change-hello-to-hi.patch ]; + # }); + # }) + ]; + # Configure your nixpkgs instance + config = { + # Disable if you don't want unfree packages + allowUnfree = true; + }; + }; + + nix = { + settings = { + experimental-features = "nix-command flakes"; + trusted-users = [ + "root" + "sascha.koenig" + ]; # Set users that are allowed to use the flake command + }; + gc = { + automatic = true; + options = "--delete-older-than 30d"; + }; + optimise.automatic = true; + registry = + (lib.mapAttrs (_: flake: {inherit flake;})) + ((lib.filterAttrs (_: lib.isType "flake")) inputs); + nixPath = ["/etc/nix/path"]; + }; +} diff --git a/hosts/common/users/default.nix b/hosts/common/users/default.nix new file mode 100644 index 0000000..10669c5 --- /dev/null +++ b/hosts/common/users/default.nix @@ -0,0 +1 @@ +{imports = [./sascha.koenig.nix];} diff --git a/hosts/common/users/sascha.koenig.nix b/hosts/common/users/sascha.koenig.nix new file mode 100644 index 0000000..d54956c --- /dev/null +++ b/hosts/common/users/sascha.koenig.nix @@ -0,0 +1,27 @@ +{ + config, + pkgs, + inputs, + ... +}: { + users.users."sascha.koenig" = { + hashedPassword = "$y$j9T$ORX4btVZgs9Xjq2oIvzJm0$lXiPwaa0D6t.eMDIx1UBesEAMOkWXBoGwpeI7X0aS8D"; + isNormalUser = true; + extraGroups = [ + "wheel" + "networkmanager" + "libvirtd" + "flatpak" + "plugdev" + "input" + "kvm" + "qemu-libvirtd" + ]; + openssh.authorizedKeys.keys = [ + "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIEZbg/Z9mnflXuLahGY8WOSBMqbgeqVIkIwRkquys1Ml sascha.koenig@azintec.com" + ]; + packages = [inputs.home-manager.packages.${pkgs.system}.default]; + }; + home-manager.users."sascha.koenig" = + import ../../../home/sascha.koenig/${config.networking.hostName}.nix; +} diff --git a/overlays/default.nix b/overlays/default.nix new file mode 100644 index 0000000..b838222 --- /dev/null +++ b/overlays/default.nix @@ -0,0 +1,21 @@ +{inputs, ...}: { + # This one brings our custom packages from the 'pkgs' directory + additions = final: _prev: import ../pkgs {pkgs = final;}; + + # This one contains whatever you want to overlay + # You can change versions, add patches, set compilation flags, anything really. + # https://nixos.wiki/wiki/Overlays + modifications = final: prev: { + n8n = import ./mods/n8n.nix {inherit prev;}; + # example = prev.example.overrideAttrs (oldAttrs: rec { + # ... + # }); + }; + + unstable-packages = final: _prev: { + unstable = import inputs.nixpkgs-unstable { + system = final.system; + config.allowUnfree = true; + }; + }; +} diff --git a/overlays/mods/n8n.nix b/overlays/mods/n8n.nix new file mode 100644 index 0000000..5c5d70e --- /dev/null +++ b/overlays/mods/n8n.nix @@ -0,0 +1,25 @@ +{prev}: +prev.n8n.overrideAttrs (oldAttrs: rec { + version = "1.103.2"; + + src = prev.fetchFromGitHub { + owner = "n8n-io"; + repo = "n8n"; + rev = "n8n@${version}"; + hash = "sha256-jCIvhQMRHmhaZKIr+zGQ18s1dChUoGE6gsUzknhCvHE="; + }; + + pnpmDeps = prev.pnpm_10.fetchDeps { + pname = oldAttrs.pname; + inherit version src; + hash = "sha256-LierbGPkVIy5/2vtBl94TQcSpmNX9OUDMntDdo5BeiU="; + }; + + nativeBuildInputs = + builtins.map + (input: + if input == prev.pnpm_9.configHook + then prev.pnpm_10.configHook + else input) + oldAttrs.nativeBuildInputs; +}) diff --git a/pkgs/default.nix b/pkgs/default.nix new file mode 100644 index 0000000..cac47f9 --- /dev/null +++ b/pkgs/default.nix @@ -0,0 +1,4 @@ +{pkgs, ...}: { + # Define your custom packages here + # my-package = pkgs.callPackage ./my-package {}; +} diff --git a/pkgs/my-package/default.nix b/pkgs/my-package/default.nix new file mode 100644 index 0000000..fe6ef0f --- /dev/null +++ b/pkgs/my-package/default.nix @@ -0,0 +1,2 @@ +# Your custom nix-package +# ... diff --git a/secrets.nix b/secrets.nix new file mode 100644 index 0000000..e89c49a --- /dev/null +++ b/secrets.nix @@ -0,0 +1,18 @@ +let + #SYSTEMS + AZ-CLD-1 = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIItSijmU5YwcJcoshtmYxpxBaVA4TPaCMk23ws7KDkAH"; + + #USERS + sascha.koenig = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIEZbg/Z9mnflXuLahGY8WOSBMqbgeqVIkIwRkquys1Ml"; + + users = [sascha.koenig]; + systems = [AZ-CLD-1]; +in { + "secrets/traefik-env.age".publicKeys = systems ++ users; + "secrets/librechat-env.age".publicKeys = systems ++ users; + "secrets/n8n-env.age".publicKeys = systems ++ users; + "secrets/outline-env.age".publicKeys = systems ++ users; + "secrets/vaultwarden-env.age".publicKeys = systems ++ users; + "secrets/hetzner-s3-az-intern-secret-key.age".publicKeys = systems ++ users; + "secrets/hetzner-s3-az-intern-access-key.age".publicKeys = systems ++ users; +} diff --git a/secrets/hetzner-s3-az-intern-access-key.age b/secrets/hetzner-s3-az-intern-access-key.age new file mode 100644 index 0000000..30610c6 --- /dev/null +++ b/secrets/hetzner-s3-az-intern-access-key.age @@ -0,0 +1,11 @@ +-----BEGIN AGE ENCRYPTED FILE----- +YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IHNzaC1lZDI1NTE5IFpoVnNlZyBDcUZI +aCsvQzBoaytUZ0NpRVY1NW1WV0dyMXVjVnowZ0FlQkNKeDU4ZzBnCnVzcElPTXVm +QjQ2MjA4YlNYRjF3dmtpUFliMWJIMVJYWkx3Z2tsTzhXeVUKLT4gc3NoLWVkMjU1 +MTkgQ1NNeWhnIFZZQ0ZTemdKTno5UUpuRjF6UENydjRtNGZnWWtRRVlLWUhPOXZL +YlpzRmMKem9yUDY2eFhBNGpVbnlibmw5K0FkSElGdzR3Rnl4VEpxUUtxTGs1ZFBw +ZwotPiB+LltMYj0ldC1ncmVhc2UKSE9TOFo1T3E4WFo0Z2hHS0hBTmJkRDQ2a0J0 +NW9qWXpCcncKLS0tIEdzKzR3WW9rZnpvTDdKQndqN1VBTWxMY1hidkhXWUZoTWhh +bE9RM1dnY2cKeguIFY/T8kg7t6pDHyCVSdx88fbkCbefaHkLT3ZeLFlEeyIxvvrv +HTgpP0kje+G9jKjku7Q= +-----END AGE ENCRYPTED FILE----- diff --git a/secrets/hetzner-s3-az-intern-secret-key.age b/secrets/hetzner-s3-az-intern-secret-key.age new file mode 100644 index 0000000..402e5b1 --- /dev/null +++ b/secrets/hetzner-s3-az-intern-secret-key.age @@ -0,0 +1,12 @@ +-----BEGIN AGE ENCRYPTED FILE----- +YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IHNzaC1lZDI1NTE5IFpoVnNlZyByQU9Y +UUdPWmxxSTZ6Rnd3K2V4Q0NQMnRkUXhvQkg5NUMrNVI0YmJ1NDE4CnJpQkZZNFVj +SWw2ZVdKV08rd3poZE5vaVBNN2R3bENBOGp3a2JIdzFNdE0KLT4gc3NoLWVkMjU1 +MTkgQ1NNeWhnIEkzWGkwVDBkNkw5S0VWbVFlYzN2OWM4dWJZQm5NakdsWUlTaGNa +Myt0ZzQKZ0dWQy9JaW1YOVdoZVU1T0ExUm4vaEcvRXFGS3ZDVXE2N21ySjI1S0dY +WQotPiB3dzxrLWdyZWFzZQp5R0tXWjBJelF0NFk2MlF1c1ZrdHlxWWprWkN2Mlc2 +SVVmSTRMSENOVnNVUWFJVmhtL05VeWNJZE54TWFTdm1tCkVTUVQKLS0tIGZ6M1JS +aWlmeFQydERNS2ROdnBGa0U4anFOVzdITStyblZQeDV3VVFSWUkKXRiSMZZLMcrq +gCXaaUBC4GtG21xSqqsD3MoBNJ+V2XzWC8UFFo8sQiJQB1Pak/CiicRnFkyEbj7m +qAfbhKEAroS3kErgbL9w5w== +-----END AGE ENCRYPTED FILE----- diff --git a/secrets/hetzner-s3-az-intern-secretekey.age b/secrets/hetzner-s3-az-intern-secretekey.age new file mode 100644 index 0000000..07d8b3a --- /dev/null +++ b/secrets/hetzner-s3-az-intern-secretekey.age @@ -0,0 +1,7 @@ +age-encryption.org/v1 +-> ssh-ed25519 JqYQjw U5No3H94fSASBcRRZLgTBHxByB95Ziyf4PF2zyrjWhc +IbrSOSlaCOphRfXDGkrXONxqZMKd7wQTbeR/C1MWvOg +-> ssh-ed25519 CSMyhg MW59VNnTF2MEGytjYT1opGF/W3gwmmtnt6njTKbu0gQ +KSnptKwX5I3b5fNMzYE1dMcklmqM+Mehm8zdcjIOKTM +--- F50ScuHxKrtaxMrBPi8yNGPbLThR0nYZoneOCN6vhhY +]pkxuQu6*E)i-)ߧA(m^O \ No newline at end of file diff --git a/secrets/librechat-env.age b/secrets/librechat-env.age new file mode 100644 index 0000000..79b0528 --- /dev/null +++ b/secrets/librechat-env.age @@ -0,0 +1,30 @@ +-----BEGIN AGE ENCRYPTED FILE----- +YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IHNzaC1lZDI1NTE5IFpoVnNlZyBBN3d1 +NS9RQWw2VUM1QysrQ0dNQ0h1RHd0bnU3OTE2TDlKeEQ3d1lKazNrCnM4NHozM244 +Ym13WVV2bVl0cVJaOUlzR1lyTklHWTZFUnROMHJmeXNnekUKLT4gc3NoLWVkMjU1 +MTkgQ1NNeWhnIFlxNGthM0JzQU9kdGxJR0gvL0NSQW5aMFFvWmRuYk91WDh0UHhv +RCtsQlUKUndkZUpaNm41MjZHR0pNajRVbnNyaUNld0lVN3E0TkFVL3FWenBPc2t2 +awotPiByIidnKi1ncmVhc2UgRyBoIGBiClJkYXFaT2dKdUdpQlYySUh2MkxzUWhq +UlloTEdOeE5LUzc1TwotLS0gNytOS05WWW91T0pDbk5sZFVmOW1Za0RiZmpucnRm +VEZZV3JLRm5YMHh6WQp6c7dlv1yOwJJW6/ShUQxszI9OZ61EJFOgRLpS12MAEo9F +ZEsGrHN2NpQB6m0G920kz1dZlURcDWbzrKFPWGJbrAnGbmKsOejfx8B41H6aEode +/0cHdTndj+Ev4SJZ9AAYpJR3shOGy/0165IBWBejw6hNs1pEfQ1JxMszleVMenYh +jArOrsYaMWLzd2jgfc2eQm0LiAHDYeE8A/ozwcUMB2FQhcCXxVmhIgEuq882lRTz +DAHWASCXqg7hG0J1RZ5J29xijEKlGJ8a6seS0ZFeQy39of9FCp4TJaslsukRlJ/b +rMWb0S0sNbakDXF+gZL6TBs5D96460eg9+Z6pv4bjeuiGJW2Pn4n3odXqwElDekx +FmHGn9YbUd/7xb/fu+b/UmN1MPXEetEt1mAc4QyjywRrZ4mTq3sxWCjhIdv2oNaS +Fq9RMOB5JDbTujvQHImnJoiLOQWTrHP1O2oYFqp+RF5+R5yfeRW4NVG3Jqp8BJJ2 +YUDg2vpXUzDZU4aLZVdIKV2LIAlKdU3azkVaFbYhaaSYIs7jIj7Eu8N2b8v6sgaJ +wqAo0nEnLj+oqy9Sz+K1GwermTIRTNgcdI9vbLQ4b5LQfYREIeXfjvTLioBbHfs+ +u0PAblOJjrytNLpLKbdoEfVCqsOg4VnqkDP5hXtbxLZgOmIqpVDAW6cO/kpuifAk +ABqMrzwLw/mOKPGHnUSul0ysU+Xn35kKC5cyxV+IGrO+AHG3SGQUBTBrsuYuM3W/ +2D9Y668udq/ljpprhwy6rxWRqFk7teaYPMhWqw5KAlt69bZgElT6ndrgruxzCV0h +CLoXjgziFG0BrYexQOio9+IsSxXlSq524+RMI50SljD1wIvXemMxn2qO4Sc38aPQ +xlceF76TMBS0+1UCFxnkRRO35YABoW3jsFGkImhXqAvyf/k/HCFECKr1eqkv2d/q +Lz+7LJ5+l4oFUrmKk8+t4uXhMvdADZwIwqISLccjSkxv5ysBRdhqqrFsPiCXTlN8 +H505chs3Dh9u5nBNK7PlU7FzwGREzao0gHraSJ/BuHDwSo8shDMh+MZ9hcSZRIzY +Q3eo72UI4mXfihXvHfrCk0ZfnvA1bNpclKrev1sNgVDm7Rg8bNBJy9E+4AamXbxq +Gfss4/SugPB6D0/OpxNcZPK4KkFWf+HyG5nnWPWh3tJFvx4yGxGZEpyXzhTWMTIz +eKq2G1UHph37nLNhFl6+uf1xMCnDKxefo6X+7fOTL5EfGMuYsSDVxEA+3RSudTUY +rWyfPUPlQPeQ89umw5S5PDv7Unku1+FkYsSRUzfPtJU9auatJrIVmw3y4Q== +-----END AGE ENCRYPTED FILE----- diff --git a/secrets/n8n-env.age b/secrets/n8n-env.age new file mode 100644 index 0000000..aa7897e --- /dev/null +++ b/secrets/n8n-env.age @@ -0,0 +1,31 @@ +-----BEGIN AGE ENCRYPTED FILE----- +YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IHNzaC1lZDI1NTE5IFpoVnNlZyBFMjc4 +cnlwYXdIbmJqVnAxbmVTSGpsZy8za2h4T0pKNjQyQVNlTjhqdVZVCjV2M2pPL2RC +N1dheUViYklkTUEzMjgwb0w2OEZsMFNBMlhsaEZhdC9Ka2MKLT4gc3NoLWVkMjU1 +MTkgQ1NNeWhnIFFjbk9Ed2FTSEJmRFNFKy9LbW4yVGlWdklQZmdaR2xyaCt4SW50 +VlZybUkKNlFUNW5EWW5CL3FzOGVzeUhjUVVoWlFHdGl1UHZLWDhicHVndVI2Q2VG +ZwotPiAqJC1ncmVhc2UgPGchOyBtN1VyIDpdTyA7aXcKN3FzMHdDQkRWQytCNmFP +RmZoUUdpdkJPVlJ1NGRtc3hOYzR4YzY5RnlnYlMwazFOemc3T0J3ZVJCN25QQmdD +ZQoKLS0tIDVOWmpBcmZVUHc1YjFJclZNSElkbEwxd0EwZ3JmTFZNcE1QODhJdVN2 +OHMKdzJLI+r7Tl+p8xEsaHqOgLpuxEu4pO+9ElNGrAjgp+jx/kZ4tadz1juPIWNy +sk+bb6CoviBcMC1FYenOdW5/d0REpfrIxsACJqubZ9foFpCTwran9qsYEID4OHf5 +jvm5w/CHQhTupX0Zt+GloIrJ47892zqTHosKxr52EU//Vs+vsU1rWLNRMghUDax/ +p/8lAKDmTcbgGRDYYg20ZEDJCuAJfPKBMqIKX/qwF+vIPJu3L7RB6iKNEEOAKYK/ +zBGKAM6MAPewJR0se3sgbI0abMYT/6vmbUHNPJo26rB1P0hLx3vKCWpXtpedbse8 +0z5bYMlB1DLQ1HXYERCgd99P80IDoApEhGpGZOA41vCsJKNDaDuZEOmQcHP2Ex8+ +Uy9hV8YKbPc2+Hjsce7H0K3YAzNeOc/SK7jT3CGubMHJmTVnXEPLBTAdxmNxCpay +z9VqGSFscJ6/rUGPgdfgjnv1lyjNsIuwj9StEhmKEQdPSUcWyr6jBJtwXecz7eGD +pk96CNTxmokRFzKeQUYBPpXwGaeJV6vnAIQNPm0p4Yq0GEe1hlrf8zuXQIdBStKI +os/bh6skewhg/SxnxhYLxNup+eopZbyoHCLR4kTr49dioB6ZH7A8vl/tBefTBVfc +MmVjea7JmfQC+Oehm0hJwMluv1/1ygSIpoVEC1DkrTgQH+0A28L/xfhgkZIKyvO0 +45wihm5wlaYznbxR3Kc7MQ7K8FqiONSraEi9G545x4xQ0BRPecD8/0ce04Ff3bCS +ewPcxazKixW6nAbM1JTYRWQ9ZQvTBXKq2cksZL6ytHC/qa6AQ6JQ31CoSqTpe+mk +MwS5qPtAKn3rQT+LmTFVVLWRIUWSaJq2IqNuzbYlpfrwHh/IAQLXT/TtCljXNQHO +nTKDN5QghtHTL2lOW2FJRsi3gHAbsuPX617+iB+cYz6ZycZUvQn5cm1spCx0IxBc +NCwzviD8SoE9rxizRJmwCqM0ALcqWgI3y8iSvmdWaq/ZBxH2j3G0nF9Duh0aeCFd +kB2H5Vdtse99sd1Ue9z8PC8/5dXtwLDyiju9ileOL8H5ir5OO5rb+uFpKTPIips1 +7dF5hV0rCzty8QbGpmAv3hE+Nb53FRtq+jIPSyT730Vq6dHfhrZ+f4HzrygDWZlj +8X8+LHYtxHianS6JEdF2rKPiZUOpML9ZQbcd5ASUxGiBLE9t0DB+tCRYEH2WZ/N7 +uHMwMxKlhq0J9Kk1UWrvV0utsLT2EfmMIE6p5o89/Vt6V7X31q19fh48XsveEZjR +q+bSAHviV1FuX34= +-----END AGE ENCRYPTED FILE----- diff --git a/secrets/outline-env.age b/secrets/outline-env.age new file mode 100644 index 0000000..5e93a2d --- /dev/null +++ b/secrets/outline-env.age @@ -0,0 +1,16 @@ +-----BEGIN AGE ENCRYPTED FILE----- +YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IHNzaC1lZDI1NTE5IFpoVnNlZyBKRXcx +MzcxcWdrREpWTVo5a3Y1TW1FZmJkMmNVNFM5Z05mTWk1c0VnRHhvClhtdTdvN0NO +NWVZeGZTM0lHcGdnSDZ5c05vYXpJVDRSVndZaXdmditOaDAKLT4gc3NoLWVkMjU1 +MTkgQ1NNeWhnICs1bWpjdW56ZDJVQTVxK0wxOEl5RW9Hd2R0Z0pZL1gzWEpoQkZK +ZFRNQk0KWm8vQlllV2J4S2tjTlcvL3RvTnNuSVBUMlpyZnlXOFkvVnlIT0dFVmE0 +OAotPiBpNC58LWdyZWFzZSB0JXo9RCA3fVdUPEE9fgpSRDdndS94Tk10N2FNL3pG +SjBLeTJ5czRxY0FCRCtQZ2JLbHBtRWRXOW5CaGRieU0yUStLdHhEaWNxb2ZtUHdi +Ck5ERQotLS0geFZpL2NyR2dNZzVPazBqblN5VUtQWXFvdjlYMmFCMVgrd0JrS1U3 +bStsRQp8s8bZP4++MwDN+2M5n+dLDX5ykgfUIW9/2naqoKl1vT5+ODbklh4G9Y07 +vLI8Lq8BFyNLLDG+Xl1CKMRwXtnQBptLJzydr0kQgvpk8NmY5iFGPbeAKODYsTaO +eC5qka+VRhNslr8DTYb0nD5Pmj1itIgQMt+IqBKGEbOhhFIXdO+1iMqM354P4aSU +n6q6vpO8AZl9ual+pUe9vSF3yMcumBTtPA0OnR7LVZ+ca1pQd1zebcz56Ek81ty3 +sWSGccwYXWjmcwTcrgucnJ03zJxGObWFuXgt87SJ9zicQYgzAWh+Pj96XvXJPcX2 +p75C9IF/YCH5CSS01duhGdPCc8R2TxivBXSLl8qYRUN/xZYevflqJfOp +-----END AGE ENCRYPTED FILE----- diff --git a/secrets/traefik-env.age b/secrets/traefik-env.age new file mode 100644 index 0000000..a2c93f2 --- /dev/null +++ b/secrets/traefik-env.age @@ -0,0 +1,14 @@ +-----BEGIN AGE ENCRYPTED FILE----- +YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IHNzaC1lZDI1NTE5IFpoVnNlZyBvcTFw +MDNOR1g3dWZtU1VKekI3T2xtSXBEekJNZk5VY2NRK2lIZEhEdVdZCmF5K2l0WllL +RnF3R3hCbTUyNXdZU21tUjV3UWdFdHI4OHpwUkJ6ZWwydkEKLT4gc3NoLWVkMjU1 +MTkgQ1NNeWhnIHlyYnBOSldmaVNsT0JRV3p5US9NcWVmZURRd1dEMUkwcW5FSXI4 +dmVkRFEKUmpqMnk2bXV0ZGxhTWtCdVRLSmZiTTJuRlVHMERwdmVPMU55Y0c1UUVh +WQotPiA9LWdyZWFzZSAvVm0lNG1mQgpSNllHcWxETis3SlJrNytqdDZoWlByUDVC +dnRRVVdidXU1eFVEVm1ZQmp0VTBCc05ldjBFCi0tLSAyQ1pHK2IxVlNGWW1VZnpi +cDN0VlVxS280eFduUVNnUFhFV1hNUHdsNGw0Cj8HCx5FpmeZ+mxv3L+XiP4glOxf +WB2Dmf7V9V8bMa2HP1MLlpSX0j6W4LxwOCAaLOERjD9hJ4wtqP4kNLRWtpfzt9X0 ++0UdTzfW0kRzDz9e5FFtybMO+qtllh9W71NEKdsw0YkO+4nimFamMh+TagJWMO6/ +Pv8xpYtPRZEm0ThV33d0d45bbRmPjX3Q44pCSO4w4H9fnWN87j+q4eRQbWefPwEB +38g= +-----END AGE ENCRYPTED FILE----- diff --git a/secrets/vaultwarden-env.age b/secrets/vaultwarden-env.age new file mode 100644 index 0000000..7d7fdd5 --- /dev/null +++ b/secrets/vaultwarden-env.age @@ -0,0 +1,443 @@ +-----BEGIN AGE ENCRYPTED FILE----- +YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IHNzaC1lZDI1NTE5IFpoVnNlZyBFaitU +emtkY1FmbGRybUszWWllWjJOc0RZVW1qVGRWd1FBcEFvRFRDNlVjCjd0RjVFaDFw +M2kvYTBqWDlSRmpJYlFWaWdjUWlqNEJvVnFrdWVzM2tNaUUKLT4gc3NoLWVkMjU1 +MTkgQ1NNeWhnIGV1ZWIwZkpJVHQ3bGp0azNWaHJaakFZclhYbnBJRlI4TkJMcHp5 +U1VWR0kKdkcyeU1SM25UdTgzdTlrN2ZmNTNhdzgyaVpaWnlLR1BTZG9paGRMV09m +TQotPiB9SGkpby1ncmVhc2UKNXZJaDdRR0dCaWRLUzhLQ0ZJY2JhQXYrQlk1QXJp +ZWpPeTR5WXc2TlVFb1lKSDdLSHNvYlJsdUtKU2hvQzBYbQpTTDBLMEtnZUh3M2dW +dwotLS0gL1g0cGZLWjQvTGlodVRyRVFoYmJCS3Zhbk1Ic1JzSjRUUzhLUHVQbk9u +QQr6dqqurkTXk0ARLmDBOOtsWnPLa/fx+8a7vYrejdX1GA9pTHYfin0fVcESAoSY +QN9XVqijJV/HfozKqVyPLzleQbdahRfgVUq4qgrtbVbFyqp+PA97rZ29mX6zorn9 +nxnNcxxtq/zaiKw3GaGvVWTt54nmTc4BgiG7Bl3PSovZ2fYrU4487dGib+o2PLea ++CnPd6bCnVIRxcr3qGi6TK/pb6XxjBCW+yzje+E0RTRMYnZNO0zj1XYFgOePMNgS +NZa4cXzNEQ8AormOfKKtDxypxZFAgoRDY5pv1KvWcR0jx+2vqlGDyTxq7tl4mnrB +p5955L9AhVuiQi+5V6BcIjNkvHBxc1O1c2peyoJg7zsmNhKMApCMWgG4v87t3RPq +pf+yTTyLJHJGbHNR1zQPRpQnKj0VDiG2gJk3UDf0Gbdzl1mM3ggP/zKpjXCRfQOK +U9NYJCp5HiaSUcGy2KRNDJAjMhvhjEMEMIMPe/NbnzJzEtonStiFqXJ8P7MkkF6X +hC4roNo6RVS/POYNkNEn+Hu1YkHou0UfXUffjQLtdKVMa192nmuf32JIAsq2v40y +88Dw++qzM74/qgDbejpldVfOjKdnbSZcp0vnsrJnNnar2zPCYzjiMCnPTUb6h+tn +QozI0/cRZABDKBn0o8bUyPjsXuao5/caB6fxae0tYJdumryekXDtZES8FbqfavsT +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 +EkZkR8w7yoAwvVluR7IHazELiPfGY7MFOA== +-----END AGE ENCRYPTED FILE----- diff --git a/terraform/main.tf b/terraform/main.tf new file mode 100644 index 0000000..6e666cd --- /dev/null +++ b/terraform/main.tf @@ -0,0 +1,28 @@ +terraform { + required_providers { + proxmox = { + source = "bpg/proxmox" + version = "0.80.0" + } + ionoscloud = { + source = "ionos-cloud/ionoscloud" + version = "~> 6.0" + } + } +} + +provider "proxmox" { + endpoint = var.proxmox_api_url + api_token = var.proxmox_token + insecure = true + ssh { + agent = true + username = "root" + private_key = file("~/.ssh/sascha.koenig") + } +} + +provider "ionoscloud" { + username = var.ionos_username + password = var.ionos_password +} diff --git a/terraform/terraform.tfstate b/terraform/terraform.tfstate new file mode 100644 index 0000000..12222c1 --- /dev/null +++ b/terraform/terraform.tfstate @@ -0,0 +1 @@ +{"version":4,"terraform_version":"1.9.1","serial":18,"lineage":"ce704470-5118-016c-99d1-2da73ef37040","outputs":{},"resources":[{"mode":"managed","type":"proxmox_virtual_environment_download_file","name":"ubuntu_cloud_image","provider":"provider[\"registry.opentofu.org/bpg/proxmox\"]","instances":[{"schema_version":0,"attributes":{"checksum":null,"checksum_algorithm":null,"content_type":"iso","datastore_id":"local","decompression_algorithm":null,"file_name":"jammy-server-cloudimg-amd64.img","id":"local:iso/jammy-server-cloudimg-amd64.img","node_name":"azpve","overwrite":true,"overwrite_unmanaged":false,"size":678153216,"upload_timeout":600,"url":"https://cloud-images.ubuntu.com/jammy/current/jammy-server-cloudimg-amd64.img","verify":true},"sensitive_attributes":[],"private":"eyJvcmlnaW5hbF9zdGF0ZV9zaXplIjoiTmpjNE1UVXpNakUyIn0="}]},{"mode":"managed","type":"proxmox_virtual_environment_file","name":"cloud_config","provider":"provider[\"registry.opentofu.org/bpg/proxmox\"]","instances":[{"schema_version":0,"attributes":{"content_type":"snippets","datastore_id":"local","file_mode":null,"file_modification_date":null,"file_name":"cloud-config.yaml","file_size":null,"file_tag":null,"id":"local:snippets/cloud-config.yaml","node_name":"azpve","overwrite":true,"source_file":[],"source_raw":[{"data":"#cloud-config\nchpasswd:\n list: |\n ubuntu:example\n expire: false\nhostname: example-hostname\npackages:\n - qemu-guest-agent\nruncmd:\n - systemctl enable qemu-guest-agent\n - systemctl start qemu-guest-agent\nusers:\n - default\n - name: ubuntu\n groups: sudo\n shell: /bin/bash\n lock_passwd: true\n ssh-authorized-keys:\n - ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPXX3ZtFW5sRVTb8CPDbGp0E/1uuNYnjlhnnkwF3iLVB sascha.koenig@azintec.com\n sudo: ALL=(ALL) NOPASSWD:ALL\n","file_name":"cloud-config.yaml","resize":0}],"timeout_upload":1800},"sensitive_attributes":[],"private":"bnVsbA=="}]},{"mode":"managed","type":"proxmox_virtual_environment_vm","name":"ubuntu_clone","provider":"provider[\"registry.opentofu.org/bpg/proxmox\"]","instances":[{"status":"tainted","schema_version":0,"attributes":{"acpi":true,"agent":[{"enabled":true,"timeout":"15m","trim":false,"type":"virtio"}],"amd_sev":[],"audio_device":[],"bios":"seabios","boot_order":null,"cdrom":[],"clone":[{"datastore_id":"","full":true,"node_name":"","retries":1,"vm_id":9000}],"cpu":[],"description":null,"disk":[],"efi_disk":[],"hook_script_file_id":null,"hostpci":[],"id":"102","initialization":[{"datastore_id":"local-lvm","dns":[{"domain":"","servers":["1.1.1.1"]}],"interface":"","ip_config":[{"ipv4":[{"address":"dhcp","gateway":""}],"ipv6":[]}],"meta_data_file_id":"","network_data_file_id":"","type":"","user_account":[{"keys":null,"password":"password","username":"user"}],"user_data_file_id":"","vendor_data_file_id":""}],"ipv4_addresses":null,"ipv6_addresses":null,"keyboard_layout":"en-us","kvm_arguments":null,"mac_addresses":null,"machine":null,"memory":[{"dedicated":768,"floating":0,"hugepages":"","keep_hugepages":false,"shared":0}],"migrate":false,"name":"ubuntu-clone","network_device":null,"network_interface_names":null,"node_name":"azpve","numa":[],"on_boot":true,"operating_system":[],"pool_id":null,"protection":false,"reboot":false,"reboot_after_update":true,"rng":[],"scsi_hardware":"virtio-scsi-pci","serial_device":[],"smbios":[],"started":true,"startup":[],"stop_on_destroy":false,"tablet_device":true,"tags":null,"template":false,"timeout_clone":1800,"timeout_create":1800,"timeout_migrate":1800,"timeout_move_disk":1800,"timeout_reboot":1800,"timeout_shutdown_vm":1800,"timeout_start_vm":1800,"timeout_stop_vm":300,"tpm_state":[],"usb":[],"vga":null,"virtiofs":[],"vm_id":102,"watchdog":[]},"sensitive_attributes":[[{"type":"get_attr","value":"initialization"},{"type":"index","value":{"value":0,"type":"number"}},{"type":"get_attr","value":"user_account"},{"type":"index","value":{"value":0,"type":"number"}},{"type":"get_attr","value":"password"}]],"private":"bnVsbA==","dependencies":["proxmox_virtual_environment_download_file.ubuntu_cloud_image","proxmox_virtual_environment_file.cloud_config","proxmox_virtual_environment_vm.ubuntu_template"]}]},{"mode":"managed","type":"proxmox_virtual_environment_vm","name":"ubuntu_template","provider":"provider[\"registry.opentofu.org/bpg/proxmox\"]","instances":[{"schema_version":0,"attributes":{"acpi":true,"agent":[],"amd_sev":[],"audio_device":[],"bios":"ovmf","boot_order":null,"cdrom":[],"clone":[],"cpu":[{"affinity":"","architecture":"","cores":2,"flags":null,"hotplugged":0,"limit":0,"numa":false,"sockets":1,"type":"qemu64","units":1024}],"description":"","disk":[{"aio":"io_uring","backup":true,"cache":"none","datastore_id":"local-lvm","discard":"on","file_format":"raw","file_id":"local:iso/jammy-server-cloudimg-amd64.img","import_from":"","interface":"virtio0","iothread":true,"path_in_datastore":"vm-9000-disk-1","replicate":true,"serial":"","size":20,"speed":[],"ssd":false}],"efi_disk":[{"datastore_id":"local-lvm","file_format":"raw","pre_enrolled_keys":false,"type":"4m"}],"hook_script_file_id":null,"hostpci":[],"id":"9000","initialization":[{"datastore_id":"local-lvm","dns":[],"interface":"ide2","ip_config":[{"ipv4":[{"address":"dhcp","gateway":""}],"ipv6":[]}],"meta_data_file_id":"","network_data_file_id":"","type":"","user_account":[],"user_data_file_id":"local:snippets/cloud-config.yaml","vendor_data_file_id":""}],"ipv4_addresses":[],"ipv6_addresses":[],"keyboard_layout":"en-us","kvm_arguments":"","mac_addresses":["BC:24:11:3B:D2:62"],"machine":"q35","memory":[{"dedicated":2048,"floating":0,"hugepages":"","keep_hugepages":false,"shared":0}],"migrate":false,"name":"ubuntu-template","network_device":[{"bridge":"vmbr0","disconnected":false,"enabled":true,"firewall":false,"mac_address":"BC:24:11:3B:D2:62","model":"virtio","mtu":0,"queues":0,"rate_limit":0,"trunks":"","vlan_id":0}],"network_interface_names":[],"node_name":"azpve","numa":[],"on_boot":true,"operating_system":[],"pool_id":null,"protection":false,"reboot":false,"reboot_after_update":true,"rng":[],"scsi_hardware":"virtio-scsi-pci","serial_device":[],"smbios":[],"started":null,"startup":[],"stop_on_destroy":false,"tablet_device":true,"tags":null,"template":true,"timeout_clone":1800,"timeout_create":1800,"timeout_migrate":1800,"timeout_move_disk":1800,"timeout_reboot":1800,"timeout_shutdown_vm":1800,"timeout_start_vm":1800,"timeout_stop_vm":300,"tpm_state":[],"usb":[],"vga":[],"virtiofs":[],"vm_id":9000,"watchdog":[]},"sensitive_attributes":[],"private":"bnVsbA==","dependencies":["proxmox_virtual_environment_download_file.ubuntu_cloud_image","proxmox_virtual_environment_file.cloud_config"]}]}],"check_results":null} diff --git a/terraform/terraform.tfvars b/terraform/terraform.tfvars new file mode 100644 index 0000000..79e84a6 --- /dev/null +++ b/terraform/terraform.tfvars @@ -0,0 +1,4 @@ +proxmox_api_url = "https://192.168.152.161:8006/api2/json" +proxmox_token = "terraform-prov@pve!tf=3c758be0-da7d-41ba-b40f-e8dd46a25312" +proxmox_node = "azpve" +ssh_public_key = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPXX3ZtFW5sRVTb8CPDbGp0E/1uuNYnjlhnnkwF3iLVB sascha.koenig@azintec.com" diff --git a/terraform/variables.tf b/terraform/variables.tf new file mode 100644 index 0000000..c352f88 --- /dev/null +++ b/terraform/variables.tf @@ -0,0 +1,22 @@ +variable "proxmox_api_url" { + description = "The URL of the Proxmox API (without /api2/json)" + type = string + default = "https://proxmox.local:8006" +} + +variable "proxmox_token" { + description = "The password for the Proxmox API" + type = string + sensitive = true +} + +variable "proxmox_node" { + description = "The name of the Proxmox node" + type = string + default = "pve" +} + +variable "ionos_username" {} +variable "ionos_password" {} + +variable "ssh_public_key" {} diff --git a/terraform/vms.tf b/terraform/vms.tf new file mode 100644 index 0000000..45366e5 --- /dev/null +++ b/terraform/vms.tf @@ -0,0 +1,135 @@ +resource "proxmox_virtual_environment_file" "cloud_config" { + content_type = "snippets" + datastore_id = "local" + node_name = var.proxmox_node + + source_raw { + data = <<-EOF + #cloud-config + chpasswd: + list: | + ubuntu:example + expire: false + hostname: example-hostname + packages: + - qemu-guest-agent + runcmd: + - systemctl enable qemu-guest-agent + - systemctl start qemu-guest-agent + users: + - default + - name: ubuntu + groups: sudo + shell: /bin/bash + lock_passwd: true + ssh-authorized-keys: + - ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPXX3ZtFW5sRVTb8CPDbGp0E/1uuNYnjlhnnkwF3iLVB sascha.koenig@azintec.com + sudo: ALL=(ALL) NOPASSWD:ALL + EOF + + file_name = "cloud-config.yaml" + } +} + +# Download Ubuntu Cloud Image +resource "proxmox_virtual_environment_download_file" "ubuntu_cloud_image" { + content_type = "iso" + datastore_id = "local" + node_name = var.proxmox_node + + url = "https://cloud-images.ubuntu.com/jammy/current/jammy-server-cloudimg-amd64.img" +} + +# Configure VM with User Data Initialization +resource "proxmox_virtual_environment_vm" "ubuntu_template" { + name = "ubuntu-template" + node_name = var.proxmox_node + + template = true + started = false + + machine = "q35" + bios = "ovmf" + vm_id = 9000 +cpu { + cores = 2 +} + +memory { + dedicated = 2048 + } + +efi_disk { + datastore_id = "local-lvm" + type = "4m" +} + +disk { + datastore_id = "local-lvm" + file_id = proxmox_virtual_environment_download_file.ubuntu_cloud_image.id + interface = "virtio0" + iothread = true + discard = "on" + size = 20 +} + +initialization { + ip_config { + ipv4 { + address = "dhcp" + } + } + + user_data_file_id = proxmox_virtual_environment_file.cloud_config.id +} + + network_device { + bridge = "vmbr0" + } +} + +resource "proxmox_virtual_environment_vm" "ubuntu_clone" { + name = "ubuntu-clone" + node_name = var.proxmox_node + + clone { + vm_id = proxmox_virtual_environment_vm.ubuntu_template.id + } + + agent { + enabled = true + } + + memory { + dedicated = 768 + } + + initialization { + datastore_id = "local-lvm" + user_account { + username = "user" + password = "password" + } + dns { + servers = ["1.1.1.1"] + } + ip_config { + ipv4 { + address = "dhcp" + } + } + } +} + +resource "null_resource" "disable_kvm" { + depends_on = [proxmox_virtual_environment_vm.ubuntu_clone] + + provisioner "local-exec" { + command = "qm set ${proxmox_virtual_environment_vm.ubuntu_clone.vm_id} --args '-no-kvm'" + } +} + +output "nixos_anywhere_command" { + value = "nix run github:nix-community/nixos-anywhere -- --flake .#AZ-NIX-1 root@${proxmox_virtual_environment_vm.ubuntu_clone.ipv4_addresses[1][0]} --build-on-remote --ssh-port 2022" + description = "Command to deploy NixOS using nixos-anywhere" +}