| pick your distro, get ZFS on root
kldload — your platform, your way, free
Source

Unattended Installation

kldload supports fully automated installs via an answers file — no web UI or user interaction required. Boot the ISO, and it installs to disk using pre-defined settings.

Works for all supported targets: CentOS, Debian, Ubuntu, Fedora, Rocky, RHEL, Arch, FreeBSD, and OpenBSD.

This is the mechanism that turns kldload from an interactive installer into a deployment platform.

An answers file is 10-15 lines of environment variables on a FAT32 USB stick. That's the entire API for unattended deployment. No YAML. No Jinja templates. No 400-line kickstart file. No preseed with undocumented d-i directives. Ten lines in a flat file. The machine boots, finds the answers, installs itself, and powers off. Zero interaction. Zero network dependency. Zero infrastructure prerequisites.

The power is in what's NOT here: no PXE server, no TFTP, no DHCP options, no network boot infrastructure. A USB stick and a power button. That's deployment. Want 50 machines? Write 50 answer files (one per hostname), burn 50 USB sticks (same ISO, different answer files), plug them in, boot them. Come back to 50 installed machines with ZFS on root.


The answers file

The installer reads environment variables from a file. Create one:

cat > answers.env << 'EOF'
KLDLOAD_DISTRO=debian
KLDLOAD_DISK=/dev/vda
KLDLOAD_HOSTNAME=web-server-01
KLDLOAD_USERNAME=admin
KLDLOAD_PASSWORD=changeme
KLDLOAD_PROFILE=server
KLDLOAD_STORAGE_MODE=zfs
KLDLOAD_ZFS_ENCRYPT=0
KLDLOAD_NET_METHOD=dhcp
KLDLOAD_TIMEZONE=America/New_York
KLDLOAD_LOCALE=en_US.UTF-8
KLDLOAD_KEYBOARD_LAYOUT=us
EOF

All supported variables

Variable Values Default Description
KLDLOAD_DISTRO centos, debian, ubuntu, fedora, rhel, rocky, arch, freebsd, openbsd Target distro
KLDLOAD_DISK /dev/vda, /dev/sda, etc. Install disk
KLDLOAD_HOSTNAME any hostname kldload-node System hostname
KLDLOAD_USERNAME any username admin Admin user
KLDLOAD_PASSWORD any string User password
KLDLOAD_PROFILE desktop, server, core desktop Install profile
KLDLOAD_STORAGE_MODE zfs zfs Always ZFS
KLDLOAD_ZFS_ENCRYPT 0, 1 0 Enable encryption
KLDLOAD_NET_METHOD dhcp, static dhcp Network config
KLDLOAD_NET_IP IP/CIDR Static IP (if static)
KLDLOAD_NET_GATEWAY IP Gateway (if static)
KLDLOAD_NET_DNS IP DNS server (if static)
KLDLOAD_TIMEZONE tz database name UTC Timezone
KLDLOAD_LOCALE locale string en_US.UTF-8 System locale
KLDLOAD_KEYBOARD_LAYOUT us, de, etc. us Keyboard layout
KLDLOAD_NVIDIA_DRIVERS 0, 1 0 Install NVIDIA drivers (auto-detects hardware)
KLDLOAD_ENABLE_EBPF 0, 1 0 Install eBPF tools
KLDLOAD_ZFS_TOPOLOGY single, mirror, raidz1, mirror-stripe single Pool vdev layout (permanent, cannot be changed)
KLDLOAD_ZFS_DATA_DISKS space-separated paths Extra disks for multi-disk topologies
KLDLOAD_ENABLE_KVM 0, 1 0 Install KVM/QEMU/libvirt, create VM datasets
KLDLOAD_ENABLE_WIREGUARD 0, 1 1 Include WireGuard (on by default)
KLDLOAD_SSH_PUBKEY SSH public key string Paste authorized_keys entry for admin user
KLDLOAD_STORAGE_MANUAL 0, 1 0 Drop to shell for manual pool creation
KLDLOAD_INFRA_MODE standalone, cluster-manager, join standalone Deployment mode
KLDLOAD_HUB_LAN IP CM IP (if join mode)

Run the install manually

From the live ISO command line:

kldload-install-target --config /path/to/answers.env

Inject the answers file into the ISO

Method 1: USB sidecar

Place answers.env on a second USB drive. The installer checks: - /run/kldload-answers.env - /mnt/answers.env - /etc/kldload/answers.env

# Format a small USB stick
mkfs.fat -F32 /dev/sdb1
mount /dev/sdb1 /mnt
cp answers.env /mnt/answers.env
umount /mnt

Boot the kldload ISO with the answers USB plugged in. The installer detects it automatically.

Method 2: Bake into the ISO

Add the file to live-build/config/includes.chroot/ before building:

cp answers.env live-build/config/includes.chroot/etc/kldload/answers.env
PROFILE=server ./deploy.sh build

Method 3: Kernel command line

Pass the config file path on the GRUB command line:

Edit live-build/config/includes.binary/EFI/BOOT/grub.cfg:

