Gardenhouse around the @world

Gardenhouse Installer

Zero-touch deployment tool for Gardenhouse images.

Delivery Modes

  1. USB: Create bootable USB drives for simple deployment
  2. ISO: Generate ISO images for redistribution
  3. PXE: Set up iPXE-based network boot
  4. Factory: Build raw disk images ready for cloning onto hard drives

Options

Boot Flow

  1. UEFI firmware loads BOOTX64.EFI from the ESP
  2. The stem UKI boots with root=stem
  3. Dracut mounts a tmpfs on /sysroot and runs stem-install
  4. stem-install finds the STEMINST labeled partition, locates the images, and installs to the target disk
  5. System reboots into the newly installed OS

ISO Image

Generates a UEFI-bootable ISO image.

Command

$ gardenhouse-installer usb iso \
    --target-profile bamboo \
    --preset-values ./presets.txt \
    --output ./installer.iso

Boot Flow

Identical to USB mode, except the ISO filesystem itself carries the STEMINST label. The stem-install.sh dracut hook mounts the ISO device directly to find the images.

PXE Network Boot

Sets up files for iPXE-based network boot. UEFI PXE chainloading works as follows:

  1. UEFI firmware downloads ipxe.efi via PXE
  2. iPXE loads boot.ipxe
  3. boot.ipxe fetches the stem UKI (stem-uki.efi) and boots it with stem.url=<server>/images/<profile>/
  4. The stem initramfs brings up networking and downloads images from the URL

Setup Server Files

# gardenhouse-installer pxe setup \
    --target-profile bamboo \
    --preset-url http://config.example.com/presets/ \
    --output /var/www/html/ipxe/ \
    --generate-dhcp-config

This produces:

/var/www/html/ipxe/
├── ipxe.efi              # iPXE EFI binary
├── rootloaderx64.efi     # Rootloader (if available)
├── stem-uki.efi          # Stem UKI
├── boot.ipxe             # Main iPXE boot script
├── dhcpd.conf            # Sample DHCP config (optional)
└── images/
    └── bamboo/
    ├── gardenhouse-root_*.img
    ├── gardenhouse-root_*.verity
    ├── gardenhouse-efi_*.efi
    ├── manifest
    └── disk_layout.cfg

Generate Per-Device Scripts

$ gardenhouse-installer pxe generate-script \
    --mac 00:11:22:33:44:55 \
    --profile bamboo \
    --preset-url http://config.example.com/presets/ \
    --server-url http://pxe.example.com/ipxe \
    --output ./device-01.ipxe

iPXE Kernel Command Line

The generated scripts automatically include:

root=stem rd.neednet=1 ip=dhcp stem.profile=bamboo stem.url=http://pxe.example.com/ipxe/images/bamboo/

If you need static IPs instead of DHCP, pass a standard dracut ip= string on the kernel command line.

Factory Disk Image

Creates a complete raw disk image that can be flashed directly onto target devices. The image contains the full partition table, all partitions formatted, and all data written.

Command

# gardenhouse-installer factory image \
    --target-profile bamboo \
    --preset-values ./factory.txt \
    --output ./factory.img \
    --compress zstd \
    --level 19

Options

Media Verification

The verify command checks that installation media (USB directory, ISO file, factory image, or raw block device) matches the manifest.

# gardenhouse-installer verify --media /dev/sdX1
# gardenhouse-installer verify --media ./installer.iso --ignore-missing

It validates checksums for all files listed in the manifest and reports any mismatches.

Preset Values

Preset values allow zero-touch configuration of the target system. They are rendered at install time and written to the USERDATA partition as /preset_values. On first boot, the firstboot script reads this file and applies the settings.

Template Variables

The installer supports automatic substitution of these placeholders when creating installation media:

Generating a Password Hash Manually

If you prefer not to use {{GENERATE}}, generate your own hash:

$ openssl passwd -6 "your_password"

Example Preset File

See examples/preset_values for a fully documented template. A minimal configuration looks like this:

FIRSTBOOT_UNATTENDED=yes
HOSTNAME=gh-{{RANDOM}}
MACHINE_ID={{UUID}}
TIMEZONE=UTC
ADMIN_USERNAME=admin
ADMIN_PASSWORD_HASH={{GENERATE}}
HOMECRYPT=no
ROOT_DISABLED=yes
SSH_AUTHORIZED_KEYS=""
FIRST_BOOT_SCRIPT=""

Required Fields for Zero-Touch

When FIRSTBOOT_UNATTENDED=yes, the firstboot script runs without prompting. These fields must be populated:

If any required field is missing, firstboot exits with an error.

Preset File Format

Preset files are plain text with KEY=value pairs. Lines starting with # are treated as comments. Values can contain template variables which are replaced at install time.

# This is a comment
HOSTNAME=server-{{SERIAL}}
ADMIN_USERNAME=admin
ADMIN_PASSWORD_HASH=$6$rounds=5000$...

Multi-line values (like SSH_AUTHORIZED_KEYS) should use quoted strings:

SSH_AUTHORIZED_KEYS="ssh-ed25519 AAAAC3NzaC... user@example.com
ssh-rsa AAAAB3NzaC... backup@example.com"

Firstboot Behavior

The firstboot OpenRC service runs once on the target system's initial boot. It performs the following actions:

  1. Load presets from /user/preset_values
  2. Create the admin user (ADMIN_USERNAME)
  3. Set passwords
  1. Set hostname (HOSTNAME)
  2. Set timezone (TIMEZONE)
  3. Write machine ID (MACHINE_ID, or auto-generate)
  4. Install SSH authorized keys (SSH_AUTHORIZED_KEYS)
  5. Run first-boot script (FIRST_BOOT_SCRIPT) if set
  6. Mark completion by touching /user/.firstboot_completed

Password Hash Detection

firstboot automatically detects password hashes:

First-Boot Script

FIRST_BOOT_SCRIPT can be:

For URLs, the script is downloaded to /tmp/firstboot-script and executed with bash.

CLI Usage

Pass presets to any installer mode:

# gardenhouse-installer usb create \
    --target-profile bamboo \
    --preset-values ./my_presets \
    --output /dev/sdX

Source

Gardenhouse Installer can be downloaded from https://git.pinkro.se/Rose/gardenhouse/gardenhouse-installer.git/about/

It is also mirrored at Codeberg where issues are tracked.