Runbook: Custom Installer USB
Status: living
Use this when installing Dubnium from private installer media without relying on GitHub credentials during the live install.
The current Dubnium installer flow writes the custom ISO to one physical USB stick as a raw disk image, matching Rufus “DD image mode” behavior:
dubnium-installer.iso -> whole USB disk
The installer image bakes an exported source snapshot of this repo and the
external/dotfiles submodule into the live system. The snapshot excludes .git
directories, so it is source content rather than a Git working copy with
history. Treat the USB as private media because it contains the private Dubnium
source.
Model seed bundles are separate from raw USB writing. Put the materialized bundle on separate media, or build it into a future image format explicitly.
What This Provides
- no GitHub token during install
- no install-time private GitHub clone
git,jq,rsync,vim, and install helpers in the live environmentunpack-dubnium, which unpacks the baked source snapshot to:
~/local/src/dubnium
- raw whole-disk USB writing for the custom installer ISO
Build The Installer ISO
Before baking, make sure the repo and submodule state are intentionally clean or intentionally staged. The flake source snapshot only sees tracked files.
git status --short
git -C external/dotfiles status --short
scripts/build-installer-iso.sh \
--iso ./dubnium-installer.iso
By default the script ensures the current Dubnium default seed bundle
idempotently for separate seed media. The seed contract is model-agnostic: the
seed must be a materialized model directory with config.json and SHA256SUMS.
Detection first checks DUBNIUM_SEED_MODEL, then common paths beside the repo
for the current default bundle.
Use --seed-model to override detection, --no-seed-download to require a
pre-existing bundle, or --no-seed-model to build installer-only media.
The script is a wrapper around this build:
nix --extra-experimental-features 'nix-command flakes' \
build .#nixosConfigurations.installer.config.system.build.isoImage
The ISO appears under:
result/iso/
The ISO build uses Nix’s flake source snapshot and bakes that source into the
installer image. This is an export-style payload: no .git directories and no
Git history.
Create A Standalone Git Export Payload
If you want a source artifact separate from the ISO, use the git-export helper:
scripts/export-installer-source.sh dubnium-installer-source.tar.gz
The helper requires the main repo and external/dotfiles submodule to be clean.
It uses git archive for both sources and writes a payload shaped like:
dubnium/
└── external/
└── dotfiles/
This payload is useful for inspection, offline transfer, or alternate installer media. The custom ISO still bakes its own payload from the same flake source that Nix evaluates.
Verify The Baked Payload
The built payload should contain the workstation host, dotfiles submodule source, and USB helpers:
payload="$(find /nix/store -maxdepth 1 -name '*-dubnium-installer-source.tar.gz' | head -n 1)"
tar -tzf "$payload" | grep -E \
'^dubnium/(flake.nix|hosts/workstation/default.nix|external/dotfiles/flake.nix|scripts/build-installer-iso.sh|scripts/export-installer-source.sh|scripts/write-installer-usb.ps1|scripts/write-installer-usb.sh)$'
if tar -tzf "$payload" | grep -q '/\.git/'; then
echo "unexpected .git directory in payload"
exit 1
fi
Prepare The USB From Windows PowerShell
After building dubnium-installer.iso, use this helper only when preparing the
USB from Windows PowerShell. It writes the ISO bytes directly to the whole USB
disk, like Rufus DD image mode:
.\scripts\write-installer-usb.ps1 `
-IsoPath .\dubnium-installer.iso `
-DiskNumber 7 `
-ExpectedFriendlyName "USB SanDisk 3.2Gen1"
The script refuses to continue unless the selected disk is the expected USB
device. It overwrites the whole disk with the ISO image. -SeedModelPath is
intentionally rejected in raw mode because there is no separate writable seed
partition to copy into.
After writing, eject and reinsert the USB if Windows does not refresh the new ISO layout immediately. Verify the installer media from whichever drive letter Windows assigns:
Test-Path I:\EFI\BOOT\BOOTX64.EFI
Test-Path I:\nix-store.squashfs
Get-Volume -DriveLetter I
Prepare The USB From macOS Or Linux
The Bash helper performs the same raw whole-disk image write on macOS or Linux. Pass the whole USB disk, not a partition.
Linux example:
lsblk -o NAME,SIZE,MODEL,TRAN,TYPE,MOUNTPOINTS
scripts/write-installer-usb.sh \
--iso ./dubnium-installer.iso \
--disk /dev/sdX \
--expected SanDisk
macOS example:
diskutil list
diskutil info /dev/diskN
scripts/write-installer-usb.sh \
--iso ./dubnium-installer.iso \
--disk /dev/diskN \
--expected SanDisk
The script refuses to write non-removable media, requires the selected device
identity to contain --expected when provided, and asks for
y at the Proceed? [y/N]: prompt before erasing the disk unless --yes is passed.
Optional One-Shot Wrappers
The older wrappers still exist for convenience, but they are not the preferred boundary:
.\scripts\build-installer-usb.ps1 `
-DiskNumber 7 `
-ExpectedFriendlyName "USB SanDisk 3.2Gen1"
bash scripts/build-installer-usb.sh \
--disk /dev/sdX \
--expected SanDisk
Use the Bash one-shot path only when the whole USB disk is visible inside the Linux environment.
Seamless USB Acceptance Check
Before leaving the build machine, verify the USB contains everything needed for a token-free install:
EFI/BOOT/BOOTX64.EFI
nix-store.squashfs
The install path should not require:
- a GitHub token
- a private SSH key
- a Hugging Face download during install when separate model seed media is used
- copying model weights into the Dubnium Git tree
Keep the USB physically private. It contains private source code in the installer payload.
Add The Model Seed Bundle
Do not copy the raw Hugging Face cache directory as the seed. The cache uses
refs, blobs, snapshots, and symlinks. Seed media should contain a normal
local model bundle.
Use separate writable media for the model seed bundle. Mount that media and copy a materialized model directory:
sudo mkdir -p /mnt/e
sudo mount -t drvfs E: /mnt/e
sudo mkdir -p /mnt/e/models
sudo rsync -a --info=progress2 \
/path/to/selected-model-bundle/ \
/mnt/e/models/selected-model-bundle/
Expected seed path:
models/selected-model-bundle/
Lightweight bundle check:
test -f /mnt/e/models/selected-model-bundle/config.json
test -f /mnt/e/models/selected-model-bundle/SHA256SUMS
See Model Seeding for creating the bundle and checksum manifest.
Install From The USB
Boot the target machine from the USB. Prefer the UEFI entry for the Dubnium installer USB.
For the guarded one-shot path, run the helper with no arguments:
install-dubnium-from-usb
The helper prints lsblk, prompts for the target whole disk, and then prompts
for install options. Defaults are btrfs for the root filesystem,
dubnium for the Home Manager machine profile, passwd for password setup,
and copying the install snapshot to /root/dubnium-install-snapshot in the
installed system.
This command erases the selected whole disk, unpacks the baked source snapshot,
generates hosts/workstation/hardware-configuration.nix, and runs:
sudo nixos-install --flake .#workstation
Use --dry-run to print the plan without touching disks. Use --user USER to
write hosts/workstation/user.nix before install. Use
--home-profile dubnium|technetium to select the Home Manager machine profile
that installs the matching ~/.config/hypr/adopted.d/machine.conf. Use
--password-mode hash to write a host-local initial password hash before
install, or --password-mode skip when another login path already exists; the
default passwd mode sets the password inside the installed system after
nixos-install. Use --no-copy-source if you do not want the install snapshot
preserved for post-install reconciliation.
The one-shot command still prints the plan and requires final confirmation:
Proceed? [y/N]:
Use --yes only for rehearsed installs where the disk identity was already
verified.
Manual path:
In the live installer terminal:
unpack-dubnium
cd ~/local/src/dubnium
Confirm the baked source exists:
test -f flake.nix
test -f hosts/workstation/default.nix
test -f external/dotfiles/flake.nix
Then continue the fresh-install flow from the local checkout:
sudo nixos-install --flake .#workstation
The workstation target imports the Dubnium Home Manager module from
external/dotfiles, so the Dubnium dotfiles profile is applied to the selected
normal user as part of the system install.
Install For Another User
To choose the installed normal user, create hosts/workstation/user.nix in the
unpacked source before running nixos-install:
{
dubnium.user.name = "alice";
dubnium.user.description = "Example User";
}
Then install normally:
sudo nixos-install --flake .#workstation
The same dotfiles Dubnium Home Manager profile is applied to the selected user.
The profile source lives in the dotfiles submodule, but the username and home
directory are supplied by dubnium.user.name.
unpack-dubnium --user USER only changes where the source is unpacked in the
live installer session. It does not change the installed NixOS user; use
dubnium.user.name for that.
After First Boot
After the installed system boots, seed the vLLM model store from the bundle on separate seed media and verify the checksum manifest before starting compute mode. See Model Seeding for the exact restore commands.
What Not To Put On The USB
Avoid storing:
- long-lived private SSH keys
- reusable GitHub credentials
- generated age identity files
- decrypted SOPS files
- model weights inside the Git repo or ISO payload
- raw Hugging Face cache directories as the seed shape
The source snapshot and a separate materialized model bundle are enough for this installer flow.