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:
- Use separate answers files per machine
- Set the hostname after install via Salt/Ansible
- 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.