diff --git a/deploy/nixos/README.md b/deploy/nixos/README.md index 062cd5f..55eb522 100644 --- a/deploy/nixos/README.md +++ b/deploy/nixos/README.md @@ -19,7 +19,7 @@ deploy/nixos/ │ └── 99-bitspire-hardware.rules # additional udev rules (loaded via configuration.nix) ├── provision-atm.sh # Push LNbits credentials to a deployed ATM via SSH ├── atm-transactions.sh # Operator query tool — reads /var/lib/bitspire/state.db -├── flash-douro-usb.sh # Helper for flashing a douro live USB +├── flash-douro-usb.sh # Helper for flashing a douro LIVE ISO (not the -usb disk image) └── build-iso.sh # Convenience wrapper for `nix build .#iso-` ``` @@ -33,19 +33,37 @@ Each ATM model has two flake outputs: | `nixosConfigurations.-installed` | installed | full GPT + systemd-boot install, ext4 root, supports `nixos-rebuild switch` | | `packages.x86_64-linux.iso-` | ISO | ISO image of the live variant | | `packages.x86_64-linux.disk-image-` | raw image | dd-able full disk image of the installed variant | -| `nixosConfigurations.-usb` | installed, on a stick | `-installed` hardened to run from a USB stick: `nixos-usb`/`ESP-USB` labels, `nofail` `/boot`, no partition growing, auto-upgrade off (`batm3`, `douro` only) | +| `nixosConfigurations.-usb` | installed, on a stick | `-installed` hardened to run from a USB stick: `nixos-usb`/`ESP-USB` labels, `nofail` `/boot`, no partition growing, auto-upgrade off, `uas` blacklisted | | `packages.x86_64-linux.disk-image--usb` | raw image | dd-able image of the `-usb` variant — flash, plug in, boot; no installer step | -Models: `douro`, `tejo`, `sintra`, `batm3`. +Models: `douro`, `tejo`, `sintra`, `batm3`. All four have `-usb` outputs. -**Run-from-USB deployments** (`batm3` today, `douro` since the LNbits cutover) -skip the Alpine + dd-to-internal-disk procedure below entirely: the stick *is* -the system. Flash `disk-image--usb` with balenaEtcher (it verifies the +**Run-from-USB deployments** skip the Alpine + dd-to-internal-disk procedure +below entirely: the stick *is* the system. That is how `batm3` runs today, how +`douro` runs since the LNbits cutover, and how `tejo` is being brought up — its +internal storage still holds the factory Debian (`ubilinux4`) and is never +touched. Flash `disk-image--usb` with balenaEtcher (it verifies the write — a truncated or bad copy fails stage-1 fsck on first boot) onto a stick of 16 GB or more, plug it in, power on. Updates go in-place against the `-usb` config (`nix copy` the toplevel + `switch-to-configuration`), which keeps pairing and `/var/lib/bitspire`. +### Two bootloader shapes, picked by firmware + +The `-usb` images are not interchangeable between models, because the fleet's +firmware is not: + +| Models | Partition table | Bootloader | Why | +|---|---|---|---| +| `batm3`, `douro` | `efi` (GPT + ESP) | systemd-boot | Their firmware UEFI-USB-boots fine via the ESP's removable `/EFI/BOOT/BOOTX64.EFI` fallback | +| `tejo`, `sintra` | `hybrid` (GPT + `bios_grub` + ESP) | GRUB, BIOS **and** UEFI | Aaeon UP Board firmware USB-boots in Legacy/BIOS mode — it boots the live ISO via isolinux, not the ESP. systemd-boot is UEFI-only, so a dd'd systemd-boot stick isn't recognised as bootable at all. The hybrid image boots either way | + +Both shapes come out of `mkUsbDiskImage` in `flake.nix`; the GRUB override is +`usbGrubHybridModule`. A UP Board `-usb` config installs GRUB with +`devices = [ "nodev" ]` so an in-place `switch-to-configuration` on a live +stick only regenerates `grub.cfg` — the image build is the one place the BIOS +stage gets written to an MBR. + ```bash # Build a Sintra disk image nix build .#disk-image-sintra diff --git a/flake.nix b/flake.nix index 0c90ca8..f7554d9 100644 --- a/flake.nix +++ b/flake.nix @@ -547,6 +547,16 @@ # the Aaeon firmware USB-boots in Legacy/BIOS mode (usbGrubHybridModule), # and the uas/autosuspend hardening from here instead of # hardware/upboard.nix, which sintra's eMMC install also reads. + # + # tejo: the unit still runs its factory Debian (ubilinux4) on internal + # storage, so the stick has to BE the system, same as douro. Its + # internal install is not NixOS and carries no nixos/ESP labels, which + # makes the label disambiguation moot there today — but the hardened + # /boot and the bus settings are what make a stick a reliable boot + # medium, so it takes the identical module set as sintra. + tejo-usb = self.nixosConfigurations.tejo-installed.extendModules { + modules = [ usbBootModule usbBusHardening usbGrubHybridModule ]; + }; sintra-usb = self.nixosConfigurations.sintra-installed.extendModules { modules = [ usbBootModule usbBusHardening usbGrubHybridModule ]; }; @@ -639,6 +649,12 @@ # matter more here than on douro — a sintra's eMMC already holds a # nixos/ESP-labelled install, and stage-1 would otherwise race the two # roots and likely mount the eMMC. + disk-image-tejo-usb = mkUsbDiskImage { + machineModel = "tejo"; + usbConfig = self.nixosConfigurations.tejo-usb; + partitionTableType = "hybrid"; + grubBiosDevice = "/dev/vda"; + }; disk-image-sintra-usb = mkUsbDiskImage { machineModel = "sintra"; usbConfig = self.nixosConfigurations.sintra-usb;