OpenBSD: System Configuration After Installation

OpenBSD: System Configuration After Installation

OpenBSD systems are configured through text files. hostname.if controls network interfaces, ntpd synchronizes time, doas provides delegated root privileges, and sysctl adjusts kernel parameters.

OpenBSD configures systems through text files. Each network interface has its own configuration file in /etc/hostname.INTERFACE. Time synchronization is handled by ntpd with built-in time zone support. Privilege management works through doas – OpenBSD’s system for delegated root privileges. Kernel parameters can be adjusted through sysctl.

This article explains network configuration through hostname.if files – for subsequent adjustments after installation as well as advanced setups for servers, desktop systems, and special requirements. The filesystem structure consistently follows OpenBSD conventions.

Network Configuration with hostname.if

Each network interface is controlled through a separate file. The filename follows the pattern /etc/hostname.INTERFACE – for example, /etc/hostname.em0 for Intel network cards or /etc/hostname.vio0 on virtual machines.

The installation creates these files automatically based on the installer input. Manual changes are made with a text editor:

$ doas vi /etc/hostname.vio0

Automatic Configuration via DHCP

The simplest configuration uses DHCP for automatic IP address assignment:

/etc/hostname.vio0:
inet autoconf
inet6 autoconf

inet autoconf enables automatic IPv4 configuration on the interface; dhcpleased then handles the DHCP configuration. inet6 autoconf enables automatic IPv6 configuration; slaacd processes Router Advertisements and SLAAC for this purpose. Learned DNS information is passed to resolvd, which manages /etc/resolv.conf.

Controlling IPv6 Behavior

IPv6 autoconfiguration is enabled for an interface with inet6 autoconf. slaacd then processes Router Advertisements and uses them to configure IPv6 addresses, among other things.

Disable IPv6 completely:

/etc/hostname.vio0:
inet autoconf
-inet6

This removes all IPv6 addresses and disables IPv6 autoconfiguration on the interface.

The configuration takes effect at the next reboot or immediately via:

$ doas sh /etc/netstart vio0

The /etc/netstart script reads the hostname.if file and applies the configuration to the interface. Daemons such as dhcpleased react to the resulting interface state.

Static IP Configuration

Servers often require fixed IP addresses. Static configuration explicitly defines the IP address, netmask, and gateway:

/etc/hostname.vio0:
inet 192.168.1.10 255.255.255.0
!route add default 192.168.1.1

The first line configures the IP address and netmask. The second line sets the default route. The exclamation mark ! executes the following command during interface activation.

CIDR notation (Classless Inter-Domain Routing) works as well. Instead of the netmask in decimal notation, /24 specifies the number of set bits – 24 bits correspond to 255.255.255.0:

/etc/hostname.vio0:
inet 192.168.1.10/24
!route add default 192.168.1.1

The DNS resolver requires manual configuration in /etc/resolv.conf:

/etc/resolv.conf:
nameserver 192.168.1.1
nameserver 192.168.1.2
lookup file bind

The lookup line defines the order for name resolution – first /etc/hosts, then DNS queries.

ℹ️ Info
With automatic network configuration, learned DNS information can be passed to resolvd. Together with other available nameserver information, resolvd uses it to manage the contents of /etc/resolv.conf.

Multiple IP Addresses on One Interface

An interface can have multiple IP addresses – useful for virtual hosts or service separation:

/etc/hostname.vio0:
inet 192.168.1.10/24
inet alias 192.168.1.11/24
inet alias 192.168.1.12/24
!route add default 192.168.1.1

The alias keyword defines additional IP addresses on the interface.

Additional addresses can also come from another directly connected subnet. Through the configured address and netmask, the system already knows this network; an additional gateway route is therefore not required solely because of the second address.

CIDR notation (/24) and decimal notation (255.255.255.0) can both be used for the configuration.

VLAN Configuration

VLANs logically separate network traffic. OpenBSD creates VLAN interfaces as vlan0, vlan1, and so on:

/etc/hostname.vlan10:
vnetid 10
parent vio0
inet 192.168.10.1/24
up
description "Management VLAN"

