<- Back

# OpenBSD: setup a local auto-installation server

Last modification on 2020-04-30

This guide describes how to setup a local mirror and installation/upgrade
server that requires little or no input interaction.


## Setup a local HTTP mirror

The HTTP mirror will be used to fetch the base sets and (optional) custom sets.
In this guide we will assume **192.168.0.2** is the local installation server
and mirror, the CPU architecture is amd64 and the OpenBSD release version is
6.5.  We will store the files in the directory with the structure:

        http://192.168.0.2/pub/OpenBSD/6.5/amd64/

Create the www serve directory and fetch all sets and install files
(if needed to save space *.iso and install65.fs can be skipped):

        $ cd /var/www/htdocs
        $ mkdir -p pub/OpenBSD/6.5/amd64/
        $ cd pub/OpenBSD/6.5/amd64/
        $ ftp 'ftp://ftp.nluug.nl/pub/OpenBSD/6.5/amd64/*'

Verify signature and check some checksums:

        $ signify -C -p /etc/signify/openbsd-65-base.pub -x SHA256.sig
Setup »httpd(8)« for simple file serving:
        # $FAVORITE_EDITOR /etc/httpd.conf
A minimal example config for »httpd.conf(5)«:
        server "*" {
                listen on * port 80
        }

The default www root directory is: /var/www/htdocs/

Enable the httpd daemon to start by default and start it now:

        # rcctl enable httpd
        # rcctl start httpd

## Creating an installation response/answer file

The installer supports loading responses to the installation/upgrade questions
from a simple text file. We can do a regular installation and copy the answers
from the saved file to make an automated version of it.

Do a test installation, at the end of the installation or upgrade when asked the
question:

        Exit to (S)hell, (H)alt or (R)eboot?

Type S to go to the shell. Find the response file for an installation and copy
it to some USB stick or write down the response answers:

        cp /tmp/i/install.resp /mnt/usbstick/

A response file could be for example:

        System hostname = testvm
        Which network interface do you wish to configure = em0
        IPv4 address for em0 = dhcp
        IPv6 address for em0 = none
        Which network interface do you wish to configure = done
        Password for root account = $2b$10$IqI43aXjgD55Q3nLbRakRO/UAG6SAClL9pyk0vIUpHZSAcLx8fWk.
        Password for user testuser = $2b$10$IqI43aXjgD55Q3nLbRakRO/UAG6SAClL9pyk0vIUpHZSAcLx8fWk.
        Start sshd(8) by default = no
        Do you expect to run the X Window System = no
        Setup a user = testuser
        Full name for user testuser = testuser
        What timezone are you in = Europe/Amsterdam
        Which disk is the root disk = wd0
        Use (W)hole disk MBR, whole disk (G)PT, (O)penBSD area or (E)dit = OpenBSD
        Use (A)uto layout, (E)dit auto layout, or create (C)ustom layout = a
        Location of sets = http
        HTTP proxy URL = none
        HTTP Server = 192.168.0.2
        Server directory = pub/OpenBSD/6.5/amd64
        Unable to connect using https. Use http instead = yes
        Location of sets = http
        Set name(s) = done
        Location of sets = done
        Exit to (S)hell, (H)alt or (R)eboot = R

Get custom encrypted password for response file:

        $ printf '%s' 'yourpassword' | encrypt


## Changing the RAMDISK kernel disk image
»rdsetroot(8)« is publicly exposed now in base since 6.5. Before 6.5 it is
available in the /usr/src/ tree as elfrdsetroot, see also the »rd(4)« man page.
        $ mkdir auto
        $ cd auto
        $ cp pubdir/bsd.rd .
        $ rdsetroot -x bsd.rd disk.fs
        # vnconfig vnd0 disk.fs
        # mkdir mount
        # mount /dev/vnd0a mount

Copy the response file (install.resp) to: mount/auto_install.conf
(installation) **or** mount/auto_upgrade.conf (upgrade), but not both. In this
guide we will do an auto-installation.

Unmount, detach and patch RAMDISK:

        # umount mount
        # vnconfig -u vnd0
        $ rdsetroot bsd.rd disk.fs

To test copy bsd.rd to the root of some testmachine like /bsd.test.rd then
(re)boot and type:

        boot /bsd.test.rd

In the future (6.5+) it will be possible to copy to a file named "/bsd.upgrade"
in the root of a current system and automatically load the kernel:
See the script bsd.upgrade in CVS.
Of course this is possible with PXE boot or some custom USB/ISO also.
As explained in the »autoinstall(8)« man page: create either an
auto_upgrade.conf **or** an auto_install.conf, but not both.


## Create bootable miniroot

