OpenBSD keeps the base system and packages completely separate. The base system resides in /usr/bin and /usr/sbin, while installed packages are placed under /usr/local. This separation is a core principle of OpenBSD’s stability and security model. Software is installed as binary packages—compiled, signed, and verified by the OpenBSD team. Every package carries a cryptographic signature via signify(1).
System Configuration explains the basic system setup after installation. This article covers software installation, updates, and package management. Package management is deliberately simple—three tools handle every task: pkg_add, pkg_delete, and pkg_info.
Base System and Packages
The separation between the base system and packages is fundamental. The base system contains only the core components—kernel, shell, essential utilities, the C compiler, and X11. No distribution-specific customizations or optional software.
Software outside the base system is installed as a package:
/usr/bin/vi # Base system editor (included)
/usr/local/bin/vim # vim package (after installation)
/usr/sbin/httpd # Base system HTTP server (included)
/usr/local/sbin/nginx # nginx package (after installation)
Packages install exclusively under /usr/local. This separation prevents conflicts between system tools and installed software. The base system remains untouched by package installations.
The update strategy reflects this separation:
- sysupgrade updates the base system
- pkg_add -u updates installed packages
- No mixing of the two systems
base*.tgz, comp*.tgz, man*.tgz, and game*.tgz sets make up the base system. Packages are installed later using pkg_add.
pkg_add - Installing Software
The pkg_add tool installs software from OpenBSD repositories. Installation downloads packages, verifies signatures, and automatically installs dependencies.
Simple Installation
Install a package:
$ doas pkg_add nginx
quirks-7.194 signed on 2026-06-10T19:46:25Z
nginx-1.30.2:bzip2-1.0.8p0: ok
nginx-1.30.2:pcre2-10.44: ok
nginx-1.30.2: ok
The following new rcscripts were installed: /etc/rc.d/nginx
See rcctl(8) for details.
New and changed readme(s):
/usr/local/share/doc/pkg-readmes/nginx
The first line refers to the quirks package—it contains metadata about package dependencies and compatibility. It is updated automatically during every installation. Dependencies such as bzip2 and pcre2 are installed automatically. The message about rcscripts indicates that nginx is available as a service (details in the planned article Services and Daemons).
The New and changed readme(s) line indicates that the package has installed a README under /usr/local/share/doc/pkg-readmes/—useful for initial configuration and port-specific notes.
Package requiring user selection:
$ doas pkg_add vim
quirks-7.194 signed on 2026-06-10T19:46:25Z
Ambiguous: choose package for vim
a 0: <None>
1: vim-9.2.357
2: vim-9.2.357-gtk3
3: vim-9.2.357-gtk3-lua
4: vim-9.2.357-gtk3-perl-python3-ruby
5: vim-9.2.357-gtk3-python3
6: vim-9.2.357-lua
7: vim-9.2.357-perl-python3-ruby
8: vim-9.2.357-python3
9: vim-9.2.357-ruby
Your choice: 1
vim-9.2.357:libsodium-1.0.22: ok
vim-9.2.357:libiconv-1.19: ok
vim-9.2.357:gettext-runtime-1.0: ok
vim-9.2.357: ok
Several variants are available—with different feature sets (GTK3 GUI, Lua, Python3, Ruby) or without X11 for servers. Selection is made interactively or by specifying the exact package name:
$ doas pkg_add vim-9.2.357-lua
Searching for Packages
Search available packages:
$ pkg_info -Q rsync
debug-rsync-3.4.4
debug-rsync-3.4.4-minimal
rsync-3.4.4
rsync-3.4.4-minimal
The -Q option searches package names. Substring matching works—py, python, and python3 all find the corresponding packages.
Debug variants contain additional symbols for debugging and are not relevant for normal operation.
Detailed package search:
$ pkg_info -Q nginx
nginx-1.30.2 (installed)
nginx-cache_purge-1.30.2
nginx-headers-more-1.30.2
nginx-lua-1.30.2
nginx-stream-1.30.2
[... additional module variants ...]
The suffix (installed) identifies packages that are already installed.
Detailed information about a package is provided by pkg_info without the -Q option—see the section pkg_info - Listing Installed Software.
Installing Dependencies Automatically
The package manager resolves dependencies automatically:
$ doas pkg_add mariadb-server
quirks-7.194 signed on 2026-06-10T19:46:25Z
mariadb-server-11.4.10p0v1:lz4-1.10.0: ok
mariadb-server-11.4.10p0v1:xz-5.8.3: ok
mariadb-server-11.4.10p0v1:zstd-1.5.7p0: ok
mariadb-server-11.4.10p0v1:mariadb-client-11.4.10p0v1: ok
mariadb-server-11.4.10p0v1:coreutils-9.10: ok
mariadb-server-11.4.10p0v1:p5-DBI-1.648: ok
mariadb-server-11.4.10p0v1:p5-DBD-MariaDB-1.23: ok
mariadb-server-11.4.10p0v1:curl-8.20.0: ok
[... additional dependencies ...]
mariadb-server-11.4.10p0v1: ok
Running tags: ok
The following new rcscripts were installed: /etc/rc.d/mysqld
See rcctl(8) for details.
New and changed readme(s):
/usr/local/share/doc/pkg-readmes/mariadb-server
The client package, compression libraries (lz4, xz, zstd), Perl modules (DBI, DBD-MariaDB), and a modern HTTP stack (curl with ngtcp2, nghttp2, and nghttp3) are installed automatically. These dependencies are required for server operation.
Installed dependencies cannot later be removed individually without uninstalling the main package. pkg_delete checks dependencies before removal.
Packages that display a README notice should be read before being put into service—the directory /usr/local/share/doc/pkg-readmes/ contains package-specific documentation covering initial configuration and special considerations.
Installing Multiple Packages at Once
Install a list of packages:
$ doas pkg_add git htop rsync curl
quirks-7.194 signed on 2026-06-10T19:46:25Z
git-2.53.0:cvsps-2.1p3: ok
git-2.53.0:gitwrapper-0.125: ok
git-2.53.0:p5-Error-0.17030: ok
git-2.53.0:p5-Time-TimeDate-2.33: ok
git-2.53.0:p5-Mail-Tools-2.21p0: ok
git-2.53.0: ok
htop-3.4.1:libb2-0.98.1v0: ok
htop-3.4.1:sqlite3-3.51.3: ok
htop-3.4.1:python-3.13.13: ok
[... additional dependencies ...]
htop-3.4.1: ok
Ambiguous: choose package for rsync
a 0: <None>
1: rsync-3.4.4
2: rsync-3.4.4-minimal
Your choice: 2
rsync-3.4.4-minimal: ok
Running tags: ok
The following new rcscripts were installed: /etc/rc.d/gitdaemon /etc/rc.d/rsyncd
See rcctl(8) for details.
New and changed readme(s):
/usr/local/share/doc/pkg-readmes/git
/usr/local/share/doc/pkg-readmes/glib2
Packages that are already installed (in this case curl as a dependency of MariaDB) are skipped silently. Packages with multiple variants require an interactive selection. If an error occurs (missing packages or network problems), the installation is aborted.
doas for privilege management. Regular users can install packages only if an appropriate doas.conf rule exists.
Repository Structure
OpenBSD uses official mirrors for package distribution. The mirror URL is read automatically from /etc/installurl:
$ cat /etc/installurl
https://cdn.openbsd.org/pub/OpenBSD
This file is created during installation based on geographical proximity. It can be changed manually if a faster mirror is known.
Mirror List
Official mirrors are documented on the OpenBSD website: https://www.openbsd.org/ftp.html ↗
German mirrors (selection):
https://ftp.spline.de/pub/OpenBSD/ # Berlin
https://ftp.halifax.rwth-aachen.de/pub/OpenBSD/ # Aachen
https://artfiles.org/openbsd/ # Hamburg
https://ftp.hostserver.de/pub/OpenBSD/ # Frankfurt
https://mirror.junda.nl/pub/OpenBSD/ # Falkenstein
Change the mirror:
$ echo "https://ftp.hostserver.de/pub/OpenBSD" | doas tee /etc/installurl
https://ftp.hostserver.de/pub/OpenBSD
$ cat /etc/installurl
https://ftp.hostserver.de/pub/OpenBSD
The pipe together with tee writes the URL into the file with root privileges. The next package installation will use the new mirror. No cache cleanup or system reboot is required.
Package Layout in the Repository
Packages are stored either under snapshots or under a release version number:
https://cdn.openbsd.org/pub/OpenBSD/7.9/packages/amd64/
The URL components:
- 7.9 - OpenBSD version (current release)
- packages - Binary packages (as opposed to sets)
- amd64 - Architecture (Intel/AMD 64-bit)
Snapshots use newer package versions:
https://cdn.openbsd.org/pub/OpenBSD/snapshots/packages/amd64/
Snapshot packages work only with a snapshot base system. The versions must match.
Signature Verification
Every package carries a digital signature. The signify(1) utility automatically verifies authenticity and integrity during installation.
Automatic Verification
Signature verification happens transparently:
$ doas pkg_add nginx
quirks-7.194 signed on 2026-06-10T19:46:25Z
nginx-1.30.2: ok
The signed on... line confirms that signature verification succeeded. If the signature is invalid, the installation is aborted immediately:
nginx-1.30.2: signature check failed
Installation aborted
Modified or corrupted packages are rejected unconditionally. There is no bypass—signature verification is mandatory.
Public Keys
Signature verification uses the public keys stored in /etc/signify:
$ ls /etc/signify
openbsd-72-base.pub openbsd-75-base.pub openbsd-78-base.pub
openbsd-72-fw.pub openbsd-75-fw.pub openbsd-78-fw.pub
openbsd-72-pkg.pub openbsd-75-pkg.pub openbsd-78-pkg.pub
openbsd-72-syspatch.pub openbsd-75-syspatch.pub openbsd-78-syspatch.pub
[... older release versions ...]
openbsd-79-base.pub openbsd-80-base.pub
openbsd-79-fw.pub openbsd-80-fw.pub
openbsd-79-pkg.pub openbsd-80-pkg.pub
openbsd-79-syspatch.pub openbsd-80-syspatch.pub
The keys are release-specific:
- base.pub - Base system updates
- pkg.pub - Package signatures
- fw.pub - Firmware updates
- syspatch.pub - Security patches
The system stores keys for multiple releases, making upgrades and downgrades possible. During a system upgrade, new keys are installed automatically.
The openbsd-80-* keys are already present—the OpenBSD project ships the signature key for the next release as part of the current system so upgrades can be performed without downloading an external key.
Trust Chain
The keys themselves are part of the base system. They are installed from the installation ISO—which in turn carries a signature that is verified before download.
Trust chain:
- The ISO signature is verified with
signify(1)(using the public release key) - Installation copies the signature keys to
/etc/signify - Packages are verified using those keys
The keys rotate with every release. Older keys remain valid for older releases, allowing downgrades or parallel release versions.
pkg_info - Listing Installed Software
The pkg_info utility displays installed packages, detailed information, and dependencies.
All Installed Packages
List all installed packages:
$ pkg_info
bzip2-1.0.8p0 block-sorting file compressor, unencumbered
coreutils-9.10 file, shell and text manipulation utilities
curl-8.20.0 transfer files with FTP, HTTP, HTTPS, etc.
git-2.53.0 distributed version control system
htop-3.4.1 interactive process viewer
mariadb-client-11.4.10p0v1 multithreaded SQL database (client)
mariadb-server-11.4.10p0v1 multithreaded SQL database (server)
nginx-1.30.2 robust and small HTTP server and mail proxy server
python-3.13.13 interpreted object-oriented programming language
rsync-3.4.4-minimal mirroring/synchronization over low bandwidth links
vim-9.2.357 vi clone with many additional features
[... additional installed packages ...]
The output shows the package name, version, and a short description. Dependencies (such as libiconv and p5-* modules) are listed as well.
Package Details
Display detailed information about a package:
$ pkg_info nginx-1.30.2
Information for inst:nginx-1.30.2
Comment:
robust and small HTTP server and mail proxy server
Description:
This is the stable branch of nginx, as distributed by nginx.org.
nginx provides FastCGI and reverse HTTP proxying, with or without caching,
including simple load balancing and fault tolerance.
It has a modular architecture. Filters include gzipping, byte ranges,
chunked responses, and SSI. Multiple SSI inclusions within a single page
can be processed in parallel if they are handled by FastCGI or proxied
servers. SSL and TLS SNI are supported.
Maintainer: Robert Nagy <robert@openbsd.org>
WWW: https://nginx.org/
The output contains:
- Comment - Purpose of the package
- Description - Description
- Maintainer - Responsible port maintainer
- WWW - Upstream project URL
Package Size
Display the disk usage of an installed package:
$ pkg_info -s nginx
Information for inst:nginx-1.30.2
Size: 1395276
The size is reported in bytes (approximately 1.4 MB in this example).
Package Signature
Display the package signature and dependencies:
$ pkg_info -S nginx
Information for inst:nginx-1.30.2
Signature: nginx-1.30.2,15,@pcre2-10.44,c.103.0,crypto.57.2,pcre2-8.0.7,ssl.60.2,z.7.2
The signature lists library dependencies together with their version numbers (@ denotes a direct port, while the remaining entries are system libraries).
Listing Dependencies
Dependencies of an installed package:
$ pkg_info -f postgresql-server | grep @depend
@depend databases/postgresql,-main:postgresql-client-=18.4:postgresql-client-18.4
@depend textproc/icu4c,-main:icu4c-*:icu4c-78.3v0
@depend textproc/libxml:libxml-*:libxml-2.15.3
The package requires postgresql-client at the exact version (=18.4), while icu4c and libxml may be any matching current version (-*).
Determine which packages depend on a specific package:
$ pkg_info -R mariadb-client
Information for inst:mariadb-client-11.4.10p0v1
Required by:
mariadb-server-11.4.10p0v1
p5-DBD-MariaDB-1.23
The output lists every package that depends on mariadb-client. This is useful before removing a package, since it shows which installed packages would be affected.
Files Installed by a Package
List every file belonging to a package:
$ pkg_info -L nginx
Information for inst:nginx-1.30.2
Files:
/etc/rc.d/nginx
/usr/local/sbin/nginx
/usr/local/man/man8/nginx.8
/usr/local/share/nginx/nginx.conf
/usr/local/share/nginx/html/index.html
/usr/local/share/doc/pkg-readmes/nginx
[... additional files ...]
This displays every installed file, configuration file, and documentation file. It is useful for determining exactly where a package installs its files.
Determine Which Package Installed a File
Find out which package installed a file:
$ pkg_info -E /usr/local/bin/vim
/usr/local/bin/vim: vim-9.2.357
vim-9.2.357 vi clone with many additional features
The -E option searches for an exact path. It works only for files that are already installed.
The output shows the package name together with its description. This is useful when investigating unknown binaries or configuration files.
pkg_delete – Removing Software
The pkg_delete utility removes installed packages together with all of their files. Configuration files may optionally be preserved.
Removing a Single Package
Uninstall a package:
$ doas pkg_delete nginx
nginx-1.30.2: ok
Read shared items: ok
All files belonging to the package are removed completely, including modified configuration files. Important configuration files should be backed up before uninstalling a package. The Read shared items message indicates that the package manager checks whether any shared files are still used by other packages.
Dependency Checks
Removing a package with dependencies:
$ doas pkg_delete mariadb-client
can't delete mariadb-client-11.4.10p0v1 without deleting mariadb-server-11.4.10p0v1 p5-DBD-MariaDB-1.23
Delete them as well ? [y/N/a] a
p5-DBD-MariaDB-1.23:mariadb-server-11.4.10p0v1: ok
p5-DBD-MariaDB-1.23: ok
mariadb-client-11.4.10p0v1: ok
Read shared items: ok
--- -mariadb-server-11.4.10p0v1 -------------------
You should also run /usr/sbin/userdel _mysql
You should also run /usr/sbin/groupdel _mysql
The message lists dependent packages and asks whether they should be removed as well:
- y — Yes, remove these packages (additional conflicts will prompt again)
- N — No, abort without making changes (default)
- a — All, automatically answer “yes” for these and all subsequent dependency conflicts
Packages do not automatically remove system users or groups. The final message shows the manual cleanup steps.
Cleaning Up Orphaned Dependencies
After packages are removed, automatically installed dependencies may remain. Remove them with:
$ doas pkg_delete -a
p5-Clone-0.47:p5-DBI-1.648: ok
p5-Clone-0.47:p5-SQL-Statement-1.414: ok
p5-Clone-0.47: ok
lua-5.1.5p8:luajit-2.1.1772619647: ok
lua-5.1.5p8: ok
lzo2-2.10p2: ok
coreutils-9.10: ok
p5-Net-Daemon-0.49:p5-PlRPC-0.2020p0: ok
p5-Net-Daemon-0.49: ok
p5-Params-Util-1.102: ok
libxml-2.15.3: ok
findutils-4.10.0p0: ok
snappy-1.1.10p2: ok
p5-MLDBM-2.05p0: ok
p5-FreezeThaw-0.5001p0: ok
p5-Math-Base-Convert-0.11p0: ok
zstd-1.5.7p0: ok
lz4-1.10.0: ok
p5-Module-Runtime-0.018: ok
Running tags: ok
Read shared items: ok
--- -libxml-2.15.3 -------------------
You should also remove /var/db/xmlcatalog
This removes all packages that:
- were installed only as dependencies (without the
@option manual-installationflag) - are no longer required by any other installed package
Packages installed manually are preserved.
Some packages leave behind databases or catalog files that must be removed manually.
Removing a Package Together with Unneeded Dependencies
Remove a package and automatically clean up dependencies that are no longer required:
$ doas pkg_delete -a htop
This removes htop together with any automatically installed dependencies that are no longer needed by other packages.
Updates and System Maintenance
OpenBSD clearly separates base system updates from package updates. Each is handled by a different utility.
Updating Packages
Update all installed packages:
$ doas pkg_add -u
quirks-7.194 signed on 2026-06-10T19:46:25Z
The command first updates quirks, then checks every installed package. If no updates are available, it exits without further output.
When updates are available, they are installed automatically:
$ doas pkg_add -u
quirks-7.147 signed on 2025-12-14T12:31:29Z
nginx-1.26.3->1.28.0p1: ok
vim-9.1.1650->9.1.1706-no_x11: ok
(Example from OpenBSD 7.8 — package names and version numbers vary between releases.)
Update a single package:
$ doas pkg_add -u vim
Only the specified package is checked and updated. Dependencies are updated automatically if required.
Base System Updates
List available patches without installing them:
$ doas syspatch -c
002_smtpd
003_vmd
syspatch -c is also suitable for cron jobs because it produces output only when patches are available.
Install patches:
$ doas syspatch
Get/Verify syspatch79-002_smtpd.tgz 100% |***...***| 313 KB 00:00
Installing patch 002_smtpd
Get/Verify syspatch79-003_vmd.tgz 100% |***...***| 114 KB 00:00
Installing patch 003_vmd
Errata can be reviewed under /var/syspatch
The patches are downloaded, signature-verified, and installed automatically. When a kernel patch is installed, the message reboot to load the new kernel is displayed, indicating that a reboot is required. Userland patches become active immediately.
List installed patches:
$ doas syspatch -l
002_smtpd
003_vmd
System Upgrade Between Major Releases
OpenBSD provides several methods for major release upgrades (7.8 → 7.9). The appropriate method depends on the desired balance between automation and control.
Automatic Upgrade with sysupgrade
The simplest method for upgrading the system:
$ doas sysupgrade
sysupgrade downloads all installation sets for the new release, verifies their signatures, and installs them automatically. The system reboots several times during the process, which completes unattended.
After the reboot, continue with After the Upgrade.
Important: sysupgrade installs all installation sets automatically, regardless of the original installation. A minimally installed server will therefore also receive the X11 sets (approximately 85 MB) and Games (approximately 2.7 MB).
For minimal server installations, the Interactive Upgrade is the better choice.
Interactive Upgrade with Set Selection
The Interactive Upgrade allows individual installation sets to be selected and is well suited for minimal server installations without X11 or additional components.
Preparation
1. Download the installer kernel and signature file:
The files are available from the OpenBSD mirrors. For amd64 systems:
$ cd /tmp
$ ftp https://cdn.openbsd.org/pub/OpenBSD/7.9/amd64/bsd.rd
$ ftp https://cdn.openbsd.org/pub/OpenBSD/7.9/amd64/SHA256.sig
For other architectures, select the appropriate platform (arm64, i386, etc.). The complete list of supported architectures is available at:
https://cdn.openbsd.org/pub/OpenBSD/7.9/
2. Verify bsd.rd:
The signature key for OpenBSD 7.9 is already included in the running system:
$ cd /tmp
$ signify -C -p /etc/signify/openbsd-79-base.pub -x SHA256.sig bsd.rd
Signature Verified
bsd.rd: OK
Continue only if verification succeeds. A failed verification indicates corrupted or modified files.
3. Copy the installer kernel into the root filesystem:
$ doas cp /tmp/bsd.rd /bsd.rd
Performing the Upgrade
Reboot the system and load the installer kernel from the boot prompt:
boot> boot /bsd.rd
The OpenBSD installer starts and asks which action should be performed. Select (U)pgrade to perform a system upgrade.
Selecting Installation Sets
The installer now proceeds through the familiar steps—keyboard layout, root disk, mirror selection, and so on. The workflow matches the installation process described in Installation and First Steps. The relevant step is the installation set selection:
Select sets by entering a set name, a file name pattern or 'all'.
De-select sets by prepending a '-', e.g.: '-game*'. Selected sets are
labelled '[X]'.
[X] bsd [X] base79.tgz [X] game79.tgz [X] xfont79.tgz
[X] bsd.mp [X] comp79.tgz [X] xbase79.tgz [X] xserv79.tgz
[X] bsd.rd [X] man79.tgz [X] xshare79.tgz
Set name(s)? (or 'abort' or 'done') [done]
[X] marks installation sets that will be installed, while [ ] marks sets that will be skipped.
For minimal server installations, deselect X11 and Games:
Set name(s)? -g* -x*
The selected sets change from [X] to [ ]. Confirm with done and the upgrade begins.
The installer downloads only the selected sets, verifies their signatures, and installs them. This saves approximately 115 MB of disk space while reducing the attack surface on server systems.
After the Upgrade
The system boots automatically into the new release. After logging in for the first time:
1. Merge configuration files:
$ doas sysmerge
sysmerge compares existing system configuration files with the new default versions and offers merge options for modified files.
2. Install binary patches:
$ doas syspatch
This installs all available security patches for the new release.
3. Update third-party packages:
$ doas pkg_add -u
quirks-7.147->7.194: ok
curl-8.16.0->8.20.0: ok
curl-8.20.0:ngtcp2-1.16.0->1.22.1: ok
python-3.12.11->3.13.13 forward dependencies:
| Dependency of py3-packaging-25.0 on python->=3.12,<3.13 doesn't match
| Dependency of glib2-2.84.4 on python->=3.12,<3.13 doesn't match
Merging py3-packaging-25.0->26.0 (ok)
Merging glib2-2.84.4->2.86.5 (ok)
[... additional updates ...]
vim-9.1.1706-no_x11->9.2.357: ok
Running tags: ok
The base system and packages are release-specific. After a major release upgrade, all installed packages must therefore be updated to the matching release.
4. Remove obsolete package versions:
Old package files may remain under /usr/local after updates:
$ doas pkg_delete -a
.libs-libsodium-1.0.20: ok
.libs-python-3.12.11: ok
This removes orphaned dependencies and obsolete package versions. It frees disk space and reduces confusion during manual maintenance.
Manual Upgrade
For maximum control and more complex scenarios, OpenBSD also provides a manual upgrade method. It allows installation sets to be selected without booting bsd.rd and is suitable for remote systems or other specialized requirements.
A complete walkthrough is provided in the separate article Manual System Upgrade (planned).
Method comparison:
- sysupgrade: Simplest method; installs all installation sets automatically.
- Interactive Upgrade: Allows installation set selection; ideal for minimal servers.
- Manual Upgrade: Maximum control; more complex (covered in a separate article).
For production servers without X11, the Interactive Upgrade is the recommended approach.
Information Used
This guide is based on:
- OpenBSD: 7.8, 7.9
- Architecture: amd64 (primary); the general concepts apply to all supported platforms
- Context: Server and desktop installations
- Status: June 2026
OpenBSD’s package management system provides flexible software installation and maintenance. The next article covers the Security Architecture—pledge, unveil, and the fundamental security features of the operating system.