๐Ÿ˜ˆ FreeBSD vs Linux: What Is Actually Different

You already know Linux. Here is the short, tested tour of what changes when the machine in front of you runs FreeBSD

Video: FreeBSD vs Linux (FreeBSD video)
Prefer to watch? This short video runs this page's main commands on a real FreeBSD 15.0 machine, with on-screen captions and no voiceover. Click to play, or watch it on YouTube.

Same family, different branch

Both Linux and FreeBSD behave like Unix: files and folders, users and permissions, processes, pipes, grep, ssh and shell scripts all work in the way you already know. The difference is in the family tree. BSD grew out of the Unix work done at the University of California, Berkeley, and FreeBSD is one of its living descendants. Linux was written from scratch, years later, to behave like Unix.

You will find FreeBSD in places where people care about networking, storage and long, quiet uptimes: firewalls and routers (pfSense and OPNsense are built on it), storage appliances, content delivery networks and plenty of ordinary servers. It is often the system at the other end of a "can you upgrade that box?" request, which is how this corner of the site came about.

Everything below was run on a real FreeBSD 15.0-RELEASE installed in a virtual machine with the default ZFS layout. Numbers and names on your machine will differ.

One system, not a kit

Linux is a kernel. A distribution (Ubuntu, Rocky, Debian) collects a kernel from one project, a C library from another, the ls and grep tools from a third, and so on. FreeBSD is developed as one whole operating system: the kernel and the basic tools ("the base system") live in the same source tree and are released together under one version number.

bsd@practice:~ $ uname -a
FreeBSD practice 15.0-RELEASE FreeBSD 15.0-RELEASE releng/15.0-n280995-7aedc8de6446 GENERIC amd64
bsd@practice:~ $ freebsd-version -kru
15.0-RELEASE
15.0-RELEASE
15.0-RELEASE
bsd@practice:~ $ head -3 /etc/os-release
NAME=FreeBSD
VERSION="15.0-RELEASE"
VERSION_ID="15.0"
bsd@practice:~ $ echo $SHELL
/bin/sh
bsd@practice:~ $ ls /
COPYRIGHT	etc		mnt		sbin		zroot
bin		home		net		sys
boot		lib		proc		tmp
dev		libexec		rescue		usr
entropy		media		root		var

Base system and packages are kept apart

On Linux, /usr/bin holds almost everything, whoever supplied it. On FreeBSD the base system lives in /bin, /sbin, /usr/bin and /usr/sbin, and everything you add yourself goes under /usr/local, so you can always tell what shipped with the OS and what you installed.

โš ๏ธ Newer package repository (checked October 2026): the package repository now targets FreeBSD 15.1, while 15.0-RELEASE is end of life. On a 15.0 machine pkg may stop with Newer FreeBSD version for package ... [y/N], and the version numbers in the output below may differ from yours. To carry on, run export IGNORE_OSVERSION=yes first, or better, move to a supported release (see the upgrading guide).

bsd@practice:~ $ which ls ps sh vi
/bin/ls
/bin/ps
/bin/sh
/usr/bin/vi
bsd@practice:~ $ ls /usr/local
bsd@practice:~ $ pkg -v
The package management tool is not yet installed on your system.
Do you want to fetch and install it now? [y/N]: n
bsd@practice:~ $ which sudo bash nano curl

Services: /etc/rc.conf, not systemd

FreeBSD has no systemd. Services are started by a set of plain shell scripts in /etc/rc.d (the base system) and /usr/local/etc/rc.d (packages), and what runs at boot is set in one text file, /etc/rc.conf.

bsd@practice:~ $ cat /etc/rc.conf
zfs_enable="YES"
hostname="practice"
ifconfig_vtnet0="DHCP"
sshd_enable="YES"
bsd@practice:~ $ sysrc hostname
hostname: practice
bsd@practice:~ $ sysrc sshd_enable
sshd_enable: YES
bsd@practice:~ $ service -e
/etc/rc.d/hostid
/etc/rc.d/hostid_save
/etc/rc.d/zpool
/etc/rc.d/kldxref
/etc/rc.d/zfsbe
/etc/rc.d/var_run
[... 25 more lines left out ...]
bsd@practice:~ $ service sshd status
sshd is running as pid 1243.
bsd@practice:~ $ ls /etc/rc.d | head -8
DAEMON
FILESYSTEMS
LOGIN
NETWORKING
SERVERS
accounting
adjkerntz
apm