In this example the miniroot will boot the custom kernel, but fetch all the
sets from the local network.

We will base our miniroot of the official version: miniroot65.fs.

We will create a 16MB miniroot to boot from (in this guide it is assumed the
original miniroot is about 4MB and the modified kernel image fits in the new
allocated space):

        $ dd if=/dev/zero of=new.fs bs=512 count=32768

Copy first part of the original image to the new disk (no truncation):

        $ dd conv=notrunc if=miniroot65.fs of=new.fs
        # vnconfig vnd0 new.fs

Expand disk OpenBSD boundaries:

        # disklabel -E vnd0
        > b
        Starting sector: [1024]
        Size ('*' for entire disk): [8576] *
        > r
        Total free sectors: 1168.
        > c a
        Partition a is currently 8576 sectors in size, and can have a maximum
        size of 9744 sectors.
        size: [8576] *
        > w
        > q

or:

        # printf 'b\n\n*\nc a\n*\nw\n' | disklabel -E vnd0

Grow filesystem and check it and mark as clean:

        # growfs -y /dev/vnd0a
        # fsck -y /dev/vnd0a

Mount filesystem:

        # mount /dev/vnd0a mount/

The kernel on the miniroot is GZIP compressed. Compress our modified bsd.rd and
overwrite the original kernel:

        # gzip -c9n bsd.rd > mount/bsd

Or to save space (+- 500KB) by stripping debug symbols, taken from bsd.gz target
in this Makefile.
        $ cp bsd.rd bsd.strip
        $ strip bsd.strip
        $ strip -R .comment -R .SUNW_ctf bsd.strip
        $ gzip -c9n bsd.strip > bsd.gz
        $ cp bsd.gz mount/bsd

Now unmount and detach:

        # umount mount/
        # vnconfig -u vnd0
Now you can »dd(1)« the image new.fs to your bootable (USB) medium.

## Adding custom sets (optional)
For patching »/etc/rc.firsttime« and other system files it is useful to use a
customized installation set like siteVERSION.tgz, for example: site65.tgz.  The
sets can even be specified per host/MAC address like
siteVERSION-$(hostname -s).tgz so for example: site65-testvm.tgz

When the installer checks the base sets of the mirror it looks for a file
index.txt.  To add custom sets the site entries have to be added.

For example:

        -rw-r--r--  1 1001  0    4538975 Oct 11 13:58:26 2018 site65-testvm.tgz

The filesize, permissions etc do not matter and are not checked by the
installer.  Only the filename is matched by a regular expression.


## Sign custom site* tarball sets (optional)

If you have custom sets without creating a signed custom release you will be
prompted for the messages:

        checksum test failed

and:

        unverified sets: continue without verification
OpenBSD uses the program »signify(1)« to cryptographically sign and
verify filesets.

To create a custom public/private keypair (ofcourse make sure to store the
private key privately):

        $ signify -G -n -c "Custom 6.5 install" -p custom-65-base.pub -s custom-65-base.sec

Create new checksum file with filelist of the current directory (except SHA256*
files):

        $ printf '%s\n' * | grep -v SHA256 | xargs sha256 > SHA256

Sign SHA256 and store as SHA256.sig, embed signature:

        $ signify -S -e -s /privatedir/custom-65-base.sec -m SHA256 -x SHA256.sig

Verify the created signature and data is correct:

        $ signify -C -p /somelocation/custom-65-base.pub -x SHA256.sig

Copy **only** the **public** key to the RAMDISK:

        $ cp custom-65-base.pub mount/etc/signify/custom-65-base.pub

Now we have to patch the install.sub file to check our public key.  If you know
a better way without having to patch this script, please let me know.

Change the variable PUB_KEY in the shellscript mount/install.sub from:

        PUB_KEY=/etc/signify/openbsd-${VERSION}-base.pub

To:

        PUB_KEY=/etc/signify/custom-${VERSION}-base.pub

And for upgrades from:

        $UPGRADE_BSDRD &&
                PUB_KEY=/mnt/etc/signify/openbsd-$((VERSION + 1))-base.pub

To:

        $UPGRADE_BSDRD &&
                PUB_KEY=/mnt/etc/signify/custom-$((VERSION + 1))-base.pub


## Ideas
* Patch »rc.firsttime(8)«: and run syspatch, add ports, setup xenodm etc.
* Custom partitioning scheme, see »autoinstall(8)« "URL to autopartitioning
  template for disklabel = url".
* Setup »pxeboot(8)« to boot and install over the network using
  »dhcpd(8)« and
  »tftpd(8)« then not even some USB stick is required.

## References

* Main OpenBSD installation and upgrade shellscript:
  /usr/src/distrib/miniroot/install.sub