OPNsenseIV · OPNsense ArchitectureOPNsense architecture
FreeBSD as the base — services, rc.d, and what the operator notices
What you'll learn
- Identify what OPNsense inherits from FreeBSD and what it adds on top
- Read the FreeBSD rc.d service framework as it appears on an OPNsense system
- Explain the kernel-level differences from Linux that an operator encounters
- List the FreeBSD diagnostic commands the operator will use most often
Prerequisites
Verified against OPNsense 25.x · FreeBSD 14.x · PF (FreeBSD packet filter) FreeBSD 14.x · Unbound 1.20+ · Kea DHCP OPNsense 25.x plugin · WireGuard in-kernel + OPNsense plugin · strongSwan (IPsec plugin) OPNsense 25.x plugin · OpenVPN 2.6.x · Suricata 7.x · 2026-08-14
OPNsense is a FreeBSD system with a PHP web front-end, a curated package set, and a generated PF ruleset on top. There is no hidden layer between the operator and the FreeBSD base — when the operator opens a shell on an OPNsense appliance, the commands are FreeBSD commands and the behaviour is FreeBSD behaviour. Operators with a Linux-only background find this disorienting for the first day; operators with a FreeBSD background find it liberating.
This lesson covers what OPNsense inherits from FreeBSD (almost
everything), how FreeBSD services actually start (rc.d and the
booting process), and the differences from Linux that the
operator notices in daily work.
What OPNsense is, structurally
A running OPNsense appliance has four layers, each with a clear responsibility:
- HardenedBSD 14.x kernel and base system. The kernel boots, detects hardware, mounts filesystems, brings up interfaces, and provides the socket stack, the routing table, PF, and the network drivers.
- FreeBSD userland. The standard FreeBSD utilities —
ifconfig,netstat,route,pfctl,sockstat,pkg,sysctl,vmstat,dmesg,tcpdump,ngctl— all present, all behaving as they do on FreeBSD. - OPNsense core. A collection of PHP scripts that read the
config XML and translate it into FreeBSD-native configuration
(PF ruleset,
rc.confparameters, Unbound config, ISC DHCP config, IPsec strongSwan config, CARP VIPs). The PHP code lives under/usr/local/sbin/and the web framework is/usr/local/opnsense/. - OPNsense plugins. Optional packages (WireGuard, IPsec,
Suricata, FRR, OpenVPN) that follow the same pattern: PHP
code in
/usr/local/opnsense/, config in the same XML, generated service config under/var/.../.
The operator’s shell access is at layer 1–2; the web GUI and API are at layer 3. The boundary between them is the config XML — every GUI change becomes an XML edit, every XML edit (through the supported path) is applied by the PHP layer and propagated to FreeBSD services.
$ ls /usr/local/opnsense/COPYING.md
README.md
Scripts
Service
UPLOAD.htm
Versions
bin
conf
contrib
mvc
service
services
srcIllustrative output
The FreeBSD booting model and rc.d
FreeBSD does not use systemd. It uses the older rc.d framework,
which is a collection of shell scripts under /etc/rc.d/ and
/usr/local/etc/rc.d/. Each script declares its dependencies
(require, provide, before, after), what it provides
(REQUIRES, PROVIDES), and how to start, stop, reload, and
status-check its service.
The boot sequence reads /etc/rc.conf for variables that control
which services are enabled (nginx_enable="YES", sshd_enable="YES",
and so on), then walks the dependency graph from the enabled
services and starts each one in order.
OPNsense manages rc.conf for the operator. The PHP scripts write
the right variables when a service is enabled in the GUI, and the
operator sees the result at the shell:
$ service nginx statusnginx is running as pid 1138.
nginx: ready (no errors)Illustrative output
rc.d, sysrc, and the boot-time variables
rc.conf is the file that controls which services start at boot.
The variables follow a strict convention: <service>_enable="YES"
or "NO". The sysrc command is the safe way to edit
rc.conf from the shell — it parses the file, preserves comments,
and either replaces an existing variable or appends a new one.
$ sysrc -n nginx_enableYESIllustrative output
The dependency graph that rc.d walks at boot matters for
production. The boot order on a typical OPNsense box is:
kernel → zfs/ufs → mountcrit → var → dev → fsclean →
→ network → routing → pfsync → pf → opnsense-bootstrap →
→ syslog-ng → unbound → nginx → ...
If pf fails to start (bad ruleset, missing table file), the boot
process continues past pf and OPNsense’s services come up
without firewalling — the appliance is up but not protected.
Always check service pf status after any reboot or any ruleset
edit. The lesson on lockout prevention covers this in the context
of remote management.
The FreeBSD vs Linux differences the operator notices
A list of differences that show up in operational work. None of these are better or worse than Linux; they are what the operator encounters.
| Concept | FreeBSD | Linux |
|---|---|---|
| Service framework | rc.d shell scripts | systemd units |
| Default firewall | PF (also ipfw, npf) | nftables (or legacy iptables) |
| Network config | ifconfig, route (newer commands alongside) | iproute2 (ip, ss, tc) |
| Package manager | pkg (binary) | apt, dnf, pacman (distribution-specific) |
| Filesystem | UFS or ZFS (OPNsense uses ZFS) | ext4, xfs, btrfs (distribution-specific) |
| Process info | ps, top, procstat | ps, top, /proc/<pid>/... |
| Memory info | vmstat, sysctl hw.physmem, systat -vm | free, /proc/meminfo |
| Socket info | sockstat, netstat | ss, netstat |
| Kernel modules | kldstat, kldload, /boot/loader.conf | lsmod, modprobe, /etc/modules-load.d/ |
| Live patching | limited | livepatch (depending on distro) |
| Container model | jails | cgroups/namespaces |
The diagnostic toolkit the operator uses
A short list of FreeBSD commands that appear repeatedly in production. The course uses each of these elsewhere; the lesson records what each one is for.
| Command | Purpose |
|---|---|
pfctl -s state | PF state table (active flows) |
pfctl -s rules | PF ruleset loaded into the kernel |
pfctl -s tables | PF tables (alias contents) |
pfctl -s Anchors | PF anchors (loaded sub-rulesets) |
netstat -rn | Routing table (FIB) |
netstat -an | Listening sockets |
sockstat -c | Active connections per process |
ifconfig <iface> | Interface status, addresses, counters |
sysctl net.inet.ip.forwarding | IP forwarding toggle |
sysctl -a | grep net.inet | All network tunables |
vmstat 1 | Memory, CPU, paging every second |
systat -vmstat 1 | FreeBSD’s classic top-like view |
dmesg | Kernel ring buffer (last boot) |
procstat -v <pid> | Process memory map and open files |
service <name> status | Service state |
tail -F /var/log/system/latest.log | Follow the system log |
tcpdump -ni <iface> | Packet capture |
pkg info | List installed packages |
pkg audit -F | List known vulnerabilities in installed packages |
The operator does not need to memorise the entire list. The course brings each command up when it is the right diagnostic tool for the problem at hand.
Summary
- OPNsense is FreeBSD (HardenedBSD) + PHP framework + plugins. The operator’s shell is a FreeBSD shell.
- FreeBSD uses
rc.d, not systemd. Services are started by shell scripts that declare dependencies.rc.confcontrols what is enabled. - The OPNsense bootstrap step runs late in the boot and is the
step that applies the GUI config to FreeBSD services. If the
web GUI does not come up, check
opnsense-bootstrapin the system log. - The FreeBSD vs Linux differences that matter operationally are: service framework, default firewall, network config toolset, package manager, filesystem, and process/socket inspection commands.
- The diagnostic toolkit is the FreeBSD toolkit. The course brings each command up in context.
Knowledge check · 3 questions
Q1. You need to enable an OPNsense-supported daemon and have full shell access. What is the supported way to enable it so the change survives a reboot and a future GUI apply?
Q2. OPNsense uses systemd as its service framework, like most modern Linux distributions.
Q3. Which of the following statements correctly describe FreeBSD vs Linux differences that an OPNsense operator encounters daily? Select all that apply.
Passing score: 75%. Answers are checked in this browser.