Users, groups and the missing sudo

bsd@practice:~ $ id
uid=1001(bsd) gid=1001(bsd) groups=0(wheel),1001(bsd)
bsd@practice:~ $ su -
Password:
root@practice:~ # whoami
root
root@practice:~ # pw groupshow wheel
wheel:*:0:root,bsd
root@practice:~ # sudo ls
-su: sudo: not found
root@practice:~ # exit

ZFS and boot environments: the undo button

FreeBSD's installer offers ZFS, a filesystem and volume manager in one. It is a first-class citizen here, and the default layout is built to make upgrades safe. (The ZFS in practice page goes much deeper.)

bsd@practice:~ $ zpool list
NAME    SIZE  ALLOC   FREE  CKPOINT  EXPANDSZ   FRAG    CAP  DEDUP    HEALTH  ALTROOT
zroot  13.5G   460M  13.1G        -         -     0%     3%  1.00x    ONLINE  -
bsd@practice:~ $ zfs list
NAME                 USED  AVAIL  REFER  MOUNTPOINT
zroot                460M  12.6G    96K  /zroot
zroot/ROOT           458M  12.6G    96K  none
zroot/ROOT/default   458M  12.6G   458M  /
zroot/home           136K  12.6G   136K  /home
zroot/tmp            104K  12.6G   104K  /tmp
zroot/usr            288K  12.6G    96K  /usr
zroot/usr/ports       96K  12.6G    96K  /usr/ports
zroot/usr/src         96K  12.6G    96K  /usr/src
zroot/var            608K  12.6G    96K  /var
zroot/var/audit       96K  12.6G    96K  /var/audit
zroot/var/crash       96K  12.6G    96K  /var/crash
zroot/var/log        128K  12.6G   128K  /var/log
zroot/var/mail        96K  12.6G    96K  /var/mail
zroot/var/tmp         96K  12.6G    96K  /var/tmp
bsd@practice:~ $ bectl list
BE      Active Mountpoint Space Created
default NR     /          458M  2026-10-05 20:58

A boot environment is a snapshot of the whole operating system that you can boot into. Here is the idea in use:

bsd@practice:~ $ su -
Password:
root@practice:~ # bectl create before-experiment
root@practice:~ # bectl list
BE                Active Mountpoint Space Created
before-experiment -      -          8K    2026-10-05 21:02
default           NR     /          458M  2026-10-05 20:58
root@practice:~ # bectl destroy -F before-experiment
root@practice:~ # bectl list
BE      Active Mountpoint Space Created
default NR     /          458M  2026-10-05 20:58
root@practice:~ # exit

bectl create before-experiment made a copy, and the space used is 8K, because ZFS only stores differences. It shows up in the list. We then removed it. Before an upgrade you create a BE, and if the upgrade goes badly, you boot the old one. That is the undo button Linux administrators dream about, and the reason the upgrade page in this corner starts here.

Network and system tools

bsd@practice:~ $ ifconfig vtnet0
vtnet0: flags=1008843<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST,LOWER_UP> metric 0 mtu 1500
	options=880028<VLAN_MTU,JUMBO_MTU,LINKSTATE,HWSTATS>
	ether 52:54:00:12:34:56
	inet 10.0.2.15 netmask 0xffffff00 broadcast 10.0.2.255
	media: Ethernet autoselect (10Gbase-T <full-duplex>)
	status: active
	nd6 options=29<PERFORMNUD,IFDISABLED,AUTO_LINKLOCAL>
bsd@practice:~ $ netstat -rn | head -6
Routing tables