The configuration defines:

  • vnetid 10 - VLAN ID
  • parent vio0 - Parent interface (here: virtio in a VM, on hardware for example em0)
  • up - Activate the interface
  • description - Optional description for ifconfig output
ℹ️ Info
The order is important: hostname.if is processed line by line. For VLAN interfaces, vnetid and parent are therefore set first, followed by the IP configuration.

The parent interface vio0 does not require an IP address if only VLANs run on it:

/etc/hostname.vio0:
up

Multiple VLANs use the same parent interface:

/etc/hostname.vlan20:
vnetid 20
parent vio0
inet 192.168.20.1/24
description "Service VLAN"
up

Wireless Networks

Wi-Fi configuration is handled through the corresponding interface files. The interface name depends on the driver – for example, iwm0 for Intel chips or athn0 for Atheros.

WPA2 configuration with a PSK:

/etc/hostname.iwm0:
nwid "HomeNetwork" wpakey "supersecret123"
inet autoconf

The parameters define:

  • nwid - Network SSID
  • wpakey - WPA2 passphrase
  • inet autoconf - DHCP after a successful connection

Hidden Networks (the SSID is not broadcast) work with the same syntax. The SSID must be specified manually – the scan shows it without a name.

⚠️ Important
Wi-Fi passwords are stored in plaintext in /etc/hostname.INTERFACE. The file should therefore only be readable by users who need these credentials.

Bridge Configuration

Bridges connect multiple network interfaces at Layer 2. A typical use case is integrating virtual machines directly into the physical network.

/etc/hostname.bridge0:
add em0
add vio0
up

The bridge0 bridge connects the em0 and vio0 interfaces at Layer 2. Frames can therefore be forwarded between the bridge members.

The connected interfaces do not require IP addresses:

/etc/hostname.em0:
up

/etc/hostname.vio0:
up

The IP configuration is applied to the bridge itself:

/etc/hostname.bridge0:
add em0
add vio0
inet 192.168.1.10/24
!route add default 192.168.1.1
up

Activating Network Configuration

Changes to hostname.if files take effect at reboot. For immediate activation:

$ doas sh /etc/netstart vio0

The script applies the configuration from the corresponding hostname.if file to the interface.

To reapply the complete network configuration:

$ doas sh /etc/netstart

The system reruns network initialization based on the existing configuration files. This also includes configurable interfaces such as VLAN interfaces.

Time and Time Synchronization

OpenBSD uses ntpd for time synchronization. The daemon is part of the base system – no additional packages are required. On a standard installation, ntpd is started at boot.

ntpd Configuration

The /etc/ntpd.conf file controls time synchronization:

/etc/ntpd.conf (Default):
servers pool.ntp.org
server time.cloudflare.com
sensor *

constraint from "9.9.9.9"              # quad9 v4 without DNS
constraint from "2620:fe::fe"          # quad9 v6 without DNS
constraints from "www.google.com"      # intentionally not 8.8.8.8

The lines define:

  • servers pool.ntp.org - Uses all IP addresses of the NTP pool. The daemon synchronizes with multiple servers simultaneously.
  • server time.cloudflare.com - A single additional NTP server.
  • sensor * - Uses all available timedelta sensors as additional time sources.
  • constraint from - Defines an HTTPS-based time constraint. Multiple configured constraints are used together to validate NTP time.
  • constraints from - Uses all IP addresses of a resolved hostname as constraints.

The constraints provide an authenticated time boundary over HTTPS. This can reduce the effects of manipulated or forged NTP responses.

ℹ️ Info
Constraints require access to the respective configured HTTPS source. If that source is unreachable, it cannot be used to validate NTP time.

Configuring the Time Zone

System time runs internally in UTC. The local time zone is defined through a symlink:

$ ls -l /etc/localtime
lrwxr-xr-x  1 root  wheel  33 Nov  1 21:27 /etc/localtime -> /usr/share/zoneinfo/Europe/Berlin

Change the time zone:

$ doas rm /etc/localtime
$ doas ln -s /usr/share/zoneinfo/Europe/Zurich /etc/localtime

Available time zones are located in /usr/share/zoneinfo/. The directory structure follows the IANA time zone database – continent/city format.

Managing the ntpd Daemon

The NTP daemon starts automatically at boot. Check its status:

