17 minutes
OpenBSD: High-Availability Firewalling
While most posts on this site usually concern Linux, I have a bit of a soft spot for OpenBSD.
OpenBSD is an operating system from the Unix lineage, started in Bell Labs many years ago, eventually giving rise to the Berkeley Software Distribution (BSD). The most known versions of BSD are NetBSD (who focus on portability, running on pretty much any hardware), FreeBSD (who focus on covering as many purposes as possible) and OpenBSD (who focus on security, sometimes at the expense of performance).
OpenBSD has (in my opinion) amazing documentation, and with a combination of their man
pages and example configuration (e.g. /etc/examples
is full of configuration examples), you can get most of the included daemons working.
OpenBSD also provides quite a comprehensive suite of software already bundled in, everything from routing daemons, web servers, firewalling, mail servers and much more.
In this post, I’m going to cover how you can setup a pair of OpenBSD machines to run as a highly-available firewall pair.
Diagram
In the diagram, we have a client machine (running on Debian 10), a server (net-01) and two OpenBSD virtual machines.
Installing OpenBSD
To set up OpenBSD, you will be presented with a text-based installer with a number of options to choose from. I won’t go into details here, as the OpenBSD FAQ can cover every aspect of it. Summing up my chosen options though: -
- Three main networks
- hvn2 - The link between the firewalls (running in the
169.254.0.0/31
range) - hvn3 - The link to the server (running in the
192.0.2.0/24
range) - hvn4 - The link to the client (running in the
192.168.99.0/24
range)
- hvn2 - The link between the firewalls (running in the
- Only installing a minimal file set, with no X11 dependencies, or the text-based games file sets
- Automatic partitioning
Setting up the the firewalls
To get the firewalls running, we need to setup the following daemons: -
pf(4)
- PF, or Packet Filter, the OpenBSD packet filtering daemoncarp(4)
- CARP, or Common Address Redundancy Protocol, for highly available IPs (like VRRP or Cisco’s HSRP)
We also need to do the following: -
- Add the correct IPs to each interface
- Allow IP forwarding through the firewalls
- Enable the
pfsync(4)
device, to sync state between the firewalls - Create the
carp(4)
interfaces - Define the
pf(4)
ruleset
Setting up the IP interfaces
To define an interface in OpenBSD, you create a file called hostname.$INTERFACE-NAME
, replacing $INTERFACE-NAME with your interfaces (e.g. hvn2, vio1), in the /etc
directory.
To demonstrate this, see below: -
## hostname.hvn2
inet 169.254.0.1 255.255.255.254
## hostname.hvn3
inet 192.0.2.10 255.255.255.0
## hostname.hvn4
inet 192.168.99.1 255.255.255.0
You can also supply the network mask in hexadecimal format (e.g. a /24
would be 0xffffff00
). To enable the interfaces, you can use doas sh /etc/netstart hvn2
.
You should now be able to see the interfaces: -
$ ifconfig hvn2
hvn2: flags=8a43<UP,BROADCAST,RUNNING,ALLMULTI,SIMPLEX,MULTICAST> mtu 1500
lladdr 00:15:5d:f4:91:ef
index 3 priority 0 llprio 3
media: Ethernet manual
status: active
inet 169.254.0.1 netmask 0xfffffffe
$ ifconfig hvn3
hvn3: flags=8b43<UP,BROADCAST,RUNNING,PROMISC,ALLMULTI,SIMPLEX,MULTICAST> mtu 1500
lladdr 00:15:5d:f4:91:f3
index 4 priority 0 llprio 3
media: Ethernet manual
status: active
inet 192.0.2.10 netmask 0xffffff00 broadcast 192.0.2.255
$ ifconfig hvn4
hvn4: flags=8b43<UP,BROADCAST,RUNNING,PROMISC,ALLMULTI,SIMPLEX,MULTICAST> mtu 1500
lladdr 00:15:5d:f4:91:f4
index 5 priority 0 llprio 3
media: Ethernet manual
status: active
inet 192.168.99.1 netmask 0xffffff00 broadcast 192.168.99.255
You’ll need to ensure that each firewall has a different IP on it’s interfaces (i.e. using 192.168.99.2/24
on hvn4 on the second firewall) so that they do not conflict.
Wait, what is doas
?
doas(1)
is a privilege escalation utility, used to temporarily elevate a user’s privileges, to allow them to perform commands that they typically cannot as a normal user. For those familiar with sudo
, it is very similar. The reason for its existence is a smaller codebase than sudo
to maintain, and also the configuration syntax is quite simple.
This is a good example of OpenBSD choosing tools that they can maintain and audit easily, rather than using external tools (or maintaining their own fork). For other examples, see the choice of their own httpd(8)
over NGINX, or bgpd(4)
over Quagga/BIRD.
To get a simple version of doas(1)
running, you can look at the /etc/examples
directory for a sample doas.conf
file. Copy this to /etc/doas.conf
, and edit it to your tastes.
## $OpenBSD: doas.conf,v 1.1 2016/09/03 11:58:32 pirofti Exp $
## Configuration sample file for doas(1).
## See doas.conf(5) for syntax and examples.
## Non-exhaustive list of variables needed to build release(8) and ports(7)
##permit nopass setenv { \
## FTPMODE PKG_CACHE PKG_PATH SM_PATH SSH_AUTH_SOCK \
## DESTDIR DISTDIR FETCH_CMD FLAVOR GROUP MAKE MAKECONF \
## MULTI_PACKAGES NOMAN OKAY_FILES OWNER PKG_DBDIR \
## PKG_DESTDIR PKG_TMPDIR PORTSDIR RELEASEDIR SHARED_ONLY \
## SUBPACKAGE WRKOBJDIR SUDO_PORT_V1 } :wsrc
## Allow wheel by default
permit keepenv :wheel
The above does nothing more than allow the wheel group to use doas(1)
. I add my user into the wheel group, and from then on I can use doas(1)
to my hearts content.
Setting up pfsync(4)
For truly highly available firewalls, you need something that will synchronize the state between them. This is because if you just failover to another machine, the second machine would have no idea of what existing TCP connections are active, what UDP connections have been seen recently (e.g. VoIP calls) and how many hits each rule has seen (important for monitoring).
OpenBSD provides the pfsync(4)
utility, which does exactly that. To quote the man
page for pfsync(4)
If configured with a physical synchronisation interface, pfsync will also send state changes out on that interface, and insert state changes received on that interface from other systems into the state table.
So if you have this running on an interface dedicated between two machines, they will share state information.
To make this work, you configure another hostname.$INTERFACE-NAME
file, except this time it will be hostname.pfsync
. The contents of the file will look something like the below: -
$ cat /etc/hostname.pfsync0
up syncdev hvn2
This is the same on both firewalls. If you run tcpdump(8)
on hvn2 while the firewall is in operation, you will see numerous state messages passing between the two firewalls (try running tcpdump -i hvn2
during operation to see).
Allow IP Forwarding
IP Forwarding is configured within the /etc/sysctl.conf
file as such: -
$ cat /etc/sysctl.conf
net.inet.ip.forwarding=1
Without this, traffic will not work through the firewalls, so make sure you enable this!
Add carp(4)
for redundancy
Unless you use devices that support routing protocols, or can failover between multiple default gateways, you’ll need to target an IP that can reside on both firewalls. In the Cisco world, they use HSRP (Hot Standby Router Protocol). The RFC version of HSRP is known as VRRP (Virtual Router Redundancy Protocol). However, despite VRRP being an RFC standard, it is patent-encumbered, meaning some elements of it are covered by patents (owned by Cisco).
Due to this, the OpenBSD developers implemented CARP instead. CARP does not infringe on any Cisco patents, although it does still use a few traits of VRRP (e.g. the IP Protocol number and Virtual MAC Addresses). This does mean that if you have VRRP and CARP on the same network, you will need to use different VRRP Group IDs and CARP Virtual Host IDs for them to coexist.
Again, to setup a carp(4)
interface on the primary firewall, you use the hostname.$INTERFACE-NAME
files. To demonstrate, see below: -
## hostname.carp1
inet 192.0.2.1 255.255.255.0 192.0.2.255 vhid 1 carpdev hvn3 pass hvn3pass
## hostname carp2
inet 192.168.99.254 255.255.255.0 192.168.99.255 vhid 1 carpdev hvn4 pass hvn4pass
The syntax is as follows: -
inet $VIRTUAL-IP $SUBNET-MASK $BROADCAST-ADDRESS vhid $CARP-VIRTUAL-HOST-ID carpdev $PHYSICAL-INTERFACE pass $PASSWORD
You need to ensure the Virtual IP is in the same network as the interface it is running on. The Physical Interface parameter is used to tie the CARP virtual interface to a physical interface.
Again, use doas /etc/netstart carpN
to start the interfaces: -
$ ifconfig carp1
carp1: flags=8843<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST> mtu 1500
lladdr 00:00:5e:00:01:01
index 8 priority 15 llprio 3
carp: MASTER carpdev hvn3 vhid 1 advbase 1 advskew 0
groups: carp
status: master
inet 192.0.2.1 netmask 0xffffff00 broadcast 192.0.2.255
$ ifconfig carp2
carp2: flags=8843<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST> mtu 1500
lladdr 00:00:5e:00:01:01
index 9 priority 15 llprio 3
carp: MASTER carpdev hvn4 vhid 1 advbase 1 advskew 0
groups: carp
status: master
inet 192.168.99.254 netmask 0xffffff00 broadcast 192.168.99.255
Notice in the above that it shows the status of the interface (in this case, the MASTER).
The syntax for the hostname
files on the secondary firewall differs slightly: -
## hostname.carp1
inet 192.0.2.1 255.255.255.0 192.0.2.255 vhid 1 carpdev hvn3 pass hvn3pass advskew 128
## hostname.carp2
inet 192.168.99.254 255.255.255.0 192.168.99.255 vhid 1 carpdev hvn4 pass hvn4pass advskew 128
The primary difference is the advskew
parameter. This is used to set a “priority” or “weight” on the interface, higher being less preferred.
The interface output on the secondary firewall looks like this: -
$ ifconfig carp1
carp1: flags=8843<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST> mtu 1500
lladdr 00:00:5e:00:01:01
index 8 priority 15 llprio 3
carp: BACKUP carpdev hvn3 vhid 1 advbase 1 advskew 128
groups: carp
status: backup
inet 192.0.2.1 netmask 0xffffff00 broadcast 192.0.2.255
$ ifconfig carp2
carp2: flags=8843<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST> mtu 1500
lladdr 00:00:5e:00:01:01
index 9 priority 15 llprio 3
carp: BACKUP carpdev hvn4 vhid 1 advbase 1 advskew 128
groups: carp
status: backup
inet 192.168.99.254 netmask 0xffffff00 broadcast 192.168.99.255
As you can see, the status of the interfaces are backup, meaning they will not respond on the Virtual IP, unless the master goes away (and they are promoted to master).
PF
After all of the above, you’ll now be ready to define a Packet Filter ruleset. There are a number of amazing resources on this, including The Book of PF by Peter Hansteen, The PF Tutorial (also by Peter Hansteen, along with Massimiliano Stucchi) and the OpenBSD PF FAQ.
PF is very flexible, in that you can apply macros, arrays/lists of IPs, and refer to them with as a single variable with your ruleset.
I have set up a very small ruleset on the two firewalls: -
oas cat /etc/pf.conf
doas ([email protected]) password:
## $OpenBSD: pf.conf,v 1.55 2017/12/03 20:40:04 sthen Exp $
##
## See pf.conf(5) and /etc/examples/pf.conf
ext_if="hvn3"
carp_ext_if="carp1"
carp_int_if="carp2"
int_if="hvn4"
sync_if="hvn2"
internet_if="hvn0"
set skip on lo
block return # block stateless traffic
pass # establish keep-state
## By default, do not permit remote connections to X11
block return in on ! lo0 proto tcp to port 6000:6010
## Port build user does not need network
block return out log proto {tcp udp} user _pbuild
## Allow PFSync
pass quick on $sync_if proto pfsync
## Allow CARP on in and out ints
pass quick on { $ext_if $int_if } proto carp
## NAT to net-01
pass out on $ext_if inet from $int_if:network to any nat-to $carp_ext_if
pass out on $ext_if inet from $carp_int_if:network to any nat-to $carp_ext_if
## NAT to the Internet
pass out on $internet_if inet from $int_if:network to any nat-to $internet_if
pass out on $internet_if inet from $carp_int_if:network to any nat-to $internet_if
A lot of the rules are from the examples, but I have also included a few extra rules: -
- Allowing PFSync on the $sync_if interface (in my case, hvn2)
- Allowing CARP on the interfaces they reside on (in my case, hvn3 and hvn4)
- Any traffic that comes in from the internal interfaces (hvn4 or carp2) going out of the interface facing net-01, to NAT it to the IP of the the $carp_ext_if (in my case, carp1)
- Any traffic that comes in from the internal interfaces (hvn4 or carp2) going out to the internet (the hvn0 interface), to NAT it to the IP of the the $internet_if (in my case, also hvn0).
The reason for not running carp(4)
on the internet interface is due to these being virtual machines without a shared Internet-facing network, or shared IP space.
To apply this ruleset, you can use doas pfctl -f /etc/pf.conf
. To enable pf(4)
to run at boot, use rcctl enable pf
(rcctl(8)
being a tool to control running daemons).
One important point to note is that pfsync(4)
does not synchronize configuration changes, only firewall state. You will need to manage keeping the rulesets synchronized separately using your chosen configuration management and deployment tool (e.g. rsync, ansible, rdist(1) or otherwise).
Verification
To show the active ruleset, you can run doas pfctl -s rules
$ doas pfctl -s rules
doas ([email protected]) password:
block return all
pass all flags S/SA
block return in on ! lo0 proto tcp from any to any port 6000:6010
block return out log proto tcp all user = 55
block return out log proto udp all user = 55
pass quick on hvn3 proto carp all
pass quick on hvn4 proto carp all
pass quick on hvn2 proto pfsync all
pass out on hvn3 inet from 192.168.99.0/24 to any flags S/SA nat-to 192.0.2.1
pass out on hvn0 inet from 192.168.99.0/24 to any flags S/SA nat-to 172.18.22.197
To view active statistics, you can run doas pfctl -vsr
doas pfctl -vsr
doas ([email protected]) password:
block return all
[ Evaluations: 1169 Packets: 0 Bytes: 0 States: 0 ]
[ Inserted: uid 0 pid 45241 State Creations: 0 ]
pass all flags S/SA
[ Evaluations: 1169 Packets: 11829 Bytes: 3762548 States: 11 ]
[ Inserted: uid 0 pid 45241 State Creations: 6645 ]
block return in on ! lo0 proto tcp from any to any port 6000:6010
[ Evaluations: 1169 Packets: 0 Bytes: 0 States: 0 ]
[ Inserted: uid 0 pid 45241 State Creations: 0 ]
block return out log proto tcp all user = 55
[ Evaluations: 145 Packets: 0 Bytes: 0 States: 0 ]
[ Inserted: uid 0 pid 45241 State Creations: 0 ]
block return out log proto udp all user = 55
[ Evaluations: 1168 Packets: 0 Bytes: 0 States: 0 ]
[ Inserted: uid 0 pid 45241 State Creations: 0 ]
pass quick on hvn3 proto carp all
[ Evaluations: 1169 Packets: 23243 Bytes: 1301608 States: 2 ]
[ Inserted: uid 0 pid 45241 State Creations: 2 ]
pass quick on hvn4 proto carp all
[ Evaluations: 1161 Packets: 23243 Bytes: 1301608 States: 2 ]
[ Inserted: uid 0 pid 45241 State Creations: 2 ]
pass quick on hvn2 proto pfsync all
[ Evaluations: 1167 Packets: 0 Bytes: 0 States: 0 ]
[ Inserted: uid 0 pid 45241 State Creations: 0 ]
pass out on hvn3 inet from 192.168.99.0/24 to any flags S/SA nat-to 192.0.2.1
[ Evaluations: 1167 Packets: 0 Bytes: 0 States: 0 ]
[ Inserted: uid 0 pid 45241 State Creations: 0 ]
pass out on hvn0 inet from 192.168.99.0/24 to any flags S/SA nat-to 172.18.22.197
[ Evaluations: 1160 Packets: 34 Bytes: 2676 States: 0 ]
[ Inserted: uid 0 pid 45241 State Creations: 26 ]
To view the current stats, you can run doas pfctl -ss
$ doas pfctl -ss
doas ([email protected]) password:
all pfsync 169.254.0.1 -> 224.0.0.240 SINGLE:NO_TRAFFIC
all pfsync 224.0.0.240 <- 169.254.0.0 NO_TRAFFIC:SINGLE
all tcp 192.168.241.7:22 <- 192.168.241.254:56448 ESTABLISHED:ESTABLISHED
all tcp 192.0.2.10:17742 -> 192.0.2.20:179 ESTABLISHED:ESTABLISHED
all tcp 192.168.241.6:22 <- 192.168.241.254:54168 ESTABLISHED:ESTABLISHED
all carp 192.0.2.10 -> 224.0.0.18 SINGLE:NO_TRAFFIC
all carp 192.168.99.1 -> 224.0.0.18 SINGLE:NO_TRAFFIC
all carp 224.0.0.18 <- 192.0.2.10 NO_TRAFFIC:SINGLE
all carp 224.0.0.18 <- 192.168.99.1 NO_TRAFFIC:SINGLE
all udp ff12::8384[21027] <- fe80::adfb:c525:9a:71b5[56280] NO_TRAFFIC:SINGLE
all udp 192.168.241.255:21027 <- 192.168.241.1:64395 NO_TRAFFIC:SINGLE
all udp 172.18.22.207:21027 <- 172.18.22.193:64395 NO_TRAFFIC:SINGLE
all tcp 192.0.2.11:179 <- 192.0.2.20:57424 TIME_WAIT:TIME_WAIT
all udp 239.255.255.250:1900 <- 192.168.241.1:58267 NO_TRAFFIC:SINGLE
all udp 239.255.255.250:1900 <- 172.18.22.193:58273 NO_TRAFFIC:SINGLE
all udp 172.18.22.207:138 <- 172.18.22.193:138 NO_TRAFFIC:SINGLE
all udp 192.168.241.255:138 <- 192.168.241.1:138 NO_TRAFFIC:SINGLE
all udp 172.18.22.198:45469 -> 193.150.34.2:123 MULTIPLE:SINGLE
all icmp 192.0.2.1:8 <- 192.0.2.20:23408 0:0
all udp 172.18.22.197:15594 -> 162.159.200.1:123 MULTIPLE:SINGLE
State replication and failover
To show the state replication, I have set a ping going from client-01 to net-01: -
$ ping 192.0.2.20
PING 192.0.2.20 (192.0.2.20) 56(84) bytes of data.
64 bytes from 192.0.2.20: icmp_seq=1 ttl=63 time=0.750 ms
64 bytes from 192.0.2.20: icmp_seq=2 ttl=63 time=0.685 ms
Viewing the state table on openbsdfw-01
for this, I can see: -
$ doas pfctl -ss | grep -i icmp
doas ([email protected]) password:
all icmp 192.0.2.20:8 <- 192.168.99.50:5463 0:0
all icmp 192.0.2.1:63341 (192.168.99.50:5463) -> 192.0.2.20:8 0:0
$ doas tcpdump -i hvn4 icmp
doas ([email protected]) password:
tcpdump: listening on hvn4, link-type EN10MB
13:16:46.519326 192.168.99.50 > 192.0.2.20: icmp: echo request (DF)
13:16:46.519931 192.0.2.20 > 192.168.99.50: icmp: echo reply
What do we see on openbsdfw-02
?
$ doas pfctl -ss | grep -i icmp
doas ([email protected]) password:
all icmp 192.0.2.20:8 <- 192.168.99.50:5463 0:0
all icmp 192.0.2.1:63341 (192.168.99.50:5463) -> 192.0.2.20:8 0:0
$ doas tcpdump -i hvn4 icmp
doas ([email protected]) password:
tcpdump: listening on hvn4, link-type EN10MB
So as you can see, we actually have the state (i.e. the ICMP packets going through), but the packets themselves do not traverse the secondary firewall.
What about if we shutdown the primary firewall?
$ doas shutdown -h now
doas ([email protected]) password:
Shutdown NOW!
shutdown: [pid 52871]
*** FINAL System shutdown message from [email protected] ***
System going down IMMEDIATELY
Did the traffic failover?
$ doas tcpdump -i hvn4 icmp
doas ([email protected]) password:
tcpdump: listening on hvn4, link-type EN10MB
13:20:02.105437 192.168.99.50 > 192.0.2.20: icmp: echo request (DF)
13:20:02.105823 192.0.2.20 > 192.168.99.50: icmp: echo reply
Looks like it did! Now lets check a few details on the secondary firewall: -
CARP Status
$ ifconfig carp1
carp1: flags=8843<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST> mtu 1500
lladdr 00:00:5e:00:01:01
index 8 priority 15 llprio 3
carp: MASTER carpdev hvn3 vhid 1 advbase 1 advskew 128
groups: carp
status: master
inet 192.0.2.1 netmask 0xffffff00 broadcast 192.0.2.255
$ ifconfig carp2
carp2: flags=8843<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST> mtu 1500
lladdr 00:00:5e:00:01:01
index 9 priority 15 llprio 3
carp: MASTER carpdev hvn4 vhid 1 advbase 1 advskew 128
groups: carp
status: master
inet 192.168.99.254 netmask 0xffffff00 broadcast 192.168.99.255
Looks like we failed over, what about the firewall statistics and states?
$ doas pfctl -ss | grep -i icmp
doas ([email protected]) password:
all icmp 192.0.2.20:8 <- 192.168.99.50:5463 0:0
all icmp 192.0.2.1:63341 (192.168.99.50:5463) -> 192.0.2.20:8 0:0
$ doas pfctl -vsr
doas ([email protected]) password:
block return all
[ Evaluations: 1445 Packets: 0 Bytes: 0 States: 0 ]
[ Inserted: uid 0 pid 97984 State Creations: 0 ]
pass all flags S/SA
[ Evaluations: 1445 Packets: 14751 Bytes: 4848439 States: 16 ]
[ Inserted: uid 0 pid 97984 State Creations: 6888 ]
block return in on ! lo0 proto tcp from any to any port 6000:6010
[ Evaluations: 1445 Packets: 0 Bytes: 0 States: 0 ]
[ Inserted: uid 0 pid 97984 State Creations: 0 ]
block return out log proto tcp all user = 55
[ Evaluations: 391 Packets: 0 Bytes: 0 States: 0 ]
[ Inserted: uid 0 pid 97984 State Creations: 0 ]
block return out log proto udp all user = 55
[ Evaluations: 1259 Packets: 0 Bytes: 0 States: 0 ]
[ Inserted: uid 0 pid 97984 State Creations: 0 ]
pass quick on hvn3 proto carp all
[ Evaluations: 1445 Packets: 47713 Bytes: 2671928 States: 1 ]
[ Inserted: uid 0 pid 97984 State Creations: 4 ]
pass quick on hvn4 proto carp all
[ Evaluations: 1257 Packets: 47713 Bytes: 2671928 States: 1 ]
[ Inserted: uid 0 pid 97984 State Creations: 4 ]
pass quick on hvn2 proto pfsync all
[ Evaluations: 1441 Packets: 0 Bytes: 0 States: 0 ]
[ Inserted: uid 0 pid 97984 State Creations: 0 ]
pass out on hvn3 inet from 192.168.99.0/24 to any flags S/SA nat-to 192.0.2.1
[ Evaluations: 1441 Packets: 434 Bytes: 36456 States: 1 ]
[ Inserted: uid 0 pid 97984 State Creations: 3 ]
pass out on hvn0 inet from 192.168.99.0/24 to any flags S/SA nat-to 172.18.22.198
[ Evaluations: 1255 Packets: 842 Bytes: 807671 States: 0 ]
[ Inserted: uid 0 pid 97984 State Creations: 27 ]
There we go, we’re passing traffic. How many packets did we lose during all of this?
[...]
--- 192.0.2.20 ping statistics ---
500 packets transmitted, 500 received, 0% packet loss, time 675ms
rtt min/avg/max/mdev = 0.424/0.856/3.406/0.270 ms
Well then, not a single packet lost. Looks like we saw high delay on one of them, but no packets actually dropped. If we set the timeout within the ping utility, I’m sure we would have seen a few drop. By default the time between packets is 1 second, which is more than enough to see in most practical situations that many people wouldn’t notice the failover.
Summary
OpenBSD is a very versatile operating system, with very sane defaults, and a high security focus. It also ships with a lot of software that means you may never need to add anything from external repositories/ports (everything from bgpd(4)
, snmpd(8)
, relayd(8)
and much more) to have a fully functional system, especially for security and network functions.
I am just a beginner when it comes to OpenBSD. If you want to know more about OpenBSD, I would urge you to visit: -
- The OpenBSD FAQ
- The OpenBSD events page - Contains a number of talks and slides about OpenBSD
- Reyk Floeter - Notable OpenBSD developer
- Peter Hansteen - Notable OpenBSD developer
- Peter Hessler - Notable OpenBSD developer
- Henning Brauer - Notable OpenBSD developer
- bsd.network - A Mastodon instance ran by Peter Hessler, with many users who contribute to OpenBSD
- OpenBSD Amsterdam - OpenBSD VPSs running on the OpenBSD
vmd(8)
Virtualisation Daemon, ran by Mischa Peters - Roman Zolotarev - Roman is involved in the BSD community, providing great information for those new to the world of all the BSDs (not just OpenBSD)
I’m missing out on many more, but the above is a good place to start! I would highly recommend going through the Events page and watching some talks regarding OpenBSD.