Whilst generally not supported by the OpenBSD project, there can
be many benefits to setting up an OpenBSD install to be read-only.
For example it might be for a router or point of sale device that
may encounter power-outage and be unable to shutdown cleanly. If
this were to happen for a standard install, an fsck(8) would happen on the next boot.
Typically this process would not take too long, but if it detects
errors and it cannot automatically solve them, the boot process may
be interrupted. Not ideal for a router use-case.
I personally use this setup on a Raspberry Pi 3 to provide a
simple SOCKS5 proxy (using the inbuilt OpenSSH) to lock some overly
chatty Windows machines behind as well as providing a tunnel to a
non-consumer UK ISP so I can access sites such as The Pirate Bay. So far
it has proven to be remarkably robust.
In general the process is quite straight-forward. Any partition
that needs write access during the typical operation of OpenBSD
needs to be mounted using a memory file-system rather than using
the physical disk. Fortunately OpenBSD provides mount_mfs(8) which serves this purpose nicely.
These key partitions are /tmp, /var and /dev.
If you are installing OpenBSD from scratch, you can skip creating
the /tmp and /var partitions entirely since they
will not be needed.
In order for OpenBSD to start using the memory partitions, the
/etc/fstab file should be modified to remove the existing
/var and /tmp mounts and instead
mount using MFS instead. At this point we should also set all the original partitions read-only. For example this original file:
527591207f2daee9.b none swap sw
527591207f2daee9.a / ffs rw 1 1
527591207f2daee9.k /home ffs rw,nodev,nosuid 1 2
527591207f2daee9.d /tmp ffs rw,nodev,nosuid 1 2
527591207f2daee9.f /usr ffs rw,nodev 1 2
527591207f2daee9.g /usr/X11R6 ffs rw,nodev 1 2
527591207f2daee9.h /usr/local ffs rw,wxallowed,nodev 1 2
527591207f2daee9.j /usr/obj ffs rw,nodev,nosuid 1 2
527591207f2daee9.i /usr/src ffs rw,nodev,nosuid 1 2
527591207f2daee9.e /var ffs rw,nodev,nosuid 1 2
Should end up looking similar to the following (Notice the
ro attribute has replaced rw on the disk partitions):
527591207f2daee9.b none swap sw
527591207f2daee9.a / ffs ro 1 1
527591207f2daee9.k /home ffs ro,nodev,nosuid 1 2
527591207f2daee9.f /usr ffs ro,nodev 1 2
527591207f2daee9.g /usr/X11R6 ffs ro,nodev 1 2
527591207f2daee9.h /usr/local ffs ro,wxallowed,nodev 1 2
527591207f2daee9.j /usr/obj ffs ro,nodev,nosuid 1 2
527591207f2daee9.i /usr/src ffs ro,nodev,nosuid 1 2
swap /tmp mfs rw 0 0
swap /dev mfs rw,-P/dev 0 0
swap /var mfs rw,-P/var,-s32m 0 0
The order of the swap entries are important. This is because
the -P flag for /dev and var is used to
prepopulate the memory partition with a copy of the files on the
phsical disk. It does this by first mounting it on /tmp
before copying the files. This means that /tmp must be
Due to the fact that initial files in the /var is only
a little smaller than the default MFS size of 8 Megs, you should
consider adjusting the size of this memory partition via the
-s argument. In the example above, 32 Megs was specified.
Remember that files are first copied into /tmp which means
that also needs to be large enough to fit these temporary files.
This may be important if you are hosting a large website in there.
With this completed, before we reboot the machine we need to
clean up the original partitions a little to remove any special
files (such as UNIX sockets) which cannot be correctly copied onto
the memory partitions. Otherwise a warning will display in the
system boot logs. These files can be removed using the following:
# rm /dev/log
# rm /dev/slaacd.sock
# rm /var/run/cron.sock
# rm /var/run/ntpd.sock
# rm /var/run/smtpd.sock
These special files will get recreated on the MFS partitions by
their respective daemons upon next startup.
The final step that we need to do to prevent anything writing
to the disk at boot is to unfortunately disable the the kernel
relinking and Address Space Layout Randomization (ASLR). Both are
great security features but unfortunately require modifying the
disk each time the machine is booted. With some effort it could be
possible to perform the task on the MFS partitions but the most
immediate solution for now is to simply disable them. At least they
have run once already.
Add the following to the /etc/rc.conf.local to disable
To disable the kernel relinking, change the
/var/db/kernel.SHA256 to contain:
SHA256 (/bsd) = NO
At this point, you probably want to consider any additional
changes to the install such as adding users, installing 3rd party
packages, etc. When you are ready, restart the machine.
Whilst it is fairly satisfying to be able to pull out the plug
and restart the machine without running the risk of losing data,
this manner of safety unfortunately doesn't quite extend to security.
For example it is still very possible for someone with root access
to be able to remount the disks read/write and modify the
data. However in many ways this is also convenient if you ever need
to tweak the setup. In order to remount the root / partition,
you can use the following command:
# mount -u -orw /
This will remount the root partition with the new write access.
This can be set to read-only again by simply rebooting or via the
-oro argument. Also note that you may want to set a few
more partitions writable depending on the task. For example if you
plan on adding a new user, you will need the /home partition
writable to create their home directory.