Internet:
Destination        Gateway            Flags         Netif Expire
default            10.0.2.2           UGS          vtnet0
10.0.2.0/24        link#1             U            vtnet0
bsd@practice:~ $ sockstat -4l
USER COMMAND     PID FD PROTO LOCAL ADDRESS         FOREIGN ADDRESS
root sshd       1243  7 tcp4  *:22                  *:*
root syslogd    1057  7 udp4  *:514                 *:*
bsd@practice:~ $ ping -c 2 10.0.2.2
PING 10.0.2.2 (10.0.2.2): 56 data bytes
64 bytes from 10.0.2.2: icmp_seq=0 ttl=255 time=0.411 ms
64 bytes from 10.0.2.2: icmp_seq=1 ttl=255 time=0.242 ms

--- 10.0.2.2 ping statistics ---
2 packets transmitted, 2 packets received, 0.0% packet loss
round-trip min/avg/max/stddev = 0.242/0.327/0.411/0.085 ms
bsd@practice:~ $ sysctl hw.ncpu hw.physmem kern.ostype kern.osrelease
hw.ncpu: 2
hw.physmem: 2102890496
kern.ostype: FreeBSD
kern.osrelease: 15.0-RELEASE
bsd@practice:~ $ uptime
 9:02PM  up 3 mins, 1 user, load averages: 0.11, 0.04, 0.01
bsd@practice:~ $ kldstat | head -5
Id Refs Address                Size Name
 1   15 0xffffffff80200000  1f4daa0 kernel
 2    1 0xffffffff8214f000   620c10 zfs.ko
 3    1 0xffffffff83018000     4250 ichsmb.ko
 4    1 0xffffffff8301d000     2178 smbus.ko
bsd@practice:~ $ ls /proc

Logs are plain text again: /var/log/messages is the main system log, written by syslogd and rotated by newsyslog. There is no journalctl: use tail, less and grep (lesson 4 of Linux 101).

Linux commands that are not there

If you type your usual Linux commands, most of the time you get a polite refusal:

bsd@practice:~ $ ip addr
-sh: ip: not found
bsd@practice:~ $ free -h
-sh: free: not found
bsd@practice:~ $ ss -tln
-sh: ss: not found
bsd@practice:~ $ systemctl status sshd
-sh: systemctl: not found
bsd@practice:~ $ apt install nano
-sh: apt: not found
bsd@practice:~ $ journalctl -u sshd
-sh: journalctl: not found
bsd@practice:~ $ which service sysrc ifconfig sockstat pkg
/usr/sbin/service
/usr/sbin/sysrc
/sbin/ifconfig
/usr/bin/sockstat
/usr/sbin/pkg

The last line shows the FreeBSD tools that answer the same questions. Here is the map:

Little gotchas for Linux hands

The tools in FreeBSD's base system come from BSD, not the GNU project, so a few familiar options differ:

bsd@practice:~ $ echo hello > t.txt
bsd@practice:~ $ sed -i 's/hello/bye/' t.txt
sed: 2: "t.txt
": undefined label '.txt'
bsd@practice:~ $ sed -i '' 's/hello/bye/' t.txt
bsd@practice:~ $ cat t.txt
bye
bsd@practice:~ $ date -d yesterday
date: illegal option -- d
usage: date [-jnRu] [-I[date|hours|minutes|seconds|ns]] [-f input_fmt]
            [ -z output_zone ] [-r filename|seconds] [-v[+|-]val[y|m|w|d|H|M|S]]
            [[[[[[cc]yy]mm]dd]HH]MM[.SS] | new_date] [+output_fmt]
How many FreeBSD admins does it take to change a light bulb?<br>
None. It is already in the base system.

๐Ÿ’ก Safe to experiment: a virtual machine is the right place to learn this. You can install FreeBSD in VirtualBox, VMware, QEMU or Proxmox in about ten minutes. Choose the ZFS option in the installer and you get boot environments for free.

๐Ÿงช Try it yourself

On a FreeBSD machine or VM:

1. Show the kernel and userland versions. Are they equal? 2. Which file decides which services start at boot? Print it. 3. Is sshd running? Use service. 4. Which user and program is listening on each TCP port? (sockstat) 5. List the ZFS datasets and the boot environments. 6. Create a boot environment called practice-1, list it, then destroy it. 7. Print the routing table and find your default gateway.

The cheat sheet

↑ FreeBSD Corner · Upgrading FreeBSD Safely: freebsd-update, pkg and Boot Environments →