From f565e9c2a1d2427e0d146fb563d23f6685101a9e Mon Sep 17 00:00:00 2001 From: beatzaplenty Date: Wed, 22 Jul 2026 02:38:11 +0000 Subject: [PATCH] Fix auto-install.sh to work standalone, not just baked into the image Two real bugs, both hit live: 1. Shebang: #!/run/current-system/sw/bin/bash only resolves on an already-activated NixOS system -- running the checked-out script directly (e.g. from a stock ISO, cloned repo) failed with "cannot execute: required file not found" on a non-NixOS box. Switched to #!/usr/bin/env bash, which resolves identically on NixOS (environment.usrbinenv's own default) and any normal Linux distro. Also fixed the file's missing executable bit. 2. FLAKE_BASE_URL: previously depended on pkgs.replaceVars substituting a Nix-templated @lanDomain@ placeholder at build time -- meaning it only ever worked when baked into the built installer image, not when run straight from a checkout (the literal, unexpanded "@lanDomain@" string reached git as a bogus hostname). Replaced with LAN_DOMAIN in scripts/env.sh (manually kept in sync with variables.nix's lanDomain, same pattern as NIX_CACHE_HOST/nixCacheHost already), sourced by the script itself like every other script in scripts/. Dropped pkgs.replaceVars from modules/installer/common.nix entirely -- scripts/env.sh is now baked into the image alongside auto-install.sh at a matching relative path (/etc/nixos-installer/env.sh next to /etc/nixos-installer/installer/auto-install.sh) so the script's own relative `source` line resolves the same way in both contexts. loginShellInit's invocation path and docs/auto-installer.md updated to match. Verified: shellcheck clean on both scripts, the baked files are byte-identical to their checked-in sources (no templating left to verify), and codex-maintenance.sh (secret grep, fmt, statix, full eval of every host/package including the installer/pxe artifacts) passes clean. --- CLAUDE.md | 30 +++++++++++++++++++++--------- docs/auto-installer.md | 27 ++++++++++++++++++++++----- modules/installer/common.nix | 24 ++++++++++++++---------- scripts/env.sh | 6 ++++++ scripts/installer/auto-install.sh | 7 +++++-- 5 files changed, 68 insertions(+), 26 deletions(-) mode change 100644 => 100755 scripts/installer/auto-install.sh diff --git a/CLAUDE.md b/CLAUDE.md index 5d0be5d..14e523d 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -179,13 +179,24 @@ instead of copying it. - `scripts/installer/auto-install.sh` — the interactive install script baked into the auto-installer image (see `docs/auto-installer.md`), kept as a real, version-controlled shell file rather than inline in - `modules/installer/common.nix`'s Nix. `common.nix` wires it in with - `pkgs.replaceVars ../../scripts/installer/auto-install.sh { inherit (vars) lanDomain; }`, - substituting the single `@lanDomain@` placeholder from `variables.nix` — - every other `${...}` in the script is a literal bash reference, - untouched by this. `replaceVars` fails the build if any `@name@`-shaped - placeholder is left unsubstituted, so a typo'd or renamed variable is - caught at eval time rather than silently shipping broken. + `modules/installer/common.nix`'s Nix. It sources `scripts/env.sh` itself + for `LAN_DOMAIN` (`export LAN_DOMAIN`/`: "${LAN_DOMAIN:=...}"`, matching + `variables.nix`'s `lanDomain` — manually kept in sync, same pattern as + `NIX_CACHE_HOST` mirroring `nixCacheHost`), rather than Nix-level string + substitution — that's what makes it work identically whether run + straight from a git checkout or from inside the built installer image. + `common.nix` bakes `scripts/env.sh` in alongside it at a matching + relative path (`/etc/nixos-installer/env.sh` next to + `/etc/nixos-installer/installer/auto-install.sh`) so the script's own + `source "$(dirname ...)/../env.sh"` line resolves the same way in both + contexts — this is also why it's invoked from + `/etc/nixos-installer/installer/auto-install.sh` rather than a flat + `/etc/auto-install.sh`. `#!/usr/bin/env bash`, not + `#!/run/current-system/sw/bin/bash`: the latter only resolves on an + already-activated NixOS system, breaking the checked-out-file case + entirely (confirmed live: "cannot execute: required file not found" on + a non-NixOS box); `/usr/bin/env` is reliably present on both NixOS + (`environment.usrbinenv`'s own default) and any normal Linux distro. ### `scripts/secrets/` @@ -297,8 +308,9 @@ Sourced by the scripts above, never run directly: ### Top level - `scripts/env.sh` — shared config (`PROXMOX_HOST`, storage pool, bridge, - default cores/memory) sourced by `create-proxmox-resource.sh`. Add new - cross-script config here instead of duplicating it per-script. + default cores/memory, `NIX_CACHE_HOST`, `LAN_DOMAIN`) sourced by + `create-proxmox-resource.sh` and `scripts/installer/auto-install.sh`. Add + new cross-script config here instead of duplicating it per-script. - `scripts/bump-nixpkgs-release.sh` — bumps `flake.nix`'s `nixpkgs.url`/ `home-manager.url` in place. Exists because flake input URLs can't reference `variables.nix` (confirmed empirically — `nix flake metadata` diff --git a/docs/auto-installer.md b/docs/auto-installer.md index 7c5c638..870aa92 100644 --- a/docs/auto-installer.md +++ b/docs/auto-installer.md @@ -8,10 +8,13 @@ lives here. The installer provides a small NixOS install environment (ISO, or the same image netbooted via PXE) with SSH access, Git support, and an interactive installation script. -Logging in as any user (root or `nixos`) runs `/etc/auto-install.sh`, -discovers available hosts from this same flake, lets the operator choose a -target, applies that host's Disko storage configuration, installs NixOS, and -reboots. +Logging in as any user (root or `nixos`) runs +`/etc/nixos-installer/installer/auto-install.sh` (the same file as +`scripts/installer/auto-install.sh` in this repo — see "Installer process" +below for why it's baked in at that path rather than a flat +`/etc/auto-install.sh`), discovers available hosts from this same flake, +lets the operator choose a target, applies that host's Disko storage +configuration, installs NixOS, and reboots. **This applies to every `nixosConfigurations` target except `lxc-*` hosts — see "LXC hosts" immediately below for why those are different.** @@ -217,7 +220,21 @@ entirely (see "LXC hosts" above), so it never reaches this code path. ## Installer process -`/etc/auto-install.sh`: +`scripts/installer/auto-install.sh` is a real, version-controlled shell +script — not an inline Nix string. It sources `scripts/env.sh` for +`LAN_DOMAIN` itself (same as every other script in `scripts/`), so it +behaves identically whether it's run straight from a git checkout (e.g. +manually, from a stock NixOS ISO that isn't this repo's own installer +image) or from inside the built installer image. That's also why it's +baked in at `/etc/nixos-installer/installer/auto-install.sh` rather than a +flat `/etc/auto-install.sh` — `modules/installer/common.nix` bakes +`scripts/env.sh` in alongside it at `/etc/nixos-installer/env.sh`, +preserving the same relative layout (`installer/auto-install.sh` -> +`../env.sh`) the checked-out repo has, so the script's own +`source ".../env.sh"` line resolves correctly in both places without any +Nix-level templating. + +Once running, it: 1. Queries `nixosConfigurations` from this flake over the network (`git+https:///beatzaplenty/nixos.git`) — this happens at *install* time, not build time, so a generic installer image always sees whatever hosts are currently committed, without needing a rebuild. 2. Presents them as a menu; confirms the choice. diff --git a/modules/installer/common.nix b/modules/installer/common.nix index 9cab712..c27dd99 100644 --- a/modules/installer/common.nix +++ b/modules/installer/common.nix @@ -46,16 +46,20 @@ ]; # Auto-install script, kept as a real, version-controlled shell file at - # scripts/installer/auto-install.sh rather than an inline Nix string -- - # replaceVars only substitutes the one value (lanDomain) that genuinely - # needs to come from variables.nix; every other "@..." pattern in the - # script is a literal `${...}` bash reference, untouched by this. - etc."auto-install.sh" = { - source = pkgs.replaceVars ../../scripts/installer/auto-install.sh { - inherit (vars) lanDomain; - }; + # scripts/installer/auto-install.sh rather than an inline Nix string. + # It sources scripts/env.sh itself (for LAN_DOMAIN, same as every other + # script in this repo) rather than relying on Nix-level templating, so + # it behaves identically whether it's run straight from a git checkout + # or from here -- baking scripts/env.sh in alongside it at a matching + # relative path (installer/auto-install.sh -> ../env.sh) is what makes + # that resolve correctly in both places. + etc = { + "nixos-installer/env.sh".source = ../../scripts/env.sh; - mode = "0755"; + "nixos-installer/installer/auto-install.sh" = { + source = ../../scripts/installer/auto-install.sh; + mode = "0755"; + }; }; }; @@ -69,7 +73,7 @@ # file-copying/chown. programs.bash.loginShellInit = '' if [ -n "$PS1" ] && [ ! -e "$HOME/.auto_install_ran" ]; then - sudo /etc/auto-install.sh + sudo /etc/nixos-installer/installer/auto-install.sh touch "$HOME/.auto_install_ran" fi ''; diff --git a/scripts/env.sh b/scripts/env.sh index 19edb8b..64ceb5d 100755 --- a/scripts/env.sh +++ b/scripts/env.sh @@ -82,6 +82,12 @@ export PVE1_HOST PVE_TEST_HOST PROXMOX_HOST PROXMOX_SSH_USER PROXMOX_STORAGE \ : "${NIX_CACHE_HOST:=nix-cache}" export NIX_CACHE_HOST +# Matches variables.nix's lanDomain (the Gitea host this flake's own repo +# is served from -- see scripts/installer/auto-install.sh's FLAKE_BASE_URL) +# -- update both if it ever changes. +: "${LAN_DOMAIN:=gitea.lan.ddnsgeek.com}" +export LAN_DOMAIN + # nix_extra_opts: call as a plain statement (NOT inside $(...)/<(...) -- # that forks a subshell, and the whole point is exporting a decision back # into *this* shell) to populate the global NIX_OPTS array with whatever diff --git a/scripts/installer/auto-install.sh b/scripts/installer/auto-install.sh old mode 100644 new mode 100755 index b1f08aa..f35f38b --- a/scripts/installer/auto-install.sh +++ b/scripts/installer/auto-install.sh @@ -1,9 +1,12 @@ -#!/run/current-system/sw/bin/bash +#!/usr/bin/env bash set -eux set -euo pipefail -export FLAKE_BASE_URL="git+https://@lanDomain@/beatzaplenty/nixos.git" +# shellcheck source=../env.sh +source "$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)/env.sh" + +export FLAKE_BASE_URL="git+https://${LAN_DOMAIN}/beatzaplenty/nixos.git" echo "Fetching available NixOS hosts from flake..." # Two categories deliberately excluded from the menu: