#!/usr/bin/env bash # Deploy the jupiter NixOS config. # # ./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. # # Runs from a non-NixOS host too (nixos-rebuild / nixos-anywhere via `nix run`). set -euo pipefail REPO="$(cd "$(dirname "$0")" && pwd)" cd "$REPO" export PATH="/nix/var/nix/profiles/default/bin:$PATH" HOSTKEY="$HOME/.config/homelab/jupiter/ssh_host_ed25519_key" cmd="${1:-switch}" case "$cmd" in 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 + static tools" nix build .#nixosConfigurations.kexec.config.system.build.kexecInstallerTarball \ -o result-kexec tb="$(ls result-kexec/*.tar.gz | head -1)" # kexec/run rebuilds an initrd with `cpio` + `gzip` from PATH — ZimaOS lacks # both. Ship static ones: GNU cpio (reliable -o -H newc), busybox as gzip. cpio="$(nix build --no-link --print-out-paths nixpkgs#pkgsStatic.cpio)/bin/cpio" bbox="$(nix build --no-link --print-out-paths nixpkgs#pkgsStatic.busybox)/bin/busybox" # One password prompt: multiplex scp + ssh over a shared control connection. cm="/tmp/homelab-cm-%r@%h:%p" o=(-o ControlMaster=auto -o "ControlPath=$cm" -o ControlPersist=300 \ -o StrictHostKeyChecking=accept-new) echo ">> connecting to root@$host (enter the ZimaOS root password once)" ssh "${o[@]}" "root@$host" 'mkdir -p /tmp/bin' scp "${o[@]}" "$cpio" "root@$host:/tmp/bin/cpio" scp "${o[@]}" "$bbox" "root@$host:/tmp/bin/gzip" # busybox as gzip (argv0) echo ">> streaming installer + kexec-ing. SSH drops as the box jumps into the" echo " RAM installer. Disks are untouched." ssh "${o[@]}" "root@$host" \ 'chmod +x /tmp/bin/*; mkdir -p /tmp/k && tar -C /tmp/k -xzf - && PATH=/tmp/bin:$PATH /tmp/k/kexec/run' \ < "$tb" || true ssh "${o[@]}" -O exit "root@$host" 2>/dev/null || true # close control socket 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; } [ -f "$HOSTKEY" ] || { echo "missing host key: $HOSTKEY" >&2; exit 1; } # Stage the pre-generated SSH host key so sops can decrypt on boot #1. stage="$(mktemp -d)" trap 'rm -rf "$stage"' EXIT install -Dm600 "$HOSTKEY" "$stage/etc/ssh/ssh_host_ed25519_key" install -Dm644 "$HOSTKEY.pub" "$stage/etc/ssh/ssh_host_ed25519_key.pub" echo ">> nixos-anywhere onto root@$host (OS disk WILL be wiped)" nix run github:nix-community/nixos-anywhere -- \ --flake ".#jupiter" \ --extra-files "$stage" \ --generate-hardware-config nixos-generate-config ./jupiter/hardware-configuration.nix \ --target-host "root@$host" ;; switch|boot|test) host="${1:-jupiter}" echo ">> nixos-rebuild $cmd on darman@$host" nix run nixpkgs#nixos-rebuild -- "$cmd" \ --flake ".#jupiter" \ --target-host "darman@$host" \ --use-remote-sudo ;; esac