linuxefi /images/pxeboot/vmlinuz ... kldload.config=/etc/kldload/answers.env

Three methods, three use cases:

USB sidecar = field deployment. Mail the ISO and the seed disk together. The field tech plugs both in and presses power. No training needed. No internet needed. The machine does the rest.

Baked into ISO = factory imaging. Every ISO produces the exact same machine. Burn 100 USBs, deploy 100 identical servers. The answer file is part of the artifact. Version control the answer file alongside the build config.

Kernel command line = PXE/iPXE network boot. If you DO have PXE infrastructure, pass the config path on the command line. The installer reads it at boot. Works with any network boot system that can modify kernel parameters.

Example: fleet of identical servers

Build 10 identical servers:

cat > answers.env << 'EOF'
KLDLOAD_DISTRO=centos
KLDLOAD_DISK=/dev/sda
KLDLOAD_USERNAME=admin
KLDLOAD_PASSWORD=fleetpass123
KLDLOAD_PROFILE=server
KLDLOAD_NET_METHOD=dhcp
KLDLOAD_TIMEZONE=UTC
EOF

Each server will get the same config except the hostname, which defaults to kldload-node. To set unique hostnames, either:

  1. Use separate answers files per machine
  2. Set the hostname after install via Salt/Ansible
  3. Use a firstboot script that derives the hostname from the MAC address

Example: encrypted desktop

cat > answers.env << 'EOF'
KLDLOAD_DISTRO=debian
KLDLOAD_DISK=/dev/nvme0n1
KLDLOAD_HOSTNAME=dev-workstation
KLDLOAD_USERNAME=developer
KLDLOAD_PASSWORD=securepass
KLDLOAD_PROFILE=desktop
KLDLOAD_ZFS_ENCRYPT=1
KLDLOAD_NVIDIA_DRIVERS=0
KLDLOAD_ENABLE_EBPF=1
KLDLOAD_NET_METHOD=dhcp
KLDLOAD_TIMEZONE=America/Los_Angeles
EOF

Example: static IP server

cat > answers.env << 'EOF'
KLDLOAD_DISTRO=centos
KLDLOAD_DISK=/dev/sda
KLDLOAD_HOSTNAME=db-primary
KLDLOAD_USERNAME=admin
KLDLOAD_PASSWORD=dbpass
KLDLOAD_PROFILE=server
KLDLOAD_NET_METHOD=static
KLDLOAD_NET_IP=10.100.10.50/24
KLDLOAD_NET_GATEWAY=10.100.10.1
KLDLOAD_NET_DNS=1.1.1.1
KLDLOAD_TIMEZONE=UTC
EOF

Example: core (ZFS only, no extras)

cat > answers.env << 'EOF'
KLDLOAD_DISTRO=debian
KLDLOAD_DISK=/dev/sda
KLDLOAD_HOSTNAME=zfs-node
KLDLOAD_USERNAME=admin
KLDLOAD_PASSWORD=changeme
KLDLOAD_PROFILE=core
KLDLOAD_NET_METHOD=dhcp
KLDLOAD_TIMEZONE=UTC
EOF

This installs a stock Debian with ZFS on root, ZFSBootMenu, SSH, and networking. No k* tools, no web UI, no sanoid, no darksites. Manage everything with native zfs, zpool, apt/dnf commands.

Notice what all four examples have in common: they're 8-12 lines of flat environment variables. No heredocs inside heredocs. No YAML indentation. No XML. No JSON with nested objects. If you can write KEY=value, you can automate kldload. The answer file format was chosen because it's the simplest possible API for deployment automation. It's also the format that every CI system, every shell script, and every Docker entrypoint already understands.

The examples also show the power of the profile system: the same ISO with KLDLOAD_PROFILE=server produces a headless SSH server. With KLDLOAD_PROFILE=desktop, it's a GNOME workstation. With KLDLOAD_PROFILE=core, it's a blank canvas. Three answer files, three completely different machines, one USB stick.


Post-install automation

After the base install, kldload runs a firstboot service. You can hook into this:

# Create a post-install script
cat > live-build/config/includes.chroot/usr/local/sbin/my-firstboot.sh << 'SCRIPT'
#!/bin/bash
# Runs once after first boot

# Install additional packages
kpkg install htop tmux

# Configure NTP
timedatectl set-ntp true

# Start your application
systemctl enable --now myapp

# Remove this script after running
rm -f /usr/local/sbin/my-firstboot.sh
SCRIPT
chmod +x live-build/config/includes.chroot/usr/local/sbin/my-firstboot.sh

Wire it into the firstboot service or create a systemd oneshot:

cat > live-build/config/includes.chroot/etc/systemd/system/my-firstboot.service << 'EOF'
[Unit]
Description=Custom firstboot
After=network-online.target kldload-firstboot.service
Wants=network-online.target

[Service]
Type=oneshot
ExecStart=/usr/local/sbin/my-firstboot.sh
RemainAfterExit=yes

[Install]
WantedBy=multi-user.target
EOF

Rebuild the ISO to include it.