Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

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 environment
  • unpack-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.