Manual NetBSD Installation with Disk Encryption
Tested on NetBSD 10.1
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.

The arrangement outlined below uses an unencrypted EFI system partition (UEFI) plus a minimal root filesystem that boots up to an encryption passphrase prompt, which upon successful entry unlocks an encrypted partition containing var
, usr
, and home
. A separate swap
partition is also created and encryption is automatically enabled at boot using a random key.
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.
This is how I do it...
- 1. Start Here
- 2. Configure Live Environment
- 3. Prepare Disk
- 4. Disk Encryption
- 5. Installation
- 6. Configuration
- 7. Finish Up
- 8. Resources
1. Start Here
Throughout this guide, 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.
This guide makes a few assumptions:
- Target device is amd64 architecture
- System uses UEFI to boot and will use a GPT partition table
- NetBSD will be the sole OS on a single disk
- NetBSD install media will be prepared on a Linux-based system
- Ethernet will be used for network access during install
1.1 Download install image
Download the NetBSD install image and the SHA512
file for verification:
$ wget -c https://cdn.netbsd.org/pub/NetBSD/NetBSD-10.1/images/NetBSD-10.1-amd64-install.img.gz
$ wget https://cdn.netbsd.org/pub/NetBSD/images/10.1/SHA512
Verify the disk image using sha512sum
:
$ sha512sum -c --ignore-missing SHA512
NetBSD-10.1-amd64-install.img.gz: OK
1.2 Prepare USB install media
Plug in a USB stick and identify its device label:
$ lsblk -f
If the USB stick is mounted, unmount the device:
# umount /dev/[device_label]
For example, if the USB stick is mounted as sde1
:
# umount /dev/sde1
Unpack the install image:
# gunzip NetBSD-10.1-amd64-install.img.gz
NOTE
Be very careful to note the proper device. All contents on the device will be lost!
Write the install image to the USB stick using the dd
command:
# dd if=NetBSD-10.1-amd64-install.img of=/dev/[device_label] bs=1M status=progress && sync
Using the previous example of sde1
, this command would replace [device_label]
with sde
(omit the partition number):
# dd if=NetBSD-10.1-amd64-install.img of=/dev/sde bs=1M status=progress && sync
2. Configure Live Environment
Insert the USB install stick into the target device and boot. 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.
Next is a prompt to select a different keyboard type if desired or leave unchanged.
Next up the menu-based sysinst program is launched:
NetBSD-10.1 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
2.1 Configure network
Select >e: Utility menu
then >c: Configure network
.
Available interfaces
lists the network interfaces detected by the NetBSD installer.
EXAMPLE
On my system I have a single (Intel) ethernet interface listed: wm0
Select the ethernet interface for configuration:
- For
Network media type
leave empty and indicateYes
for autoconfiguration - For
host name
for the purposes of this HOWTO I enterbsdbox
- For
DNS domain
enterhome.arpa
Your host name: bsdbox
Your DNS domain [home]: home.arpa
...
Are they OK?
>a: Yes
2.2 Remote login to installer
OPTIONAL
I make this manual install process easier - enable cut-n-paste commands from this HOWTO, access to a web browser to lookup information online - by remotely logging into the installer via ssh(1) from another computer.
Set up ssh
on the target device by selecting >a: Run /bin/sh
from the Utilities
menu.
Create a passwd(1) for root
:
# passwd root
Open sshd_config(5) for editing with vi(1):
# vi /etc/ssh/sshd_config
Set permission to allow root
to login:
PermitRootLogin yes
Save changes and exit.
Start sshd(8):
# /etc/rc.d/sshd onestart
Retrieve IP address for the active interface configured earlier (example: wm0
) with ifconfig(8):
# ifconfig wm0
Switch to the other computer and login to target device via ssh
:
$ ssh root@<target_device_ip_address>
3. Prepare disk
EXAMPLE
For the purposes of this HOWTO, the 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.
3.1 Identify disks and partitions
Discover what disk devices and partitions have been recognized by the kernel using sysctl(8):
# sysctl hw.disknames
hw.disknames = ld0 dk0 dk1 dk2 dk3 sd0 dk4 dk5 sd1
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
using dkctl(8):
# 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
Check which device the installer booted from using dmesg(8):
# dmesg | fgrep "root on"
[ 4.158650] root on dk5
More details about individual disks can be retrieved by extracting parts of the kernel output from the dmesg
output (example: for ld0
):
# dmesg | fgrep ld0
[ 1.045032] ld0 at nvme0 nsid 1
[ 1.045032] ld0: 931 GB, 121601 cyl, 255 head, 63 sec, 512 bytes/sect x 1953525168 sectors
[ 2.178653] ld0: GPT GUID: 2271c564-dd66-4398-b6f3-12bec0c9df07
[ 2.178653] dk0 at ld0: "esp", 614400 blocks at 2048, type: msdos
[ 2.248652] dk1 at ld0: "boot", 2097152 blocks at 616448, type: ext2fs
[ 2.308652] dk2 at ld0: "root", 134217728 blocks at 2713600, type: <unknown>
[ 2.378653] dk3 at ld0: "home", 1816573327 blocks at 136931328, type: <unknown>
There is also the nvmectl(8) command (use atactl(8) for SATA drives):
# nvmectl identify nvme0 | egrep 'Model|Device type|Capacity'
Model Number: Samsung SSD 980 1TB
3.2 Create wedges
EXAMPLE
Swap partition size is set to >= installed RAM size on target device.
For our new encrypted NetBSD install, create a GPT partition table with four wedges:
Size | Format | Use as |
---|---|---|
128MB | msdos | EFI system partition |
6GB | ffs | root partition |
8GB | swap | swap partition |
->END | cgd | encrypted partition |
EXAMPLE
The NVMe storage device detected above as ld0
is where NetBSD will be installed. Adjust accordingly for your own storage device.
Set the mydisk
variable:
# mydisk="ld0"
Create a new GPT partition table with gpt(8):
# gpt destroy $mydisk
# gpt create -f $mydisk
Create the wedges:
# gpt add -l "ESP" -t efi -s 128m $mydisk
# gpt add -l "root" -t ffs -s 6g $mydisk
# gpt add -l "swap" -t swap -s 8g $mydisk
# gpt add -l "syscgd" -t cgd $mydisk
# gpt show $mydisk
List wedges with dkctl(8):
# dkctl $mydisk listwedges
/dev/rld0: 4 wedges:
dk0: ESP, 262144 blocks at 4096, type: msdos
dk1: root, 12582912 blocks at 266240, type: ffs
dk2: swap, 16777216 blocks at 12849152, type: swap
dk3: syscgd, 1923895296 blocks at 29626368, type: cgd
3.3 Format and mount wedges
Format the EFI wedge with newfs_msdos(8) and mount:
# newfs_msdos /dev/rdk0
# mount /dev/dk0 /mnt
Format the root wedge with newfs(8) and mount:
# newfs -O 2 dk1
# mount /dev/dk1 /targetroot
3.4 Add EFI boot entries
# mkdir -p /mnt/EFI/boot
# cp -v /usr/mdec/*.efi /mnt/EFI/boot
/usr/mdec/bootia32.efi -> /mnt/EFI/boot/bootia32.efi
/usr/mdec/bootx64.efi -> /mnt/EFI/boot/bootx64.efi
Unmount the EFI wedge:
# umount /mnt
4. Disk Encryption
NetBSD uses the cryptographic device driver (CGD) to create and manage encrypted devices.
4.1 Create encrypted device
Using cgdconfig(8), a parameters file is generated that stores the encryption type, key length, and a random password salt for the new cgd(4).
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
EXAMPLE
NAME
is the label used (example: syscgd
) when the wedge for CGD was 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
4.2 Create disklabels
NOTE
Disklabel(5) c
and d
have special meaning in NetBSD (addressing the whole disk) and should not be used.
Within the encrypted device, three disklabels are created:
Disklabel | Mountpoint | Size |
---|---|---|
cgd0a | /var | 6GB |
cgd0b | /usr | 48GB |
cgd0e | /home | ->END |
Create the labels using disklabel(8) 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]: 6G
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: ...
If satisfied with the edits, write the label and quit disklabel
:
partition>W
Label disk [n]?y
Label written
partition>Q
4.3 Verify 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
If everything worked, the cgd0
drive is now open and disklabel is visible with disklabel
:
# disklabel cgd0
4.4 Format and mount disklabels
# newfs -O 2 cgd0a
# newfs -O 2 cgd0b
# newfs -O 2 cgd0e
# 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
.
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:
# cd /amd64/binary/sets
# for set in base comp etc games gpufw kern-GENERIC man misc modules tests text xbase xcomp xetc xfont xserver; do
> tar -xvzpf $set.tar.xz -C /targetroot
> done
6. Configuration
Enter chroot
on the target device:
# chroot /targetroot
6.1 Create directories
Create the kern
and proc
directories:
# mkdir kern proc
6.2 Create devices
# cd dev
# sh MAKEDEV all
NOTE
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:
-rw-r--r-- 1 root wheel 0 Apr 15 16:57 null
To avoid this error, remove the existing null
:
# rm /dev/null
Re-create null
with mknod(8):
# mknod -m 0666 -u root -g wheel /dev/null c 2 2
# ls -l null
crw-rw-rw- 1 root wheel 2, 2 Apr 21 17:07 null
6.3 Create fstab
# cat > /etc/fstab << EOF
NAME=root / ffs rw 1 1
NAME=swap none swap sw,dp 0 0
tmpfs /tmp tmpfs rw,-m=1777,-s=ram%25
kernfs /kern kernfs rw
ptyfs /dev/pts ptyfs rw
procfs /proc procfs rw
tmpfs /var/shm tmpfs rw,-m1777,-sram%25
# encrypted file systems
/dev/cgd0a /var ffs rw 1 2
/dev/cgd0b /usr ffs rw 1 2
/dev/cgd0e /home ffs rw 1 2
EOF
6.4 Startup configuration
Open rc.conf(5) for editing:
# vi /etc/rc.conf
EXAMPLE
In this example, my hostname was earlier set to bsdbox.home.arpa
during network setup, and my wired interface is wm0
. Adjust accordingly.
Settings:
# 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=bsdbox.home.arpa
sshd=YES
ntpdate=YES
wscons=YES
cgd=YES
Save changes and exit.
6.5 Set root password
# passwd root
6.6 Set 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
For example, I use the colemak
keymap:
encoding us.colemak
Save changes and exit.
6.7 Set timezone
Create a symlink to the appropriate timezone for your localtime
:
# ln -sf /usr/share/zoneinfo/[region/<city_or_sub-region] /etc/localtime
For example, set localtime
to Canada/Eastern
:
# ln -sf /usr/share/zoneinfo/Canada/Eastern /etc/localtime
6.8 Create network interface
The ifconfig.if(5) contains the configuration details for each network interface.
For example, to 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
6.9 Enable multiple terminals
Set the status of terminals ttyE1-ttyE3
in ttys(5) 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
Unmount:
# cd /
# umount /targetroot/home
# umount /targetroot/usr
# umount /targetroot/var
# umount /targetroot
Close CGD device:
# cgdconfig -u cgd0
Reboot:
# shutdown -r now
NOTE
During boot, when prompted for the encryption passphrase - regardless of the keymap set in wscons.conf
- enter the correct passphrase using the US QWERTY keymap:
NAME=syscgd's passphrase:
Upon success, boot resumes....
NetBSD/amd64 (bsdbox.home.arpa) (constty)
login: root
Password:
Welcome to NetBSD!
8. Resources
- This HOWTO posted by vsis was crucial in getting my own system configured with encryption: NetBSD - UEFI installation with Full Disk Encryption
- Alternative approach for disk encryption using a ramdisk on BIOS boot systems: NetBSD Full-Disk Encryption with CGD (BIOS/GPT)
- NetBSD INSTALL: Installation procedure for NetBSD/amd64
- NetBSD Wiki: Installing NetBSD on a x86 system with UEFI
- NetBSD Guide: Chapter 14. The cryptographic device driver (CGD)
- Suggested tools for inspecting disks: Disk management from Installation ISO
- Skipping sysinst install for a more "hands-on" approach: Manual NetBSD install on GPT/UEFI
- Swap encryption is now automatic using the
vm.swap_encrypt=1
sysctl(8) variable: Announcing NetBSD 10.0
You can like, share, or comment on this post on the Fediverse 💬
» Next: Customize the Login on NetBSD
« Previous: Use SSH keys on NetBSD for Passwordless Logins to Servers