LUNAROPS · OPERATIONAL UPLINK 100% UPTIME 1,247d POSTS 893 JEFF.MOON@LUNAROPS.DEV UTC --:--:--

FreeBSD and OpenBSD for the Linux Admin

freebsdopenbsdbsdlinuxvirtualizationinfrastructure

If you have spent your career on Linux, the BSDs feel close enough to be familiar and different enough to be confusing. Same shell, same ls -l, same SSH, the same general Unix muscle memory — and then you go looking for systemctl, apt, /etc/netplan, or a kernel that is one package among thousands, and none of it is there. The reflex is to call this “Linux with the furniture rearranged.” That reflex is wrong, and getting past it is the whole point of this post.

FreeBSD and OpenBSD are not Linux distributions. Linux is a kernel; a distribution is a kernel plus a userland plus a package manager plus a thousand independent upstreams, assembled by Debian or Red Hat or Arch into something that boots. A BSD is a single project that develops the kernel and the core userland together, in one source tree, released as one coherent operating system. That one architectural fact ripples out into everything that surprises a Linux admin — and once it clicks, the rest of the BSD world stops feeling arbitrary and starts feeling, frankly, cleaner.

This post is the orientation for that crossing. What is genuinely different, what FreeBSD gives you (jails, bhyve, ZFS, ports), what OpenBSD gives you (a security model with no real Linux equivalent, and the nicest firewall syntax ever written), and the honest accounting of where a BSD wins and where Linux still wins handily.


The one idea that explains everything: the base system

On a Linux box, draw a line around “the operating system” and you cannot. Is coreutils the OS? glibc? systemd? bash? They are separate projects, separately versioned, glued together by your distro’s package manager, and you update them independently with apt or dnf. There is no canonical “base”; there is a pile of packages, some of which happen to be load-bearing.

A BSD draws that line for you. The base system — kernel, libc, the core utilities, the shell, the C compiler toolchain, the firewall, the init system, the documentation — lives in one version-controlled source tree and ships as one unit. Everything else — nginx, Postgres, Python, your editor — is a package or a port, kept strictly separate under /usr/local. The boundary is real and enforced: base goes in /bin, /sbin, /usr/bin; third-party software goes in /usr/local/bin, /usr/local/etc. You always know which side of the line a thing is on.

   Linux (the distro model)              BSD (the base-system model)
   ─────────────────────────             ────────────────────────────
   kernel        (kernel.org)            ┌──────────────────────────┐
   glibc         (separate upstream)     │  ONE source tree:        │
   coreutils     (separate upstream)     │  kernel + libc + utils   │  -> /bin, /usr/bin
   systemd       (separate upstream)     │  + toolchain + pf + init │
   bash          (separate upstream)     │  + man pages             │
   ...glued by apt/dnf into a distro     └──────────────────────────┘
                                          packages (ports/pkg)         -> /usr/local

The practical consequences are large and mostly pleasant:

  • One coherent upgrade. freebsd-update (binary) or a make buildworld (from source) moves the entire base from 14.3 to 14.4 as a single, tested, internally-consistent step. There is no “I upgraded the kernel but libc is now mismatched” failure mode, because they were built and tested together.
  • Documentation that is actually complete. Because the base is one project, its manual pages and the FreeBSD Handbook / OpenBSD’s man pages are authoritative and cover the whole system. BSD man pages are famously excellent precisely because the OS is bounded enough to document fully. On Linux, man quality varies wildly because there is no single owner.
  • Configuration is centralized and boring. FreeBSD’s /etc/rc.conf is one file of key=VALUE lines that drives the whole system’s services and networking. No systemd unit graph, no /etc/netplan YAML, no NetworkManager. You set ifconfig_em0="inet 192.168.1.10/24" and sshd_enable="YES" in one place and reboot, or use sysrc to edit it safely from a script.

If you internalize only one thing before installing a BSD, make it this: base and packages are different worlds, and the OS is the base. Almost every “wait, where is…?” moment for a Linux admin traces back to looking for a base component in package-land or vice versa.


FreeBSD: the pragmatic, capable BSD

FreeBSD is the BSD you reach for when you want to run things: servers, storage, virtualization hosts, network appliances. It prioritizes performance, broad functionality, and a deep software catalog, and it is the BSD with the features a Linux admin will most immediately recognize and want. The current line is FreeBSD 15.0 (released December 2025), with 14.x still fully supported as the conservative production branch.

Jails — containers, fifteen years early

Here is the fact that reorders a Linux admin’s mental map: FreeBSD had containers in 2000. Jails are OS-level virtualization — many isolated userlands sharing one kernel, each with its own filesystem root, processes, users, and network identity — and they predate Docker by thirteen years and LXC by eight. The Linux machinery you know from the namespaces and cgroups post is the reinvention; jails are the original idea, built as one coherent kernel feature rather than assembled from a dozen independent primitives.