$ rcctl check ntpd
ntpd(ok)

The status output (ok) means that the daemon is running. Check time synchronization:

$ ntpctl -s status
5/5 peers valid, 1/1 sensors valid, constraint offset -2s, clock synced, stratum 3

The output shows:

  • 5/5 peers valid - All configured NTP servers are responding
  • 1/1 sensors valid - One time sensor is valid
  • constraint offset -2s - Time offset of the determined constraint relative to the local system time
  • clock synced - System time is synchronized
  • stratum 3 - Synchronization hierarchy of the local system. Lower stratum values indicate a shorter hierarchy to a reference time source.

Detailed peer information:

$ ntpctl -s peers
peer
   wt tl st  next  poll          offset       delay      jitter
162.159.200.1 time.cloudflare.com
    1 10  3 1551s 1627s         1.717ms    30.046ms     8.432ms
217.144.138.234 from pool pool.ntp.org
    1 10  2 1341s 1521s         3.957ms    42.019ms     9.079ms
94.130.35.4 from pool pool.ntp.org
    1 10  2    7s 1633s         1.234ms    40.783ms     8.753ms
45.9.61.155 from pool pool.ntp.org
 *  1 10  2 1381s 1565s         4.494ms    42.251ms    14.893ms
185.252.140.126 from pool pool.ntp.org
    1 10  2   30s 1641s         1.857ms    44.043ms    10.572ms

The columns mean:

  • wt (weight) - Weight of the time source; the default value is 1
  • tl (trust level) - Internal trust value of the peer
  • st (stratum) - Hierarchy level of the server
  • next - Seconds until the next query
  • poll - Current polling interval in seconds (adjusts automatically)
  • offset - Time difference between the server and the local system
  • delay - Network latency to the server (round-trip time)
  • jitter - Variation in the time difference across multiple measurements

The asterisk * marks the peer to which the system clock is currently synchronized.

Time Synchronization with Large Offsets

ntpd corrects time offsets gradually through adjtime(2), avoiding jumps in system time. With larger offsets, the complete correction can therefore take correspondingly longer.

For faster initial synchronization, rdate can set the system time immediately:

$ doas rdate pool.ntp.org
$ doas rcctl restart ntpd

ntpctl -s status can be used to check whether the system time has already reached the clock synced status. How long this takes after startup depends, among other things, on the reachable time sources and the initial state of the system clock.

Privilege Management with doas

OpenBSD uses doas for privileged commands. The tool follows OpenBSD’s principle of simplicity – few configuration options and clear syntax. Configuration is stored in /etc/doas.conf.

Basic Configuration

The installation article shows a minimal doas configuration. For regular use, an extended configuration is useful:

/etc/doas.conf:
permit persist :wheel
permit nopass keepenv root as root

The rules in detail:

permit persist :wheel - Members of the wheel group may use doas to execute commands as other users. The persist flag remembers a successful authentication for a limited time, so repeated doas invocations do not immediately ask for the password again.

permit nopass keepenv root as root - When root is both the invoking and target user, no password prompt is required; keepenv additionally preserves the invoking user’s environment.

User-Specific Rules

Individual users can be granted specific privileges:

/etc/doas.conf:
permit persist :wheel
permit nopass michael cmd /usr/sbin/pkg_add
permit nopass michael cmd /usr/sbin/pkg_delete
permit nopass sandra cmd /usr/sbin/rcctl args restart httpd

The rules define:

permit nopass michael cmd /usr/sbin/pkg_add - User michael may run pkg_add without a password. Useful for frequent package installations.

permit nopass sandra cmd /usr/sbin/rcctl args restart httpd - User sandra may only run rcctl restart httpd. The args keyword restricts the permitted arguments.

Controlling Environment Variables

By default, doas creates a new environment for the target user and sets, among other variables, HOME, LOGNAME, PATH, SHELL, and USER appropriately for the target. With keepenv, additional variables from the invoking user’s environment are preserved:

/etc/doas.conf:
permit persist keepenv :wheel

setenv provides more precise control with four variants:

/etc/doas.conf:
permit persist setenv { -ENV PS1=$DOAS_PS1 SSH_AUTH_SOCK PATH=/sbin:/bin } :wheel

