NetBSD Installation with Disk Encryption ☯ Daniel Wayne Armstrong

13 min read Original article ↗

Last edited on 2026-04-12 Tagged under  #netbsd   #bsd   #encrypt 

The first time I installed NetBSD I used sysinst(8), a menu-based program launched at boot that runs in the console. It has a clear and concise layout and I was quickly up-and-running on my new BSD system.

For my next install I wanted to include disk encryption to protect personal data in case the device is lost or stolen. Its not really enough to simply encrypt home directories. Passphrases and sensitive data can linger and be extracted from locations such as system logs and swap memory. There is a trade-off to be made between how much to encrypt, the convenience of operating the system, and the ability for the system to boot.



1. Start Here

Throughout this HOWTO, if you see square brackets [] in code blocks, that means the word of code (square brackets included) should be replaced with something else. This is detailed in the instructions before or after the code block.

NetBSD will be installed as the sole operating system on a single disk using a four-partition layout:

  • Partition ESP is the EFI system partition.
  • Partition root hosts a minimal root filesystem that boots to an encryption passphrase prompt, which upon entry unlocks…
  • … the encrypted device on partition syscgd containing the contents of var, usr, and home.
  • Partition swap is swap memory auto-encrypted at boot using a random key.

A few assumptions:

  • Target device is amd64 architecture using UEFI to boot.
  • Secure boot is disabled on target device.
  • Network access during install uses a wired interface.

Sysinst does not provide the option for encrypting the system in this manner, so early in the install process I switch to the console and proceed to manually install NetBSD.

Acquire an installation image

The latest official installation images (as of April 2026) are available here: Images and torrents

Download the NetBSD-11.0_RC3-amd64-install.img.gz image and the SHA512 file for verification:

wget https://cdn.netbsd.org/pub/NetBSD/images/11.0_RC3/NetBSD-11.0_RC3-amd64-install.img.gz
wget https://cdn.netbsd.org/pub/NetBSD/images/11.0_RC3/SHA512

Verify the image using sha512sum:

sha512sum -c --ignore-missing SHA512 

Decompress the image:

gunzip NetBSD-11.0_RC3-amd64-install.img.gz

Prepare the USB installation medium

Write the installer to an unmounted USB storage device running the dd(1) command as root.

WARNING
Be very careful to note the proper device (which can be identified with lsblk). All contents on the device will be lost!

Example: On a Linux system, if a USB stick appears as sdx1, then write the installer to sdx (omit partition number):

dd bs=4M conv=fsync oflag=direct status=progress if=NetBSD-11.0_RC3-amd64-install.img of=/dev/sdx

2. Configure the Live Environment

Boot the target device from the NetBSD installation medium. Select Option 1 (default) to Install NetBSD.

After the installer has successfully booted into the NetBSD kernel, a prompt appears to select which language will be used for installation messages, followed by a prompt to select a different keyboard type if desired or leave unchanged.

Next up the menu-based sysinst program is launched:

NetBSD-11.0_RC3 Install System

>a: Install NetBSD to hard disk
 b: Upgrade NetBSD on a hard disk
 c: Re-install sets or install additional sets
 d: Reboot the computer
 e: Utility menu
 f: Config menu
 x: Exit Install System

Connect to the internet

At the Install System main menu, select >e: Utility menu then >c: Configure network.

Available interfaces lists the network interfaces detected by the NetBSD installer.

Example: With my target device Available interfaces lists two: wm0 (wired) and iwn0 (wireless). I choose to configure the wired ethernet interface:

Network media (empty to autoconfigure) [autoselect]: <enter>
Perform autoconfiguration?
>a: Yes
Your host name: foobox
Your DNS domain: home.arpa
The following are the values you entered.

[...]

Are they OK?
>a: Yes

Remote login to the installer

Make this manual installation process easier (i.e. cut-n-paste commands) by remotely logging into the installer via ssh from another computer.

Open a shell by selecting >a: Run /bin/sh from the Utilities menu.

Set a password for root:

passwd

Open the sshd_config file for editing using the vi editor:

