I’ve used OpenBSD on and off since 2.1. More back then than in the last 10 years or so though, so I thought I’d try it again.

What triggered this was me finding a silly bug in GNU cpio that has existed with a “FIXME” comment since at least 1994. I checked OpenBSD to see if it had a related bug, but as expected no it was just fine.

I don’t quite remember why I stopped using OpenBSD for servers, but I do remember filesystem corruption on “unexpected power disconnections” (even with softdep turned on), which I’ve never really seen on Linux.

That and that fewer things “just worked” than with Linux, which matters more when I installed more random things than I do now. I’ve become a lot more minimalist. Probably due to less spare time. Life is better when you don’t run things like PHP (not that OpenBSD doesn’t support PHP, just an example) or your own email server with various antispam tooling, and other things.

This is all experience from running OpenBSD on a server. On my next laptop I intend to try running OpenBSD on the desktop, and will see if that more ad-hoc environment works well. E.g. will gnuradio work? Lack of other-OS VM support may be a problem.

How to run OpenBSD in 2019

The easiest way to run servers nowadays is to just rent VMs on public clouds. Unfortunately most clouds don’t support OpenBSD. Vultr does, and they’re pretty good. They have IPv6-only VMs (US locations only) that are only $2.50/month ($3.50/month with IPv4). They also, unlike some other cloud vendors, give access to the actual console, which is very helpful.

I installed OpenBSD 6.5 (the newest, at the time), and tried it out.

The good

  • Security mindset. Should go without saying, but it’s a perfectly usable Unix system that places security first. They may not be first (e.g. took them years to reinvent W^X behind Linux), but they were the first to turn on the features by default, and you can trust them to continue to do so. E.g. who else bothers to link a unique kernel per system?

  • Ports and packages end up in /usr/local, and anything outside that either you put there, or it’s the base system. Sure, it means /usr/local may be a bit of a mess, but outside of it isn’t.

  • It’s clear what base system you’re running. Kernel and everything is plainly “6.6” (or whatever). Well… plus any syspatch fixes.

  • Upgrading the system to OpenBSD 6.6 was easy. I had my fears, but it was about as easy as installing. I used the classic method that requires taking the server out of commission and console access, for running the installer. But with 6.5->6.6 they’ve created sysupgrade that can do this on a live system.

  • The init system has gotten start/stop scripts, in /etc/rc.d. From what I remember /etc/rc used to be one big start script, with no good way to restart services without remembering what took a HUP, what wanted its own tool, etc…

  • Most things just worked. My Go code worked fine. Well, except for an annoying bug in Go’s sys/unix and syscall libraries, that (like the GNU cpio bug) is not a great sign of quality.

  • Modern enough clang to support C++17. The GCC version is stuck in the stone age because of licensing, but clang is a worthy replacement now. Development should be good here.

  • Since I’d fixed some MPLS code a long time ago I read through the MPLS forwarding code. Like when I checked OpenBSD’s cpio code I found it of very high quality, with APIs designed such that it’s hard to use them incorrectly, or to leak resources.

  • I generally find the OpenBSD manpages to be of higher quality than GNU ones. Also nice to have man section 9 (kernel internals) installed by default.

The bad

It’s less smooth to use. It lacks many convenience options in tools. Some examples:

  • Upgrading has a bunch of manual cleanup steps. Edit: you can install package sysclean, which will do this for you. But you have to install and run it yourself, as opposed to being part of the upgrade.

  • I can reliably crash it by using too much RAM. Completely freezes it, even the console and not answering ping. I don’t know if this is OpenBSD’s fault, or a result of it being in a VM, or something on Vultr’s side. Adding some more swap helped, but that just delays the problem.

  • On my Vultr system there was no default package repo path, so I had to choose a mirror myself and set PKG_PATH. And since I’m on an IPv6-only VM I had to check a few before finding one that had an IPv6 address. Unclear if this was OpenBSD or Vultr’s misconfig, because apparently it’s supposed to “just work” by having /etc/installurl point to a mirror but on Vultr it’s empty.

  • find requires a path argument. I don’t see why it can’t default to . like on Linux.

  • du doesn’t take a -m switch. Workaround is BLOCKSIZE=1000000 du -cs * which is not as friendly for numerical sorting.

  • which brings me to: if the correction to SI units was lacking in Linux it’s completely absent in OpenBSD. I’m guessing they’ve chosen not to.

  • OpenBSD’s tar can’t read /etc/spwd.db due to security features, which is great and all, but prevents backing up /etc and being able to check exit code for success of everything else. It also doesn’t support exclusion or inclusion lists. I would have changed my portable backupscripts to cpio, but because GNU cpio has the bug mentioned earlier I can’t. OpenBSD’s default shell (ksh) has support for glob exclusions, as does bash. But it’s not a great solution (cmdline length for one, and this could be its own blog post so I’ll stop here). Luckily you can install GNU tar as a package and use that.

  • TCP MD5 seems to be implemented as system-wide settings. It’s understandable but I don’t like it. More on that here.

  • After upgrading to OpenBSD 6.6 random shellscripts started failing. Turns out /bin/sh could’t handle large HISTSIZE that I had set for bash, and it just aborts the shell if set too high, instead of making do with less history. The developers were very responsive and it’s been fixed now, but still needs to be improved a bit further, as they pointed out.

  • While the manpages are good, the source code is not very well commented. I agree that good code doesn’t need “what does it do”, but it does need “why”. Specifically what I found missing were:

    • What is an “environment” in ksh? What is its purpose?

    • Why is ksh using its own allocator?

  • I found a bug in the first part of the kernel I looked at. Not a serious one, but still.

  • acme-client (at least in 6.5) doesn’t work with IPv6-only machines. I fixed the first step by replacing a PF_UNSPEC with PF_INET6, but then the next step failed so I switched to certbot.

  • There are some Linux-only things. Pov-Ray 3.7, in addition to since 3.6 switching to the terrible AGPL, switched to build scripts that only work on Linux. This sucks for my distributed render project.

  • Postgresql was a bit awkward to set up, since the unix user is _postgresql, but the postgres user is postgres. Adding export PGUSER=postgres to ~_postgresql/.profile seemed like the best fix. You also have to initdb the database yourself.

  • The equivalent to strace, ktrace/kdump, is a two-step process, and does not produce as good output.

  • No checksumming filesystem in sight.

  • Less binary compatability. Linux is strict on not breaking userspace, but OpenBSD seems less so. Seems the old dnetc binaries don’t work on a modern OpenBSD system, for example.

  • The general OpenBSD attitude. Read the last paragraph of this FAQ and tell me you feel like this is a system and people that care about your use cases. It really says that this is their OS, and if you happen to be able to run it then good for you.


Ouch, that’s a long list of bad stuff. Still, I like it. I’ll continue to run it, and will make sure my stuff continues working on OpenBSD.

And maybe in a year I’ll have a review of OpenBSD on a laptop.


This blog post got posted on reddit, and mentioned on BSDNow episode 324.