The conceptual difference matters. A Linux container is an emergent property — you compose namespaces (PID, net, mount, user, UTS, IPC), cgroups, seccomp, and capabilities, and the sum behaves like a container. A jail is a first-class kernel object with a single jail(2) call; isolation is the default, not something you assemble. That makes jails simpler to reason about and harder to misconfigure into a leaky half-container.

A minimal jail in modern FreeBSD, defined in /etc/jail.conf:

web {
    host.hostname = "web.example.com";
    path = "/jails/web";
    ip4.addr = "192.168.1.10";
    exec.start = "/bin/sh /etc/rc";
    exec.stop  = "/bin/sh /etc/rc.shutdown";
    mount.devfs;            # give the jail a minimal /dev
    allow.raw_sockets = 0;  # no raw sockets unless you grant them
}
# create the root filesystem (ideally its own ZFS dataset), then:
service jail start web
jls                       # list running jails, like `docker ps`
jexec web /bin/sh         # get a shell inside, like `docker exec`

In practice nobody hand-rolls jail.conf for a fleet. The ecosystem standardized on managers that wrap jails the way Docker wraps Linux namespaces: Bastille (lightweight, template-driven, the modern favorite), iocage (ZFS-native, snapshot-aware), and the older ezjail. Bastille in particular gives you a Dockerfile-ish workflow — templates, bootstrapping, thin clones via ZFS — without dragging in a daemon or a registry. Jails are how a huge amount of FreeBSD’s real-world hosting gets done: one beefy host, dozens of isolated services, near-zero overhead because they share the kernel.

bhyve — the KVM-class hypervisor

When you need full virtual machines rather than shared-kernel jails — a Linux guest, a Windows guest, a different OS entirely — FreeBSD has bhyve, a modern Type-2 hypervisor in the same class as Linux’s KVM. It needs hardware virtualization (Intel VT-x / AMD-V), boots guests through UEFI, and runs Linux, Windows, other BSDs, and illumos as guests. It is lean and fast, with a minimal device model in the spirit of — though older and broader than — the microVM approach Amazon later took with Firecracker.

As with jails, you rarely drive it raw. vm-bhyve gives it a tidy CLI:

# one-time host setup, then:
vm create -t freebsd -s 40G -m 4G myguest
vm install myguest FreeBSD-15.0-RELEASE-amd64-disc1.iso
vm start myguest
vm console myguest        # attach to the guest console
vm list

The honest comparison: bhyve is excellent and genuinely production-grade, but the surrounding ecosystem is thinner than KVM’s. There is no libvirt-scale management universe, no Proxmox-equivalent that everyone uses, fewer pre-built cloud images, and a smaller community to answer the weird questions. If your virtualization needs are mainstream and large, KVM has more road paved. If you want a clean hypervisor on a FreeBSD storage box to run a few VMs alongside your jails, bhyve is a joy.

ZFS, native and first-class

FreeBSD treats ZFS as a first-class root filesystem — you can install onto a ZFS pool from the installer, boot from it, and get snapshots, send/receive replication, compression, and end-to-end checksums as a normal part of the OS rather than a bolted-on module. This is one of FreeBSD’s strongest pitches as a storage platform, and it is the same OpenZFS that the ZFS for the homelab post covers on Linux — except here it has been native and trusted for over a decade, with none of the licensing awkwardness that keeps ZFS at arm’s length on Linux. Pair ZFS datasets with jails (a dataset per jail, thin-cloned from a template) and you have an elegant, snapshot-everything hosting substrate that is hard to replicate as cleanly on Linux.

Ports and packages

FreeBSD software comes two ways from one collection. The ports tree (/usr/ports) is ~30,000 recipes that build software from source with your chosen compile-time options; pkg installs the same software as pre-built binaries. Most people use pkg and dip into ports only when they need a non-default build option:

pkg install nginx postgresql16-server   # binary, fast, the common path
pkg update && pkg upgrade                # update everything from packages

# ports, when you need custom options:
cd /usr/ports/www/nginx && make config && make install clean

Enable and start services through rc.conf, not systemd:

sysrc nginx_enable=YES        # writes nginx_enable="YES" into /etc/rc.conf
service nginx start

OpenBSD: correctness and security as the product

OpenBSD is a different animal with a different obsession. Where FreeBSD optimizes for capability and performance, OpenBSD optimizes for correctness, simplicity, and security, and it is willing to trade raw speed and hardware breadth to get them. Its famous slogan — “Only two remote holes in the default install, in a heck of a long time” — is not marketing; it is the lived result of relentless code auditing and a culture that treats a complicated feature as a liability until proven otherwise. The current release is OpenBSD 7.9 (May 2026), the project’s 60th, shipping on its metronomic six-month cadence.