The syntax supports:

  • SSH_AUTH_SOCK - Preserve the variable from the user environment
  • PS1=$DOAS_PS1 - Take the value from an existing variable (using $)
  • PATH=/sbin:/bin - Set to a fixed value
  • -ENV - Explicitly remove the variable (using -)

Multiple definitions are separated by spaces.

ℹ️ Info
The example shows the different possibilities provided by setenv: variables can be preserved, newly set, derived from other variables, or explicitly removed.

Testing the doas Configuration

If /etc/doas.conf cannot be parsed, the privilege check fails. The configuration can therefore be checked before use:

$ doas -C /etc/doas.conf

The -C option parses and checks the configuration file without executing a command. With an error-free configuration, this invocation produces no output. Syntax errors are reported with a line number.

Kernel Parameters with sysctl

The sysctl tool reads and changes kernel parameters at runtime. The values are grouped into categories – networking, filesystem, hardware, security.

Displaying Available Parameters

List all available parameters:

$ sysctl -a
kern.ostype=OpenBSD
kern.osrelease=7.9
kern.osrevision=202605
kern.version=OpenBSD 7.9 (GENERIC.MP) #449: Wed May  6 13:17:25 MDT 2026
    deraadt@amd64.openbsd.org:/usr/src/sys/arch/amd64/compile/GENERIC.MP

kern.maxvnodes=12277
kern.maxproc=1310
kern.maxfiles=7030
[...]

The output shows several hundred parameters. Filter by category:

$ sysctl net.inet.ip
net.inet.ip.forwarding=0
net.inet.ip.redirect=1
net.inet.ip.ttl=64
net.inet.ip.mtudisc=1

The hierarchical structure allows more precise queries of individual areas and parameters.

Important Network Parameters

Enable IP forwarding - required when the system is to route IPv4 packets between interfaces:

$ doas sysctl net.inet.ip.forwarding=1
net.inet.ip.forwarding: 0 -> 1

The system forwards IPv4 packets between interfaces. On a standard installation, IPv4 forwarding is disabled.

IPv6 forwarding works analogously:

$ doas sysctl net.inet6.ip6.forwarding=1

Adjust system limits:

$ doas sysctl kern.maxfiles=10000
$ doas sysctl kern.maxproc=2000

The maxfiles parameter limits the system-wide number of open files, while maxproc limits the maximum number of simultaneous processes. Whether these limits need to be adjusted depends on the specific resource requirements of the system and its services.

Permanent Changes

Permanent configuration is stored in /etc/sysctl.conf. If the file does not exist, it can be created as needed:

$ doas vi /etc/sysctl.conf

Contents:

net.inet.ip.forwarding=1
net.inet6.ip6.forwarding=1
kern.maxfiles=10000

The file is read automatically at boot. The syntax is identical to sysctl commands, only without the sysctl prefix – for example, net.inet.ip.forwarding=1 instead of sysctl net.inet.ip.forwarding=1.

ℹ️ Info
Changes to /etc/sysctl.conf take effect only at the next boot. For immediate activation, an additional manual sysctl invocation is required.

Filesystem Structure

OpenBSD follows BSD conventions for its filesystem structure. Some differences from Linux exist – particularly in system directories and package management.

Base System vs. Packages

OpenBSD separates the base system from additionally installed packages. Programs and libraries belonging to the base system are located, among other places, in /bin, /sbin, /usr/bin, and /usr/sbin. Packages are generally installed under /usr/local; depending on the package, individual files may also be placed in other designated locations. The Package Management article explains this separation in detail.

Important System Directories

/etc - System configuration. All important configuration files are located here:

  • hostname.* - Network configuration
  • rc.conf.local - Local service configuration
  • doas.conf - Privilege management
  • sysctl.conf - Persistent kernel parameters

/var - Variable data. Log files, spool directories, temporary data:

  • /var/log - System logs
  • /var/mail - Mail spool
  • /var/www - Default webroot
  • /var/run - Runtime files (PIDs, sockets)

/usr/local - Installed packages:

  • /usr/local/bin - Executable programs
  • /usr/local/lib - Libraries
  • /usr/local/share - Shared data
  • /usr/local/etc - Package-specific configuration (created as needed)

