First release of installiso

Posted on

One year ago I posted how to script an unattended installation of OpenBSD on the QEMU virtual machine monitor on Linux. The script involved setting up a complicated network boot environment because I treated the installation image as a black box. Of course, I could have mounted the ISO 9660 image and created a modified image using mkisofs(8). But I didn’t know how to insert the autoinstall(8) response file into the RAMDISK kernel in the ISO 9660 image. That was no surprise – why would anyone need to change an OpenBSD kernel on Linux.

OpenBSD, on the other hand, includes adequate utilities. Thanks to vmctl(8), rdsetroot(8), and mkhybrid(8), we can modify the ISO 9660 image and the contained RAMDISK kernel. The exact process is a bit tedious so I decided to automate it. The resulting script is more hacky than pretty but it gets the job done and I found it useful enough to give it a name, installiso, and release it today. Currently, it’s limited to the amd64 architecture, though it should work on other architectures alike. You can download the very first release here. The man page is also viewable here. Feedback appreciated!

In the remainder of this post I’ll show how to use installiso to create custom OpenBSD installation images for unattended – and possibly offline – installation. As an example, I’ll show how to create virtual machines on OpenBSD’s own virtual machine monitor, vmm(4). Finally, I’ll list the concrete commands necessary to patch an installation image without installiso because I would want to know how it works.


You can install the installiso utility as follows.

$ ftp
$ tar -xzf installiso-0.1.0.tar.gz
$ cd installiso-0.1.0/
$ doas make install
$ man 8 installiso

Alternatively, you can run ./installiso.ksh without installation.


Given a response file install.conf, and a file-specific file set site/, you can download, verify, and customize an official installation image as follows.

$ installiso -v fetch -r 6.9
$ doas installiso -v \
    patch -i install.conf -s site/ install69.iso custom.iso

You can also specify a mirror, another release or the latest development snapshot, and a signify(1) public key if you like. See the man page.


You can create a virtual machine on OpenBSD’s own virtual machine monitor, vmm(4), as follows.

First, we create an autoinstall(8) response file. Here, we’ll setup a regular user and authorize an ssh(1) public key. Of course, you can skip this step and have the installer mail you the responses recorded during an interactive installation instead.

$ cat >install.conf <<EOF
Change the default console to com0 = yes
Which speed should com0 use = 115200
System hostname = openbsd-vm
DNS domain name =
Password for root = *************
Start sshd(8) by default = yes
Allow root ssh login = no
Setup a user = $USER
Full name for user $USER = $( userinfo "$USER" | sed -n 's/^gecos[[:space:]]*\(.*\)$/\1/p' )
Password for user = *************
Public ssh key for user = $( cat "$HOME/.ssh/" )
What timezone are you in = UTC
Location of sets = cd0
Set name(s) = site*.tgz
Directory does not contain SHA256.sig. Continue without verification = yes

Second, we create a site-specific file set.

$ mkdir site
$ cat >site/ <<EOF
#! /bin/ksh

set -o errexit

# Set OpenBSD mirror server used by pkg_add(1) and other commands.
echo "$( grep -v -e '^#' -e '^[:space:]*$' /etc/installurl )" > /etc/installurl

# Permit user group wheel to run any command as root
# without entering their password using doas(1).
echo "permit nopass keepenv :wheel" > /etc/doas.conf

# Install packages on the first boot.
echo "pkg_add sqlite3" >> /etc/rc.firsttime
$ chmod +x site/

Third, fetch and patch an installation image as above.

$ installiso -v fetch -r 6.9
$ doas installiso -v \
    patch -i install.conf -s site/ install69.iso custom.iso

Forth, we start a virtual machine off a new disk image and the custom installation image. The OpenBSD FAQ contains a good introduction to vmm(4). I assume you’ve setup the network option 2.

$ vmctl create -s 10G disk.qcow2
$ doas vmctl start -c -i 1 -L -m 512M -d disk.qcow2 \
    -r custom.iso tmp

Finally, we can log into the new virtual machine once the unattended installation has completed.

$ ssh \
    -o "StrictHostKeyChecking no" \
    -o "UserKnownHostsFile /dev/null" \

Disklabel template

In the above example, the OpenBSD installer allocates all disk space automatically, see disklabel(8). You can supply a custom disklabel template instead if you need more control.

First, create a disklabel template.

$ cat >disklabel_template <<EOF
/      5G
swap   1G
/home  2G

Second, add a corresponding URL to the response file.

$ echo "URL to autopartitioning template for disklabel =" >> install.conf

Finally, serve the file during the unattended installation.

$ printf 'HTTP/1.0 200 OK\n\n' |
    cat - disklabel_template |
    nc -lN 8080

Inner workings

The installiso patch command used above

$ doas installiso -v \
    patch -i install.conf -s site/ install69.iso custom.iso

boils down to the following commands – excluding error handling, temporary files, command-line options, etc.

First, we extract the ISO 9660 image.

# vnconfig vnd0 install69.iso
# mount -t cd9660 /dev/vnd0c /mnt
# mkdir cd
# tar -C /mnt -c -f - . | tar -C cd -x -p -f -
# umount /mnt
# vnconfig -u vnd0

Second, we patch the RAMDISK kernel.

# gzip -d -o bsd.rd cd/6.9/amd64/bsd.rd
# rdsetroot -x bsd.rd disk.fs
# vnconfig vnd0 disk.fs
# mount /dev/vnd0a /mnt
# install -o root -g wheel -m 0644 -C \
    install.conf /mnt/auto_install.conf
# umount /mnt
# vnconfig -u vnd0
# rdsetroot bsd.rd disk.fs
# gzip -9fnq bsd.rd

Third, we insert the patched kernel and the site-specific file set into the extracted ISO 9660 image.

# install -o root -g 2000 -m 0755 -C \
    bsd.rd.gz cd/6.9/amd64/bsd.rd
# ( cd site/ && tar -c -z -f ../cd/6.9/amd64/site69.tgz . )
# ( cd cd/6.9/amd64/ && ls -l > index.txt )

Finally, we create the bootable ISO 9660 image.

# mkhybrid -a -R -T -L -l -d -D -N -o custom.iso \
    -A "Custom OpenBSD 6.9 amd64 Install CD" \
    -b 6.9/amd64/cdbr -c 6.9/amd64/boot.catalog \