A Linux admin should care about OpenBSD for three reasons even if they never run it as a daily server: it is upstream for software you already depend on, it pioneered security mitigations that later spread everywhere, and it has the best firewall configuration language in existence.

You already run OpenBSD’s code

OpenSSH — the SSH you use on every Linux box on Earth — is developed by the OpenBSD project. So is LibreSSL, the audited fork of OpenSSL spun up after Heartbleed. So is tmux. OpenBSD’s influence on the Unix world is wildly out of proportion to its install base, because its people write the security-critical plumbing everyone else ships.

A security model with no Linux equivalent

OpenBSD’s headline security features are two system calls that have no direct, in-base Linux counterpart:

  • pledge(2) lets a program voluntarily renounce capabilities at runtime. A program declares “from this point on, I only need stdio, rpath, and inet” — and the kernel kills it if it then tries to, say, exec another binary or open a writable file. It is privilege reduction the application opts into, in a single readable line, and OpenBSD’s own base utilities are pledged throughout.
  • unveil(2) restricts which parts of the filesystem a process can even see. A program unveils only the few paths it legitimately needs — unveil("/etc/myapp", "r"), unveil("/var/log/myapp", "rw") — and the rest of the filesystem ceases to exist for it, regardless of Unix permissions.

The closest Linux analogs are seccomp-bpf, Landlock, SELinux, or AppArmor — all real, all powerful, and all dramatically more complex to author than pledge/unveil’s one-line declarations. Linux pushes this isolation into separate subsystems and policy languages; OpenBSD bakes coarse, ergonomic versions into the base and uses them on its own programs by default. On top of those, OpenBSD enforces W^X (no memory page is both writable and executable), aggressive ASLR, and a long list of other mitigations as non-negotiable defaults. The philosophy is the inverse of Linux’s “ship it flexible, let the admin lock it down”: OpenBSD ships it locked down and makes you justify loosening it.

For Linux-side context on where this isolation lives in your world, see the sandboxed-runtime and container-security posts — OpenBSD reaches a related goal by a much simpler road.

vmm/vmd — virtualization, deliberately minimal

OpenBSD has a hypervisor too, vmm/vmd, but it is intentionally spartan: it runs OpenBSD and Linux guests, with no Windows support, no PCI passthrough, and a deliberately small feature set. That is not an oversight — it is the OpenBSD philosophy applied to virtualization. If you need a serious VM host, use bhyve or KVM; vmm exists to run a few trusted guests with minimal attack surface.


pf: the cleanest firewall syntax ever written

If there is one piece of BSD that should make a Linux admin envious, it is pf (Packet Filter). Born in OpenBSD in 2001 and later adopted by FreeBSD, pf is a stateful firewall whose configuration file reads like a description of your intent rather than a sequence of opcodes. Set the canonical pf.conf beside an equivalent nftables or — heaven forbid — raw iptables ruleset and the difference in legibility is not subtle.

A complete, production-shaped OpenBSD pf.conf:

# macros — name your interfaces and hosts once
ext_if = "em0"

# tables — efficient lists you can modify at runtime
table <bruteforce> persist

# options
set skip on lo                 # never filter loopback

# normalization — reassemble fragments, sanitize packets
match in all scrub (no-df)

# default deny, then explicitly allow
block return                   # block and notify, rather than silently drop
pass out                       # allow all outbound, keep state automatically

# brute-force protection: jail abusers in the <bruteforce> table
block quick from <bruteforce>
pass in on $ext_if proto tcp to port ssh \
    keep state (max-src-conn 5, max-src-conn-rate 5/30, \
        overload <bruteforce> flush global)

pass in on $ext_if proto tcp to port { www https }

Read that top to bottom and you understand the firewall. Several design choices earn pf its reputation:

  • Last-matching-rule-wins, with quick to short-circuit — the opposite of iptables’ first-match, and far easier to reason about for a layered policy.
  • Stateful by default. pass keeps state automatically; return traffic for an allowed connection is allowed without a second rule. No more “allow ESTABLISHED,RELATED” boilerplate on every chain.
  • Tables are first-class, kernel-resident sets you mutate live (pfctl -t bruteforce -T add 10.0.0.5) without reloading rules — the basis of the elegant overload brute-force trick above, which auto-bans any IP that opens too many SSH connections too fast.
  • Macros and anchors let you name things and compose rulesets cleanly.

This is the same job as the nftables toolkit on Linux — and nftables is a genuine improvement over iptables — but pf still reads more like prose. It is the single biggest reason BSDs remain beloved for firewalls and routers, and it is why pfSense and OPNsense, the two dominant open-source firewall appliances, are both built on FreeBSD.