vi /etc/ssh/sshd_config

Set permission to allow root to login:

PermitRootLogin yes

Save changes and exit.

Start the sshd daemon:

/etc/rc.d/sshd onestart

Retrieve the IP address for the active interface configured earlier (example: wm0):

ifconfig wm0

Switch to the other computer and ssh into the target device:

ssh root@[ip_address]

… where [ip_address] is the target device’s address obtained with the ifconfig command above.

3. Prepare the DISK

NOTE
For the purposes of this HOWTO, the example target device has a single NVMe disk with an existing install of Linux that will be erased and replaced by NetBSD. Device IDs and storage sizes will vary between devices.

Identify disks and partitions

Discover what disk devices and partitions have been recognized by the kernel:

# sysctl hw.disknames
hw.disknames = ld0 dk0 dk1 dk2 dk3 sd0 dk4 dk5

NVMe devices show up as ld and hard disks are identified by wd. USB devices usually show up as sd.

The dk devices are partitions (know as wedges in NetBSD parlance) on the storage devices, and this early after boot are usually displayed in order, that is: dk0 through dk3 are wedges on the NVMe target device ld0, and dk4 and dk5 on the USB installer sd0.

Verify by asking for a list of wedges on sd0:

# dkctl sd0 listwedges
/dev/rsd0: 2 wedges:
dk4: EFI system, 262144 blocks at 2048, type: msdos
dk5: 30c4cc4e-5369-449c-8994-a4b1ea665b4b, 4853760 blocks at 264192, type: ffs

Verify which device the installer booted from:

# dmesg | fgrep "root on"
[     4.158650] root on dk5

There is also the nvmectl command (use atactl for SATA drives):

# nvmectl identify nvme0 | egrep 'Model|Device type|Capacity'
Model Number:               Samsung SSD 980 1TB

Define DISK variable

The NVMe storage device detected above as ld0 is where NetBSD will be installed. Adjust accordingly for your own storage device:

DISK="ld0"

Wipe DISK

Wipe existing file systems and partition table on DISK:

gpt destroy $DISK && gpt show $DISK

Partition DISK

NOTE
I typically set the swap partition size equal to the amount of physical RAM to a maximum 16g.

Create a GPT partition table on DISK with the following layout:

NumberSizeTypeUse as
1550mefiESP partition
26gffsRoot partition
316gswapEncrypted swap partition
4->ENDcgdEncrypted system partition

Create a new GPT partition table:

gpt create -f $DISK

Create the wedges:

gpt add -l "ESP" -t efi -s 550m $DISK
gpt add -l "root" -t ffs -s 6g $DISK
gpt add -l "swap" -t swap -s 16g $DISK
gpt add -l "syscgd" -t cgd $DISK
gpt show $DISK

Define wedge variables

List wedges:

# dkctl $DISK listwedges
/dev/rld0: 4 wedges:
dk2: ESP, 524288 blocks at 34, type: msdos
dk3: root, 16777216 blocks at 524322, type: ffs
dk4: swap, 33554432 blocks at 17301538, type: swap
dk5: syscgd, 1902669165 blocks at 50855970, type: cgd

NOTE
Your dk[number] numbering may differ from above. Adjust accordingly:

Define variables:

DK_ESP="dk2"
DK_ROOT="dk3"

Format and mount the ESP wedge

newfs_msdos /dev/r${DK_ESP} && mount /dev/${DK_ESP} /mnt

Add EFI boot entries to ESP

