From 02926f70770ceb90cf382da2b54f888ba969f423 Mon Sep 17 00:00:00 2001 From: Kumar Damani Date: Wed, 1 Jul 2026 00:09:21 -0400 Subject: nix based config --- .gitignore | 3 + nix/.sops.yaml | 17 +++ nix/README.md | 30 +++++ nix/deploy.sh | 50 ++++++++ nix/flake.lock | 48 ++++++++ nix/flake.nix | 40 +++++++ nix/generate-keys.sh | 12 ++ nix/per-host/base/configuration.nix | 67 +++++++++++ nix/per-host/rproxy-2/configuration.nix | 190 ++++++++++++++++++++++++++++++ nix/per-host/torrents-2/configuration.nix | 64 ++++++++++ nix/secrets/rproxy-2.yaml | 26 ++++ nix/secrets/torrents-2.yaml | 25 ++++ 12 files changed, 572 insertions(+) create mode 100644 nix/.sops.yaml create mode 100644 nix/README.md create mode 100755 nix/deploy.sh create mode 100644 nix/flake.lock create mode 100644 nix/flake.nix create mode 100755 nix/generate-keys.sh create mode 100644 nix/per-host/base/configuration.nix create mode 100644 nix/per-host/rproxy-2/configuration.nix create mode 100644 nix/per-host/torrents-2/configuration.nix create mode 100644 nix/secrets/rproxy-2.yaml create mode 100644 nix/secrets/torrents-2.yaml diff --git a/.gitignore b/.gitignore index c55d3b2..c3513ce 100755 --- a/.gitignore +++ b/.gitignore @@ -10,5 +10,8 @@ terraform/*.tfvars ansible/vaultkey ansible/playbooks/artifacts/ +nix/host-keys +nix/result + .devenv .direnv diff --git a/nix/.sops.yaml b/nix/.sops.yaml new file mode 100644 index 0000000..d03cddc --- /dev/null +++ b/nix/.sops.yaml @@ -0,0 +1,17 @@ +keys: + - &admin_me age12teny70e5cm3992z7atx9g9606d4a60dsl8nskzkpp234uelnctq82mqaa + - &server_torrents_2 age1cunp9vshd45hlfqdxd4pdvg0qgfllk7mctff65s02wm447xgde7qar7z25 + - &server_rproxy_2 age1h58rh5q0d7rg984g3e3qfrgwzu3ujzkkcg8f0ls5jlsvdy44f5ls3aywyx + +creation_rules: + - path_regex: 'secrets/torrents.*\.yaml$' + key_groups: + - age: + - *admin_me + - *server_torrents_2 + + - path_regex: 'secrets/rproxy.*\.yaml$' + key_groups: + - age: + - *admin_me + - *server_rproxy_2 diff --git a/nix/README.md b/nix/README.md new file mode 100644 index 0000000..08d7305 --- /dev/null +++ b/nix/README.md @@ -0,0 +1,30 @@ +Build base image: +```sh +nixos-rebuild build-image --image-variant proxmox --flake .#base +``` + +Copy base image to a Proxmox node: +```sh +scp result/vzdump-qemu-nixos-26.05.20260401.6201e20.vma.zst root@192.168.0.85:/var/lib/vz/dump/ +``` + +Restore on Proxmox. + +Convert to Proxmox Template. + +Run TF as usual using clone against the Template. + +```sh +# first time only +./generate-keys.sh torrents--2 + +# edit the .sops.yaml to include the host's age key + +sops secrets/rproxy-2.yaml + +./deploy.sh torrents-2 root +``` + +Sources: +https://github.com/nix-community/nixos-generators +https://gist.github.com/joshleecreates/e6892ca21b0e6b7c24d96ca2a24bf23e diff --git a/nix/deploy.sh b/nix/deploy.sh new file mode 100755 index 0000000..d3ad649 --- /dev/null +++ b/nix/deploy.sh @@ -0,0 +1,50 @@ +#!/usr/bin/env bash +set -euo pipefail + +HOST="$1" +FLAKE=".#${HOST}" +KEY_DIR="./host-keys/${HOST}" +USER="${2:-root}" + +# Validate +if [ ! -d "$KEY_DIR" ]; then + echo "❌ No host key directory found for '${HOST}'" + exit 1 +fi + +# Validate the per-host secrets file exists +SECRETS_FILE="secrets/${HOST}.yaml" +if [ ! -f "$SECRETS_FILE" ]; then + echo "❌ No secrets file found at ${SECRETS_FILE}" + echo " Run: sops ${SECRETS_FILE}" + exit 1 +fi + + +# ---- Compare host key fingerprints and replace if different ---- +LOCAL_FINGERPRINT=$(ssh-keygen -lf "${KEY_DIR}/ssh_host_ed25519_key.pub" 2>/dev/null | awk '{print $2}') +REMOTE_FINGERPRINT=$(ssh "${USER}@${HOST}" ssh-keygen -lf /etc/ssh/ssh_host_ed25519_key.pub 2>/dev/null | awk '{print $2}') + +if [ "$LOCAL_FINGERPRINT" != "$REMOTE_FINGERPRINT" ]; then + echo "→ [${HOST}] Host key mismatch! Replacing..." + echo " Local: ${LOCAL_FINGERPRINT}" + echo " Remote: ${REMOTE_FINGERPRINT}" + + # Copy the pre-generated key to replace the VM's auto-generated one + scp "${KEY_DIR}/ssh_host_ed25519_key" "${USER}@${HOST}:/etc/ssh/ssh_host_ed25519_key" + scp "${KEY_DIR}/ssh_host_ed25519_key.pub" "${USER}@${HOST}:/etc/ssh/ssh_host_ed25519_key.pub" + ssh "${USER}@${HOST}" chmod 600 /etc/ssh/ssh_host_ed25519_key + ssh "${USER}@${HOST}" chmod 644 /etc/ssh/ssh_host_ed25519_key.pub + + echo "→ [${HOST}] Key replaced. You may get a WARNING on next SSH (host key changed)." + echo " Remove old key with: ssh-keygen -R ${HOST}" +else + echo "→ [${HOST}] Host keys match, no action needed" +fi + +# Deploy +echo "→ [${HOST}] Deploying with nixos-rebuild..." +nixos-rebuild switch \ + --flake "$FLAKE" \ + --target-host "${USER}@${HOST}" \ + --sudo diff --git a/nix/flake.lock b/nix/flake.lock new file mode 100644 index 0000000..6ff8928 --- /dev/null +++ b/nix/flake.lock @@ -0,0 +1,48 @@ +{ + "nodes": { + "nixpkgs": { + "locked": { + "lastModified": 1775036866, + "narHash": "sha256-ZojAnPuCdy657PbTq5V0Y+AHKhZAIwSIT2cb8UgAz/U=", + "owner": "nixos", + "repo": "nixpkgs", + "rev": "6201e203d09599479a3b3450ed24fa81537ebc4e", + "type": "github" + }, + "original": { + "owner": "nixos", + "ref": "nixos-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "root": { + "inputs": { + "nixpkgs": "nixpkgs", + "sops-nix": "sops-nix" + } + }, + "sops-nix": { + "inputs": { + "nixpkgs": [ + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1776771786, + "narHash": "sha256-DRFGPfFV6hbrfO9a1PH1FkCi7qR5FgjSqsQGGvk1rdI=", + "owner": "Mic92", + "repo": "sops-nix", + "rev": "bef289e2248991f7afeb95965c82fbcd8ff72598", + "type": "github" + }, + "original": { + "owner": "Mic92", + "repo": "sops-nix", + "type": "github" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/nix/flake.nix b/nix/flake.nix new file mode 100644 index 0000000..e4cde5f --- /dev/null +++ b/nix/flake.nix @@ -0,0 +1,40 @@ +{ + description = "NixOS configurations"; + + inputs = { + nixpkgs.url = "github:nixos/nixpkgs?ref=nixos-unstable"; + sops-nix = { + url = "github:Mic92/sops-nix"; + inputs.nixpkgs.follows = "nixpkgs"; + }; + }; + + outputs = inputs@{ nixpkgs, sops-nix, ... }: { + nixosConfigurations = { + "base" = nixpkgs.lib.nixosSystem { + system = "x86_64-linux"; + modules = [ + ./per-host/base/configuration.nix + ]; + }; + + "torrents-2" = nixpkgs.lib.nixosSystem { + system = "x86_64-linux"; + modules = [ + ./per-host/base/configuration.nix + ./per-host/torrents-2/configuration.nix + sops-nix.nixosModules.sops + ]; + }; + + "rproxy-2" = nixpkgs.lib.nixosSystem { + system = "x86_64-linux"; + modules = [ + ./per-host/base/configuration.nix + ./per-host/rproxy-2/configuration.nix + sops-nix.nixosModules.sops + ]; + }; + }; + }; +} diff --git a/nix/generate-keys.sh b/nix/generate-keys.sh new file mode 100755 index 0000000..611d931 --- /dev/null +++ b/nix/generate-keys.sh @@ -0,0 +1,12 @@ +#!/usr/bin/env bash +# Generate a host key for a specific host +set -euo pipefail + +HOST="$1" +mkdir -p "./host-keys/${HOST}" +ssh-keygen -t ed25519 -f "./host-keys/${HOST}/ssh_host_ed25519_key" -N "" +echo "✅ Generated host key for ${HOST}" +echo "" +echo "👉 Derive age public key with:" +# echo " cat ./host-keys/${HOST}/ssh_host_ed25519_key.pub | nix run nixpkgs#ssh-to-age" +echo " cat ./host-keys/${HOST}/ssh_host_ed25519_key.pub | ssh-to-age" diff --git a/nix/per-host/base/configuration.nix b/nix/per-host/base/configuration.nix new file mode 100644 index 0000000..8b34249 --- /dev/null +++ b/nix/per-host/base/configuration.nix @@ -0,0 +1,67 @@ +{ config, pkgs, modulesPath, lib, system, ... }: + +{ + imports = [ + (modulesPath + "/profiles/qemu-guest.nix") + ]; + + config = { + #Provide a default hostname + networking.hostName = lib.mkDefault "base"; + networking.useDHCP = lib.mkDefault true; + + # Enable QEMU Guest for Proxmox + services.qemuGuest.enable = lib.mkDefault true; + + # Use the boot drive for grub + boot.loader.grub.enable = lib.mkDefault true; + boot.loader.grub.devices = [ "nodev" ]; + + boot.growPartition = lib.mkDefault true; + + # Allow remote updates with flakes and non-root users + nix.settings.trusted-users = [ "root" "@wheel" ]; + nix.settings.experimental-features = [ "nix-command" "flakes" ]; + + # Some sane packages we need on every system + environment.systemPackages = with pkgs; [ + vim # for emergencies + git # for pulling nix flakes + python3 # for ansible + ]; + + # Don't ask for passwords + security.sudo.wheelNeedsPassword = false; + + # Enable ssh + services.openssh = { + enable = true; + settings.PasswordAuthentication = false; + settings.KbdInteractiveAuthentication = false; + }; + programs.ssh.startAgent = true; + + # Add an admin user + users.users.jefe = { + isNormalUser = true; + description = "el jefe"; + extraGroups = [ "networkmanager" "wheel" ]; + }; + users.users.jefe.openssh.authorizedKeys.keys = [ + "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIAYYjB+fK4JFlJSY6Ax48p38eSuDG12VQVqP+WSrWGuO" + ]; + + users.users.root.openssh.authorizedKeys.keys = [ + "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIAYYjB+fK4JFlJSY6Ax48p38eSuDG12VQVqP+WSrWGuO" + ]; + + # Default filesystem + fileSystems."/" = lib.mkDefault { + device = "/dev/disk/by-label/nixos"; + autoResize = true; + fsType = "ext4"; + }; + + system.stateVersion = lib.mkDefault "25.11"; + }; +} diff --git a/nix/per-host/rproxy-2/configuration.nix b/nix/per-host/rproxy-2/configuration.nix new file mode 100644 index 0000000..d1580e8 --- /dev/null +++ b/nix/per-host/rproxy-2/configuration.nix @@ -0,0 +1,190 @@ +{ config, pkgs, modulesPath, lib, system, ... }: + +{ + config = { + sops.age.sshKeyPaths = [ "/etc/ssh/ssh_host_ed25519_key" ]; + sops.defaultSopsFile = ../../secrets/rproxy-2.yaml; + sops.secrets."caddy/env" = { + owner = "caddy"; + restartUnits = [ "caddy.service" ]; + }; + + networking.hostName = "rproxy-2"; + networking.firewall.allowedTCPPorts = [ 80 443 ]; + + services.caddy = { + enable = true; + package = pkgs.caddy.withPlugins { + plugins = [ "github.com/caddy-dns/namecheap@v1.0.0" ]; + hash = "sha256-G+iBYwqKNB0kyQ060R9J2brbwsRl/WgvB6Tkc6MC5yU="; + }; + environmentFile = config.sops.secrets."caddy/env".path; + + # Test config only + # virtualHosts."rproxy2.kumardamani.net:80".extraConfig = '' + # respond "Hello, world! {$NAMECHEAP_API_USER}" + # tls internal + # ''; + + virtualHosts."lidarr.kumardamani.net:443".extraConfig = '' + reverse_proxy med-dl:8686 + tls { + dns namecheap { + api_key {$NAMECHEAP_API_KEY} + user {$NAMECHEAP_API_USER} + } + } + ''; + + virtualHosts."radarr.kumardamani.net:443".extraConfig = '' + reverse_proxy med-dl:7878 + tls { + dns namecheap { + api_key {$NAMECHEAP_API_KEY} + user {$NAMECHEAP_API_USER} + } + } + ''; + + virtualHosts."sonarr.kumardamani.net:443".extraConfig = '' + reverse_proxy med-dl:8989 + tls { + dns namecheap { + api_key {$NAMECHEAP_API_KEY} + user {$NAMECHEAP_API_USER} + } + } + ''; + + virtualHosts."namemydragon.lol:443".extraConfig = '' + reverse_proxy sites:84 + tls { + dns namecheap { + api_key {$NAMECHEAP_API_KEY} + user {$NAMECHEAP_API_USER} + } + } + ''; + + virtualHosts."www.namemydragon.lol:443".extraConfig = '' + reverse_proxy sites:84 + tls { + dns namecheap { + api_key {$NAMECHEAP_API_KEY} + user {$NAMECHEAP_API_USER} + } + } + ''; + + virtualHosts."metrics2.kumardamani.net:443".extraConfig = '' + reverse_proxy monitoring:9090 + tls { + dns namecheap { + api_key {$NAMECHEAP_API_KEY} + user {$NAMECHEAP_API_USER} + } + } + ''; + + virtualHosts."torrents.kumardamani.net:443".extraConfig = '' + reverse_proxy torrents:9091 + tls { + dns namecheap { + api_key {$NAMECHEAP_API_KEY} + user {$NAMECHEAP_API_USER} + } + } + ''; + + virtualHosts."vault.kumardamani.net:443".extraConfig = '' + reverse_proxy vault:8989 + tls { + dns namecheap { + api_key {$NAMECHEAP_API_KEY} + user {$NAMECHEAP_API_USER} + } + } + ''; + + virtualHosts."nc.kumardamani.net:443".extraConfig = '' + reverse_proxy nc-kumar:11000 + tls { + dns namecheap { + api_key {$NAMECHEAP_API_KEY} + user {$NAMECHEAP_API_USER} + } + } + ''; + + virtualHosts."kumardamani.net:443".extraConfig = '' + reverse_proxy sites:83 + tls { + dns namecheap { + api_key {$NAMECHEAP_API_KEY} + user {$NAMECHEAP_API_USER} + } + } + ''; + + virtualHosts."www.kumardamani.net:443".extraConfig = '' + reverse_proxy sites:83 + tls { + dns namecheap { + api_key {$NAMECHEAP_API_KEY} + user {$NAMECHEAP_API_USER} + } + } + ''; + + virtualHosts."damanistuff.net:443".extraConfig = '' + reverse_proxy sites:82 + tls { + dns namecheap { + api_key {$NAMECHEAP_API_KEY} + user {$NAMECHEAP_API_USER} + } + } + ''; + + virtualHosts."www.damanistuff.net:443".extraConfig = '' + reverse_proxy sites:82 + tls { + dns namecheap { + api_key {$NAMECHEAP_API_KEY} + user {$NAMECHEAP_API_USER} + } + } + ''; + + virtualHosts."kavisjourneys.com".extraConfig = '' + reverse_proxy sites:81 + tls { + dns namecheap { + api_key {$NAMECHEAP_API_KEY} + user {$NAMECHEAP_API_USER} + } + } + ''; + + virtualHosts."www.kavisjourneys.com".extraConfig = '' + reverse_proxy sites:81 + tls { + dns namecheap { + api_key {$NAMECHEAP_API_KEY} + user {$NAMECHEAP_API_USER} + } + } + ''; + + virtualHosts."*.min.kumardamani.net".extraConfig = '' + reverse_proxy minio:9000 + tls { + dns namecheap { + api_key {$NAMECHEAP_API_KEY} + user {$NAMECHEAP_API_USER} + } + } + ''; + }; + }; +} diff --git a/nix/per-host/torrents-2/configuration.nix b/nix/per-host/torrents-2/configuration.nix new file mode 100644 index 0000000..6e7cd49 --- /dev/null +++ b/nix/per-host/torrents-2/configuration.nix @@ -0,0 +1,64 @@ +{ config, pkgs, modulesPath, lib, system, ... }: + +{ + config = { + sops.age.sshKeyPaths = [ "/etc/ssh/ssh_host_ed25519_key" ]; + sops.defaultSopsFile = ../../secrets/torrents-2.yaml; + # sops.secrets."foo" = { + # owner = "transmission"; + # }; + + networking.hostName = "torrents-2"; + networking.firewall.allowedTCPPorts = [ 80 443 9091 ]; + + hardware.graphics = { + enable = true; + }; + + hardware.nvidia = { + modesetting.enable = true; + nvidiaPersistenced = true; + powerManagement.enable = false; + powerManagement.finegrained = false; + open = false; + nvidiaSettings = true; + package = config.boot.kernelPackages.nvidiaPackages.legacy_580; + }; + + nixpkgs.config.allowUnfree = true; + + services.xserver.videoDrivers = [ "nvidia" ]; + + sops.templates."transmission-rpc-password.json" = { + content = '' + { + "rpc-password": "${config.sops.placeholder.foo}" + } + ''; + owner = "transmission"; + restartUnits = [ "transmission.service" ]; + }; + + services.transmission = { + enable = true; + package = pkgs.transmission_4; + credentialsFile = config.sops.templates."transmission-rpc-password.json".path; + settings = { + rpc-authentication-required = true; + rpc-username = "kdam0"; + # testpass + # rpc-password = "{b55cdbfcac290fff79d3bdb3441082dca8f278aay.bodWGn"; + # rpc-password-file = config.sops.secrets."foo".path; + rpc-bind-address = "0.0.0.0"; + # rpc-host-whitelist = "torrents2.kumardamani.net"; + rpc-whitelist-enabled = true; + rpc-whitelist = "127.0.0.1,10.10.*.*"; + }; + }; + + fileSystems."/mnt/data" = { + device = "nas.bacala:/mnt/tank/customers/kumar/media"; + fsType = "nfs"; + }; + }; +} diff --git a/nix/secrets/rproxy-2.yaml b/nix/secrets/rproxy-2.yaml new file mode 100644 index 0000000..f597e7a --- /dev/null +++ b/nix/secrets/rproxy-2.yaml @@ -0,0 +1,26 @@ +caddy: + env: ENC[AES256_GCM,data:QwDHxZpSn1Z64qw3EJtlLLL+zbjMFxkVq11Fvu2uYQ876MfO1nqNqY8chJkmM3hGVhnSc+t9G9rv+/IXYvPngd+XKuHgi2bNp47jFuXHi8U=,iv:3q7xMBDyx+zhIV472gNZEkWiTdZIdCRFZjCNOwox5nc=,tag:Kl+xhznyzatyYsRBPlwh/A==,type:str] +sops: + age: + - recipient: age12teny70e5cm3992z7atx9g9606d4a60dsl8nskzkpp234uelnctq82mqaa + enc: | + -----BEGIN AGE ENCRYPTED FILE----- + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBhQnptb3QrM0NVeGY3NFVx + c21TMlQ0NTAvN2c1enRybFBKY2ptT2lFbUdBCldwNGNkVjdiaE5hOGlpWGRoQ0pV + VXIzT3dqZ2hDM29YVm1jRldRTDJXSUkKLS0tIGNFZEdSMjhVTTlOZTEzY1NTMW41 + dEZZNHhhN1FBZEJHMGFab29iWXFLMW8KjjC/mHCG1R1899rVyhUMXdyxoi9PevKl + dSKlV0b9cVuI5Ad8/FQdI+h5FAMBXLpORB/5GGjvqlzVL4Bz0MXvwg== + -----END AGE ENCRYPTED FILE----- + - recipient: age1h58rh5q0d7rg984g3e3qfrgwzu3ujzkkcg8f0ls5jlsvdy44f5ls3aywyx + enc: | + -----BEGIN AGE ENCRYPTED FILE----- + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSArUkRFZ2RJU1ovS2U3WUxi + OGJCSGtseTdkdmxMMitwOUNlUHVyT0F1R3ljCklSY1o4MFUzZXVsNzZYZkJWNC9v + dWZPdDBhN3Bab3YrQWkvZXRpTkFZSHMKLS0tIFJWRWU3TGpYTmU4eU80NEI3TzVV + dDdGemVxVklRNkdNbGFiR3Vvd2pOVUkKjUSql5h+otnIRviVg2N5RF1JSYvBeAMJ + lWVy7HGPuzzBk0SZUP5C0cdnGymklZtXE+5qHBlmOUFF5MOqoGEgqw== + -----END AGE ENCRYPTED FILE----- + lastmodified: "2026-07-01T02:40:11Z" + mac: ENC[AES256_GCM,data:b4dO1T1HHX3GQKv1imZMQHrSLzc+Au6WB4r/PjvA+bHMj9SSlU7JxVOQia1pGC4fv9B9i9TLrzyC1WLNk4cpss3+mFTWu/Ep8hk0409LoH8cvQTeyOIVs9vIeDV7+ENTTNyJMMPQu/gwpODRP9Xs6YGfGomMth0ntUdyufMRAlk=,iv:ndO9Ijbxw+2lRwCtDxgpG+P9cIAGap4j4GhxML4V04k=,tag:fik52goMxEry4Ei3vDTLag==,type:str] + unencrypted_suffix: _unencrypted + version: 3.12.2 diff --git a/nix/secrets/torrents-2.yaml b/nix/secrets/torrents-2.yaml new file mode 100644 index 0000000..584d092 --- /dev/null +++ b/nix/secrets/torrents-2.yaml @@ -0,0 +1,25 @@ +foo: ENC[AES256_GCM,data:nxgkp0a10nLbVqs=,iv:ywxB2H2a/NBW4hwBkFV/JcTpgpnLjHZ4++XS8vpylDA=,tag:wLEnmbpPDsUlacDGqkBajw==,type:str] +sops: + age: + - recipient: age12teny70e5cm3992z7atx9g9606d4a60dsl8nskzkpp234uelnctq82mqaa + enc: | + -----BEGIN AGE ENCRYPTED FILE----- + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBpQ050aEhkQUc0bHJnR3d2 + WDBVSXFBc09uMDdxdGNMa05JY0FMbmRzQ1Y0ClN2ME1WMGxiSXVhRWxqY0t1ZmZQ + a3VremtsaHloWEkxYjBUN0Zyd053YkUKLS0tIHJzUjhpVzEwYXIvQXN5RWxBMTRW + MnJVb2FRR29jZ052YTJuS2NvaDFaS00KgjvJEcRYbp/2jhIwCVs8P3ITPrxxpHyu + 3iNcGydW+r6KFOjKfYKeXEjJFEPj3G/ipd7EdNi7FwG9e41QehvZYQ== + -----END AGE ENCRYPTED FILE----- + - recipient: age1cunp9vshd45hlfqdxd4pdvg0qgfllk7mctff65s02wm447xgde7qar7z25 + enc: | + -----BEGIN AGE ENCRYPTED FILE----- + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBzZzVFbzhsNVliSktiRm16 + N3lNSEtUUytJaDNVdDFML1M2RzloYnFpem5nClMrTHh1N3NBMFN5T1pueU45UlEw + aVhuZGhQL1VEaUdCTGRZUWo4MTZtUHMKLS0tIFFxdm02MXlrZEN6Z0VhRkc5S3lU + V2g0KzJzZmlGTlBIR3gwdDZUbUViTjgK2QuhL/4Wop3EP8mwoToF8u2UAiHEEknQ + I8DRcA7P5rea4pnuaJTYvhz1JzZN0fUr5EOVO6O7YZ9bdlKeDJ+sMw== + -----END AGE ENCRYPTED FILE----- + lastmodified: "2026-06-29T02:18:04Z" + mac: ENC[AES256_GCM,data:ZdhR3KRHMDNB7d05fZO+2TIIijNn3r8jKwAaoB8wSsTon2oPkPMB3iDl0G0Sy2mC/idZNKC8UOSpxcrV0vBjwxjibOOgyUL0faBda8l3NASGLyxd2NcP3M0xIwnLJlqhVjfdkpZ2JwTRkHxmUiZMHLd7fwL1zZaWjs8OCgeLqnw=,iv:nVWOXwygqHXZdUE/dX3cl9c/IcgWfhKj/M+TWaHWWVY=,tag:anNJVNhUYV37BGnkbsTJXQ==,type:str] + unencrypted_suffix: _unencrypted + version: 3.12.2 -- cgit v1.2.3