diff --git a/deploy b/deploy index 615d40d..127e052 100755 --- a/deploy +++ b/deploy @@ -1,8 +1,12 @@ #!/usr/bin/env bash # Deploy the jupiter NixOS config. # -# ./deploy install first install onto a fresh box (nixos-anywhere). -# Wipes the OS disk. Ships the sops host key. +# ./deploy kexec headless-only: for a read-only-root box (ZimaOS) +# where nixos-anywhere can't ssh-copy-id. Uploads a +# kexec installer (our SSH key baked in) to /tmp and +# boots into it. Then run `install`. +# ./deploy install first install onto a fresh box / running installer +# (nixos-anywhere). Wipes the OS disk. Ships host key. # ./deploy [switch] [host] rebuild + activate on a running jupiter (default). # ./deploy boot [host] stage for next boot, don't activate now. # ./deploy test [host] activate without adding a boot entry. @@ -18,11 +22,30 @@ HOSTKEY="$HOME/.config/homelab/jupiter/ssh_host_ed25519_key" cmd="${1:-switch}" case "$cmd" in - switch|boot|test|install) shift || true ;; + switch|boot|test|install|kexec) shift || true ;; *) cmd="switch" ;; esac case "$cmd" in + kexec) + host="${1:-}" + [ -n "$host" ] || { echo "usage: ./deploy kexec " >&2; exit 1; } + + echo ">> building kexec installer (SSH key baked in)" + nix build .#nixosConfigurations.kexec.config.system.build.kexecInstallerTarball \ + -o result-kexec + tb="$(ls result-kexec/*.tar.gz | head -1)" + + echo ">> streaming installer to root@$host and kexec-ing (enter root password)" + echo " Extracted to /tmp (tmpfs); no compressed copy stored. SSH drops as" + echo " the box jumps into the RAM installer. Disks are untouched." + # Stream the tarball straight into remote tar to avoid a second 522MB copy. + ssh "root@$host" 'mkdir -p /tmp/k && tar -C /tmp/k -xzf - && /tmp/k/kexec/run' < "$tb" || true + + echo ">> box is kexec-ing. Wait ~1-2 min for the installer + network, then:" + echo " ./deploy install $host" + ;; + install) host="${1:-}" [ -n "$host" ] || { echo "usage: ./deploy install " >&2; exit 1; } diff --git a/flake.lock b/flake.lock index d601739..bbf67a2 100644 --- a/flake.lock +++ b/flake.lock @@ -20,6 +20,59 @@ "type": "github" } }, + "nixos-images": { + "inputs": { + "nixos-stable": "nixos-stable", + "nixos-unstable": "nixos-unstable" + }, + "locked": { + "lastModified": 1783593136, + "narHash": "sha256-zy5an02BdZ65OgVKdRkz2TpbdBrsW+uQD7AA2wLuiTM=", + "owner": "nix-community", + "repo": "nixos-images", + "rev": "803f28511c7d5f39f2537c342122fd94b8e1d519", + "type": "github" + }, + "original": { + "owner": "nix-community", + "repo": "nixos-images", + "type": "github" + } + }, + "nixos-stable": { + "locked": { + "lastModified": 1783389287, + "narHash": "sha256-0xIy4dVLqq47rA+mRy0hXDfjhQd4E5PoIns/RmB7nR4=", + "ref": "nixos-26.05", + "rev": "0ad6f47ea4fe188f4bc8f0380f93ae8523337c6c", + "shallow": true, + "type": "git", + "url": "https://github.com/NixOS/nixpkgs" + }, + "original": { + "ref": "nixos-26.05", + "shallow": true, + "type": "git", + "url": "https://github.com/NixOS/nixpkgs" + } + }, + "nixos-unstable": { + "locked": { + "lastModified": 1782175435, + "narHash": "sha256-EMzXKmnOtBQ2MnvpiNOm7E+kOMvdPrIKaeg52Tip2Uk=", + "ref": "nixpkgs-unstable", + "rev": "89570f24e97e614aa34aa9ab1c927b6578a43775", + "shallow": true, + "type": "git", + "url": "https://github.com/NixOS/nixpkgs" + }, + "original": { + "ref": "nixpkgs-unstable", + "shallow": true, + "type": "git", + "url": "https://github.com/NixOS/nixpkgs" + } + }, "nixpkgs": { "locked": { "lastModified": 1783703440, @@ -39,6 +92,7 @@ "root": { "inputs": { "disko": "disko", + "nixos-images": "nixos-images", "nixpkgs": "nixpkgs", "sops-nix": "sops-nix" } diff --git a/flake.nix b/flake.nix index 82759d2..dbccf76 100644 --- a/flake.nix +++ b/flake.nix @@ -11,9 +11,13 @@ url = "github:Mic92/sops-nix"; inputs.nixpkgs.follows = "nixpkgs"; }; + nixos-images = { + url = "github:nix-community/nixos-images"; + inputs.nixpkgs.follows = "nixpkgs"; + }; }; - outputs = { self, nixpkgs, disko, sops-nix, ... }@inputs: + outputs = { self, nixpkgs, disko, sops-nix, nixos-images, ... }@inputs: let system = "x86_64-linux"; in @@ -39,6 +43,23 @@ specialArgs = { inherit inputs; }; modules = [ ./jupiter/vm.nix ]; }; + + # Custom kexec installer with our SSH key baked in, for headless install + # onto a box with a read-only root (ZimaOS) where nixos-anywhere can't + # ssh-copy-id. Build the tarball: + # nix build .#nixosConfigurations.kexec.config.system.build.kexecInstallerTarball + # then scp it to the target's writable /tmp and run kexec/run (see README). + kexec = nixpkgs.lib.nixosSystem { + inherit system; + modules = [ + nixos-images.nixosModules.kexec-installer + ({ ... }: { + users.users.root.openssh.authorizedKeys.keys = [ + "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIGZpkPVhzi1zG5JI9hWyUgdyvNIQbp4ts4jw3idpMhhN erik@laptop" + ]; + }) + ]; + }; }; }; }