Where a BSD genuinely beats Linux

Be specific, because “BSD is better” with no scope is just tribalism. The concrete cases where reaching for a BSD is the right engineering call:

Use case Why the BSD wins
Firewalls and routers pf’s clarity, FreeBSD’s mature network stack, and pfSense/OPNsense make this the BSDs’ strongest home-field.
Storage appliances / NAS Native, long-trusted ZFS plus jails for services is a cleaner storage substrate than Linux’s bolted-on ZFS. TrueNAS’s core lineage is FreeBSD for exactly this reason.
Dense, low-overhead multi-tenancy Jails give you many isolated services on one host with less ceremony and less daemon than the Docker/Kubernetes stack, when you do not need that stack’s scale.
Security-sensitive, minimal-surface boxes OpenBSD for bastion hosts, VPN endpoints, DNS, and small public-facing services where attack surface matters more than features.
Long-lived, low-churn infrastructure The coherent base system and excellent docs make BSDs forgiving to operate and upgrade over many years with few surprises.

The honest other side: where Linux wins

A post that only sold the BSDs would be lying by omission. The reasons the overwhelming majority of servers run Linux are real and mostly decisive:

  • Hardware support. Linux’s driver coverage dwarfs the BSDs’, especially for new NICs, GPUs, Wi-Fi, and exotic server hardware. The newer or weirder your hardware, the likelier FreeBSD limps and OpenBSD simply does not see the device. This single factor disqualifies the BSDs from a lot of deployments before any other consideration.
  • The software and container ecosystem. Docker, Kubernetes, and essentially the entire cloud-native universe are Linux-kernel-native (they are namespaces and cgroups). You can run Linux containers on FreeBSD only through compatibility layers and caveats. If your world is containers and orchestration, you are on Linux, full stop.
  • Commercial software and vendor support. Databases, monitoring agents, proprietary drivers, and enterprise tools target Linux first and often only. “Is it supported on FreeBSD?” frequently has an awkward answer.
  • Performance at the bleeding edge and mindshare. For many high-end workloads Linux has more tuning attention and newer hardware enablement. And the talent pool, the Stack Overflow answers, and the muscle memory are all Linux — hiring and on-call are simply easier.
  • OpenBSD’s deliberate trade-offs. OpenBSD’s security focus costs raw performance and hardware breadth on purpose. It is a scalpel, not a workhorse; using it as a general-purpose heavy-lifting server is using it against its grain.

The blunt summary: choose a BSD for the specific jobs above where its strengths are decisive, and reach for Linux for the general case and anything container-centric. This is not a war you have to pick a permanent side in — plenty of good shops run OpenBSD firewalls in front of Linux fleets, or a FreeBSD ZFS box serving Linux hypervisors, and let each OS do what it is best at.


Getting started without committing your career

You do not have to reinstall your laptop to learn this. The low-risk on-ramps:

  • Run one in a VM. Spin up FreeBSD or OpenBSD under KVM/bhyve/VirtualBox, install it, and do the install by hand once — partition to ZFS on FreeBSD, read the prompts on OpenBSD. The installers are short and educational.
  • Replace one appliance. The highest-value first step for most admins is putting OPNsense or pfSense (FreeBSD) on your home or lab router, or standing up an OpenBSD box as a VPN/DNS endpoint. You learn pf in anger and get a genuinely better appliance.
  • Read the docs, because they are real. The FreeBSD Handbook and OpenBSD’s man pages and FAQ are complete and accurate in a way Linux documentation rarely is. On a BSD, “read the man page” is actually sufficient advice.
  • Use a jail or two. On a FreeBSD box, install Bastille and stand up a couple of jails. It is the fastest way to feel why people who run jails are reluctant to go back to Docker for simple hosting.

The verdict

The BSDs are not a retro curiosity and they are not a Linux replacement. They are a different, internally-coherent answer to “what is an operating system” — one tree, one base, ruthlessly documented — that happens to be the best available tool for a handful of specific jobs: firewalls and routers (pf and pfSense/OPNsense), storage appliances (native ZFS plus jails), low-ceremony multi-tenancy (jails), and minimal-surface security boxes (OpenBSD). For those, a BSD is not a compromise; it is the right call.

For everything else — and “everything else” is most of the server world, all of the container world, and anything on bleeding-edge hardware — Linux’s ecosystem, hardware support, and mindshare win, and that is fine. The mature position is not loyalty to one kernel; it is knowing both well enough to put an OpenBSD firewall in front of a Kubernetes cluster and a FreeBSD ZFS box underneath it, and to feel no contradiction in doing so. Learn the BSDs not to leave Linux, but to stop reaching for Linux when something else is plainly the better instrument.


Sources

Comments