mkdir -p /mnt/EFI/boot && cp -v /usr/mdec/*.efi /mnt/EFI/boot

Unmount wedge:

umount /mnt

Format and mount the root wedge

Format and mount the root wedge with the FFSv2 file system with support for extended attributes and access control lists:

newfs -O 2ea /dev/r${DK_ROOT} && mount /dev/${DK_ROOT} /targetroot

4. Disk Encryption

NetBSD uses the cryptographic device driver (CGD) to create and manage encrypted devices.

Create encrypted device

Using cgdconfig, a parameters file is generated that stores the encryption type, key length, and a random password salt for the new encrypted device.

There are a few different encryption ciphers supported. I choose aes-xts with a 512-bit key:

mkdir -p /targetroot/etc/cgd && chmod 700 /targetroot/etc/cgd
cgdconfig -g -V disklabel -o /targetroot/etc/cgd/syscgd aes-xts 512

NOTE
NAME=syscgd is the label for the CGD wedge created earlier.

Create the encrypted device and assign it a passphrase. This passphrase will be used to open the CGD device at boot:

cgdconfig -V re-enter cgd0 NAME=syscgd /targetroot/etc/cgd/syscgd

Create disklabels

NOTE
Disklabels c and d have special meaning in NetBSD and should not be used.

Within the encrypted device, three disklabels are created:

DisklabelMountpointSize
cgd0a/var8GB
cgd0b/usr48GB
cgd0e/home->END

Create the labels using disklabel in interactive mode:

# disklabel -Ii cgd0
Enter '?' for help
...

Create cgd0a:

partition>a
Filesystem type [4.2BSD]: <enter>
Start offset ('x' to start after partition 'x') [0c, 0s, 0M]: <enter>
Partition size ('$' for all remaining) [947594c, 1940672512s, 947594M]: 8G
  a: ...

Create cgd0b:

partition>b
Filesystem type [unused]: 4.2BSD
Start offset ('x' to start after partition 'x') [0c, 0s, 0M]: a
Partition size ('$' for all remaining) [0c, 0s, 0M]: 48G    
  b: ...

Create cgd0e:

partition>e
Filesystem type [unused]: 4.2BSD
Start offset ('x' to start after partition 'x') [0c, 0s, 0M]: b
Partition size ('$' for all remaining) [0c, 0s, 0M]: $
 e: ...

Write the label and quit:

partition>W
Label disk [n]?y
Label written
partition>Q

Verify encrypted device

Set configuration in target device:

echo 'cgd0 NAME=syscgd /etc/cgd/syscgd' > /targetroot/etc/cgd/cgd.conf

Close the CGD device:

cgdconfig -u cgd0

Unlock the CGD device again with the passphrase set earlier:

cgdconfig cgd0 NAME=syscgd /targetroot/etc/cgd/syscgd

The cgd0 drive should now be open and the disklabel visible:

disklabel cgd0

Format and mount disklabels

Format:

newfs -O 2ea cgd0a
newfs -O 2ea cgd0b
newfs -O 2ea cgd0e

Mount:

mkdir /targetroot/var /targetroot/usr /targetroot/home
mount /dev/cgd0a /targetroot/var
mount /dev/cgd0b /targetroot/usr
mount /dev/cgd0e /targetroot/home

5. Installation

The new system is composed of sets (collections of packages) installed to the target device. These sets are located in /amd64/binary/sets. Move into that directory:

cd /amd64/binary/sets && ls

NOTE
Adding flag p to the tar command is important. It ensures that all files preserve their owners and mode.

At a minimum, you must select a kernel and the base and etc sets. Below are the sets I choose to install for a desktop setup:

# for set in base comp etc games gpufw kern-GENERIC man misc modules rescue tests text xbase xcomp xetc xfont xserver; do
> tar -xvzpf $set.tar.xz -C /targetroot
> done

6. Configure the System

Chroot into the freshly installed NetBSD and configure the new OS.

Chroot

chroot /targetroot

Directories

Create the kern and proc directories:

mkdir kern proc

Devices

cd dev
sh MAKEDEV all

On a previous install, after rebooting the boot process halted with the error message:

/etc/defaults/rc.conf: cannot create /dev/null: read-only file system
/etc/rc: cannot create /dev/null: read-only file system

MAKEDEV had created null but it was incorrectly configured:

# ls -l /dev/null
-rw-r--r--  1 root  wheel  0 Apr  5 13:06 null

To avoid this error, remove the existing null:

rm /dev/null

Re-create null with mknod:

# mknod -m 0666 -u root -g wheel /dev/null c 2 2 && ls -l /dev/null
crw-rw-rw-  1 root  wheel  2, 2 Apr 11 13:10 /dev/null

Root password

passwd

Superuser

Create a user account assigned to the wheel and operator groups:

useradd -G [groups] -m [username]

Example: Create an account for user foo and assign a password:

useradd -G wheel,operator -m foo
passwd foo
userinfo foo

Fstab

# cat > /etc/fstab << EOF
NAME=root         /         ffs     rw,log,noatime  	1 1
NAME=swap         none      swap    sw,dp   		0 0
tmpfs             /tmp      tmpfs   rw,-m1777,-sram%25
kernfs            /kern     kernfs  rw
ptyfs             /dev/pts  ptyfs   rw
procfs            /proc     procfs  rw
tmpfs             /var/shm  tmpfs   rw,-m1777,-sram%25
/dev/cgd0a        /var      ffs     rw,log,noatime      1 2
/dev/cgd0b        /usr      ffs     rw,log,noatime      1 2
/dev/cgd0e        /home     ffs     rw,log,noatime      1 2 
EOF

Startup

Open rc.conf for editing:

vi /etc/rc.conf

NOTE
In this HOWTO, my hostname was earlier set to foobox.home.arpa during network setup, and my wired interface is wm0. Adjust accordingly:

# If this is not set to YES, the system will drop into single-user mode.
#
rc_configured=YES

# Add local overrides below.
#
# Wait for CGD to be unlocked before mounting.
critical_filesystems_local="OPTIONAL:/var OPTIONAL:/usr"
dhcpcd=YES
dhcpcd_flags="-qM wm0"
hostname=foobox.home.arpa
sshd=YES
ntpd=YES
ntpdate=YES
wscons=YES
cgd=YES

Save changes and exit.

NOTE
Any Error: /dev/ttyp0: No such file or directory messages can be safely ignored.

Keyboard

A full list of keyboard mappings and variants can be found in wskbd(4).

Set encoding [type_of_keyboard] in wscons.conf.

Open file for editing:

vi /etc/wscons.conf

Example: I use the non-default colemak keymap:

encoding us.colemak

Save changes and exit.

Timezone

Create a symlink to the appropriate timezone for your localtime:

ln -sf /usr/share/zoneinfo/[region/<city_or_sub-region] /etc/localtime

Example: Set localtime to Canada/Eastern:

ln -sf /usr/share/zoneinfo/Canada/Eastern /etc/localtime && date

Network interface

ifconfig.if(5) contains the configuration details for each network interface.

Example: Create an interface file for the wm0 interface that is assigned an IP address via DHCP:

# cat > /etc/ifconfig.wm0 << EOF
up
media autoselect
EOF

Terminals

Set the status of terminals ttyE1-ttyE3 in ttys from off to on.

Open file for editing:

vi /etc/ttys

This is how it should look:

# name  getty                           type    status          comments
#
console "/usr/libexec/getty Pc"         wsvt25  off secure
constty "/usr/libexec/getty Pc"         wsvt25  on secure
ttyE0   "/usr/libexec/getty Pc"         wsvt25  off secure
ttyE1   "/usr/libexec/getty Pc"         wsvt25  on secure
ttyE2   "/usr/libexec/getty Pc"         wsvt25  on secure
ttyE3   "/usr/libexec/getty Pc"         wsvt25  on secure

Save changes and exit.

7. Finish Up

Exit chroot:

exit
cd /

Unmount:

umount /targetroot/home
umount /targetroot/usr
umount /targetroot/var
umount /targetroot

Close encrypted device:

cgdconfig -u cgd0

Reboot system:

shutdown -r now

NOTE
When prompted for the passphrase to unlock the encrypted device, keymap is us qwerty regardless of keymap that might have been set in wscons.conf.

User is prompted for the passphrase to unlock the encrypted syscgd device. Upon success, boot resumes:

NetBSD/amd64 (foobox.home.arpa) (constty)

login: root
Password:

Welcome to NetBSD!

To shutdown/poweroff the system:

shutdown -p now

8. Resources

Next: NetBSD: After the First Boot (TODO)

You can like, share, or comment on this post on the Fediverse 💬