feat: custom kexec installer for headless install on read-only-root (ZimaOS)

- add nixos-images input; nixosConfigurations.kexec bakes in the ssh login key
- build via config.system.build.kexecInstallerTarball
- deploy: ./deploy kexec <host> streams the installer to /tmp and kexecs
- works around ZimaOS RO root where nixos-anywhere ssh-copy-id fails

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
erik
2026-07-12 22:14:35 +02:00
co-authored by Claude Opus 4.8
parent 95e945fa6f
commit f581203b57
3 changed files with 102 additions and 4 deletions
+26 -3
View File
@@ -1,8 +1,12 @@
#!/usr/bin/env bash
# Deploy the jupiter NixOS config.
#
# ./deploy install <ip> first install onto a fresh box (nixos-anywhere).
# Wipes the OS disk. Ships the sops host key.
# ./deploy kexec <host> 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 <ip> 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 <ip-or-host>" >&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 <ip-or-host>" >&2; exit 1; }