/home - User directories. Standard layout with hidden configuration files (.profile, .kshrc).

X11 Structure

X11 components are located under /usr/X11R6 – but only if the X11 sets were selected during installation:

/usr/X11R6/bin       # X11 programs (xterm, xclock)
/usr/X11R6/lib       # X11 libraries
/usr/X11R6/share     # Fonts, icons, themes

This separation keeps the X11 components shipped with OpenBSD in their own directory tree.

Device Nodes

Device nodes are located in /dev. They provide the interface to devices made available by the kernel. Under OpenBSD, the required special files are created, among other ways, with /dev/MAKEDEV:

$ ls -l /dev/sd0*
brw-r-----  1 root  operator  4,  0 Jun  9 10:26 /dev/sd0a
brw-r-----  1 root  operator  4,  1 Jun  9 10:26 /dev/sd0b
brw-r-----  1 root  operator  4,  2 Jun  9 10:26 /dev/sd0c
[...]

The letter suffixes designate partitions in the OpenBSD disklabel:

  • a - Conventionally the root partition (/) on the boot disk
  • b - Conventionally swap on the boot disk
  • c - The entire physical device; this partition has a special meaning
  • d-p - Additional partitions as needed

The specific assignments other than c depend on the respective disklabel. The /dev/MAKEDEV script creates device nodes as needed.

Mount Points

The /etc/fstab file defines automatic mounts at boot:

$ cat /etc/fstab
1d2d758e4ba30877.b none swap sw
1d2d758e4ba30877.a / ffs rw 1 1
1d2d758e4ba30877.k /home ffs rw,nodev,nosuid 1 2
1d2d758e4ba30877.d /tmp ffs rw,nodev,nosuid 1 2
1d2d758e4ba30877.f /usr ffs rw,nodev 1 2
1d2d758e4ba30877.g /usr/X11R6 ffs rw,nodev 1 2
1d2d758e4ba30877.h /usr/local ffs rw,wxallowed,nodev 1 2
1d2d758e4ba30877.j /usr/obj ffs rw,nodev,nosuid 1 2
1d2d758e4ba30877.i /usr/src ffs rw,nodev,nosuid 1 2
1d2d758e4ba30877.e /var ffs rw,nodev,nosuid 1 2

The hexadecimal strings are DUIDs – unique device IDs. In /etc/fstab, DUIDs can be used instead of device names such as /dev/sd0a. This keeps the reference to a filesystem independent of the device name under which the disk is detected. The partition letters (a, b, d, e, …) are assigned during installation and vary depending on the selected partitioning scheme.

The mount options:

  • rw - Read-write access
  • nodev - Special files on this filesystem are not interpreted as devices
  • nosuid - Set-user-ID and set-group-ID bits do not take effect when executing files
  • wxallowed - Allows executable and simultaneously writable memory mappings for programs on this filesystem, for example for software with a JIT compiler

Temporary Filesystems

In the installation shown, /tmp is located on a separate filesystem. On systems with sufficient available memory, /tmp can be mounted as tmpfs:

$ cat /etc/fstab
swap /tmp tmpfs rw,nodev,nosuid,-s=2G 0 0

The tmpfs uses virtual memory instead of a persistent block device. The -s=2G parameter limits its size to 2 gigabytes. Because the filesystem is not persistent, its contents are no longer present after a reboot.


Information Used

This guide refers to:

  • OpenBSD: 7.8, 7.9
  • Architecture: amd64 (primarily), general concepts apply to all platforms
  • Context: Server and desktop configuration
  • As of: August 2026

System configuration forms the foundation for production OpenBSD systems. The next article covers Package Management – software installation and updates.

Michael

has worked with technical systems, their dependencies, and interfaces for more than four decades – today with a particular focus on resilient systems, digital independence, and the controlled use of AI.
More about Michael →

Open Knowledge Needs People

We develop ideas, share knowledge, and create open-source software and tools. With your support, you help us continue this work for years to come.
Get involved and support our work →
OpenBSD: System Configuration After Installation
← Next Article OpenBSD: Package Management and Software Installation
OpenBSD: System Configuration After Installation
Previous Article → OpenBSD: Installation and First Steps