Introduction
A few days ago I installed FreeBSD on my laptop with an encrypted ZFS root and a minimal X11 setup. I documented every step and then re-did the installation to ensure my setup was reproducible. This article is an edited version of my installation notes, which I hope is useful to you.
The Hardware
My laptop is an ASUS K501. It has an NVIDIA GPU but in this guide I’ll focus on the Intel integrated graphics.
Pre-Installation
The zeroth step: the target computer must have UEFI enabled, and the laptop plugged it to ethernet so you don’t have to deal with Wi-Fi at installation time.
Getting FreeBSD
-
Download the
memstick
image file.curl -o memstick.img \ "https://download.freebsd.org/ftp/releases/amd64/amd64/ISO-IMAGES/11.2/FreeBSD-11.2-RELEASE-amd64-memstick.img"
-
Verify. As of 17 August 2018 the SHA256 hash of the mini-memstick image is:
4b90f19c9f08cc7a2db39072e43967d90f3bf057125aa16b8c9d7c3ea8d23b39
Run
sha256sum memstick.img
to compare this with the file’s actual hash.
Copying the Image to a USB Drive
-
Run
fdisk -l
to find your USB drive’s device identifier. In my case it’s/dev/sdb
. -
Copy the
memstick.img
file to the USB drive using this command:sudo dd if=memstick.img of=/dev/<your USB device id> conv=sync
Installation
First Steps
-
Press 1 to select boot multi user, wait for the blue screen to come up.
-
Choose
Install
. -
Choose your keymap.
-
Enter a meaningful hostname.
-
You will be prompted for system components to install, I just choose the default.
-
Network install. On my hardware it autodetected everything.
-
Say yes to using IPv4 and DHCP, wait for DHCP lease.
-
Say yes to IPv6 and SLAAC, wait for router solicitation.
-
Set DNS to Google’s
- IPv6:
2001:4860:4860::8888
2001:4860:4860::8844
- IPv4:
8.8.8.8
8.8.4.4
Or whichever you want to use.
- IPv6:
-
Choose the mirror to download packages from.
Full Disk Encryption Setup
This part of the guide is straight from this howto.
Partitioning
-
At the partitioning screen, select
Shell
, the option to partition by hand. -
Destroy existing partitions:
gpart destroy -F /dev/ada0
-
Create the partition table:
gpart create -s GPT /dev/ada0
-
Create the EFI partition:
gpart add -t efi -s 100M -a 1M -l EFI /dev/ada0
-
Create a swap partition:
gpart add -t freebsd-swap -s 4G -a 1M -l FreeBSD-swap /dev/ada0
-
Create the boot partition
gpart add -t freebsd-ufs -s 10G -a 1M -l FreeBSD-ufsboot /dev/ada0
-
Create the encrypted partition
gpart add -t freebsd-zfs -a 1M -l FreeBSD-enczroot /dev/ada0
-
Configure the EFI partition:
newfs_msdos -F 16 -L FreeBSD_EFI /dev/ada0p1 mkdir /tmp/efi mount -t msdosfs /dev/ada0p1 /tmp/efi mkdir -p /tmp/efi/EFI/BOOT cp /boot/boot1.efi /tmp/efi/EFI/BOOT/BOOTX64.EFI umount /dev/ada0p1
-
Configure the UFS boot partition:
newfs -L ufsboot -S 4096 /dev/ada0p3 mkdir /tmp/ufsboot mount /dev/ada0p3 /tmp/ufsboot
(Note: we went from ada0p1
to ada0p3
because we dont need to do anything
with swap.)
Configuring Encryption
-
Configuring GELI:
kldload aesni mkdir -p /tmp/ufsboot/boot/geli dd if=/dev/random of=/tmp/ufsboot/boot/geli/ada0p4.key bs=64 count=1 geli init -e AES-XTS -l 128 -s 4096 -b -K /tmp/ufsboot/boot/geli/ada0p4.key /dev/ada0p4
This will prompt you for the disk encryption password. Choose carefully.
-
Then, run:
cp /var/backups/ada0p4.eli /tmp/ufsboot/boot/geli/ geli attach -k /tmp/ufsboot/boot/geli/ada0p4.key /dev/ada0p4
This will ask you to enter the password you entered above.
-
Very important final step:
geli configure -b /dev/ada0p4.eli
Configuring ZFS:
-
Create the pool:
zpool create -R /mnt \ -O canmount=off -O mountpoint=none -O atime=off -O compression=on \ zroot /dev/ada0p4.eli
The values of the properties are described here. Briefly, turning
atime
off reduces disk traffic because the filesystem is not updating access time metadata every time the file is accessed. Settingcompression
toon
turns on compression. -
Create the boot container:
zfs create -o canmount=off -o mountpoint=none zroot/ROOT
-
The default boot environment:
zfs create -o mountpoint=/ zroot/ROOT/master
-
Some more things:
zfs create -o mountpoint=/usr/jails zroot/ROOT/master/jails zfs create -o mountpoint=/usr/local zroot/ROOT/master/local zfs create -o mountpoint=/usr/ports zroot/ROOT/master/ports zfs create -o mountpoint=/var zroot/ROOT/master/var zfs create -o mountpoint=/var/log zroot/ROOT/master/log
And:
zfs create -o mountpoint=/usr/home zroot/home zfs create -o mountpoint=/usr/obj zroot/obj zfs create -o mountpoint=/usr/ports/distfiles zroot/distfiles zfs create -o mountpoint=/usr/src zroot/src101 zfs create -o mountpoint=/tmp zroot/tmp zfs create -o mountpoint=/var/tmp zroot/vartmp
Why the 101? I’m not sure. I copied that straight from the guide.
-
Finish up:
mkdir /mnt/ufsboot umount /dev/ada0p3 mount /dev/ada0p3 /mnt/ufsboot cd /mnt ln -s ufsboot/boot boot cd /
-
Edit
fstab
. Run:vi /tmp/bsdinstall_etc/fstab
And write this:
# Device Mountpoint FStype Options Dump Pass# /dev/ada0p2.eli none swap sw,ealgo=AES-XTS,keylen=128,sectorsize=4096 0 0 /dev/ada0p3 /ufsboot ufs rw 1 1
-
Return to the installer by running
exit
.
Since this is a net installation it will start downloading the rest of the packages it needs
Installation Continued
-
Enter the root password.
-
Set the time.
-
Select your region.
-
Select startup services. I add
ntpd
andpowerd
. -
Security options. Choose all of them.
-
Add new users to the system. When prompted, make your user a part of the
wheel
group. Otherwise, the interactive program for adding users is fairly self-explanatory. -
At this stage installation is complete, but we have to write some more ZFS-related configuration. Select the option to exit the installation, you’ll be prompted whether or not you want to open a shell to make any post-installation changes. Choose
Yes
.
Final Configuration
-
Configure the
/boot/loader.conf
file so load your geli services:vi /boot/loader.conf
Its contents should be:
zfs_load="YES" aesni_load="YES" geom_eli_load="YES" geli_ada0p4_keyfile0_load="YES" geli_ada0p4_keyfile0_type="ada0p4:geli_keyfile0" geli_ada0p4_keyfile0_name="/boot/geli/ada0p4.key" vfs.root.mountfrom="zfs:zroot/ROOT/master" # Boot prompt delay autoboot_delay="3" # enable temperature sensors coretemp_load="YES" # enable AHCI on modern hardware for better performance ahci_load="YES" # enable asynchronous I/O (big performance gains with NGINX) aio_load="YES" # in-memory file system tmpfs_load="YES" # load PF firewall and the Intel ethernet driver early at boot time pf_load="YES" pflog_load="YES" if_igb_load="YES"
-
Update
/etc/rc.conf
to enable ZFS:vi /etc/rc.conf
At the end add the line:
zfs_enable="YES"
-
Finally, reboot. You have a working FreeBSD system.
Post-Installation
Log in as root.
UTF-8 Everywhere
-
Edit
/etc/profile
and add this at the end:LANG=en_US.UTF-8; export LANG CHARSET=UTF-8; export CHARSET
-
Edit
/etc/login.conf
, and at the bottom of the default login class,default:\
, change the last line to::umask=022:\ :charset=UTF-8:\ :lang=en_US.UTF-8:
-
Rebuild the DB:
cap_mkdb /etc/login.conf
Setting up pkg
-
Run
/usr/sbin/pkg
, say yes, and wait for it to install the newpkg
. -
Run
pkg2ng
to upgrade the package database. -
Finally, run
pkg update
.
Setting up Ports
Run:
portsnap fetch
portsnap extract
portsnap fetch update
X11
-
Install the required packages:
pkg install xorg-server xf86-input-mouse xf86-input-keyboard xinit xauth xterm twm xorg-fonts
-
Download kernel sources:
cd / fetch ftp://ftp.freebsd.org/pub/FreeBSD/releases/amd64/11.2-RELEASE/src.txz tar -C / -xzvf src.txz rm src.txz
-
Set up
drm-next-kmod
.cd /usr/ports/graphics/drm-next-kmod/ make install clean
You will be prompted for options. Leave them as-is. After the installation is complete, run
pkg info -D drm-next-kmod
To view the installation information.
-
Edit
/etc/rc.conf
, add this to the end:kld_list="/boot/modules/i915kms.ko"
-
Add your user to the
video
group:pw groupmod video -m <YOUR USER NAME>
-
Edit
~/.xinitrc
and write:exec twm
Reboot. If this works, the screen will flash after entering your passphrase as the console switches drivers.
Login as your user, not as root, and run
startx
. This should work, and by work I mean show you a completely black background and no cursor. On my setup the touchpad doesn’t work, so plug it an external mouse and left-click anywhere on the screen to bring up thetwm
menu. This will confirm thattwm
is working.
Web Browser Setup
-
Run
pkg install firefox
. This will take a while. -
Run
dbus-uuidgen > /var/lib/dbus/machine-id
to fix something. -
Exit root and run
firefox
as your user.
File Manager Setup
-
As root, run
pkg install pcmanfm
-
Exit root and run
pcmanfm
as your user to test it.
Improving Battery Life
This part of the guide comes from this guide.
-
First, to view battery status, use
$ acpiconf -i 0
-
Add the following lines to
/etc/rc.conf
:powerd_enable="YES" powerd_flags="-a hiadaptive -b adaptive" performance_cx_lowest="Cmax" economy_cx_lowest="Cmax" ifconfig_wlan0="WPA DHCP powersave"
(You might already have
powerd_enable="YES"
from the installation step.) -
Add the following to
/boot/loader.conf
:hw.pci.do_power_nodriver="3" hw.snd.latency="7" hint.p4tcc.0.disabled="1" hint.acpi_throttle.0.disabled="1" hint.ahcich.0.pm_level="5" hint.ahcich.1.pm_level="5" hint.ahcich.2.pm_level="5" hint.ahcich.3.pm_level="5" hint.ahcich.4.pm_level="5" hint.ahcich.5.pm_level="5" # for intel cards only drm.i915.enable_rc6="7" drm.i915.semaphores="1" drm.i915.intel_iommu_enabled="1"
-
Reboot to make sure everything is fine
sudo
-
From root, run:
pkg install sudo
This will create a sudoers file on
/usr/local/etc/sudoers
. -
If you want to set up passwordless sudo for your user, run
visudo
to open the sudoers file, and add:Add:<your username here> ALL=(ALL) NOPASSWD: ALL
at the end. Save and quit, and try
sudo su
on a new terminal to make sure it works.
Emacs
Installing Emacs from binary packages is thankfully simple:
sudo pkg install emacs
Afterwards run emacs
to ensure everything works.
Depending on your Emacs setup, you might have to install some packages for your configuration to work. For example, I use Inconsolata as the Emacs font, so I had to run:
sudo pkg install inconsolata-ttf
Sound
-
Edit
/boot/loader.conf
and add this line:snd_hda_load="YES"
-
Edit
/etc/rc.conf
and add this line:sndiod_enable="YES"
-
Open
/dev/sndstat
to view your sound devices. In my case:$ cat /dev/sndstat Installed devices: pcm0: <Conexant CX20751/2 (Analog)> (play/rec) default pcm1: <Conexant CX20751/2 (Right Analog)> (play/rec)
-
The
pcm*
devices above are your audio outputs. By default on my laptop, sound comes out on the speaker (pcm0
above). To change to the headphone jack (pcm1
), I run:sysctl hw.snd.default_unit=1
Any program using sound needs to be restarted for the change to take effect. Alternatively, I can set this in
/etc/sysctl.conf
:hw.snd.default_unit=1
Replace
1
with the ID of the PCM device you wish to use by default. -
You can check the settings of your audio devices using the
mixer
command:$ mixer Mixer vol is currently set to 86:86 Mixer pcm is currently set to 100:100 Mixer mic is currently set to 56:56 Mixer rec is currently set to 93:93 Recording source: mic
And change the volume like so:
$ mixer -s vol 50 Setting the mixer vol from 86:86 to 50:50. $ mixer -s vol 80 Setting the mixer vol from 50:50 to 80:80. $ mixer -s vol 100 Setting the mixer vol from 80:80 to 100:100.
Miscellaneous
Ruby
I manage my Ruby environment using rbenv to manage different versions of Ruby, and the rbenv plugin ruby-build to install them.
sudo pkg install rbenv ruby-build
To see a list of available rubies:
rbenv install --list
Let’s install a recent version of Ruby:
rbenv install 2.5.1
rbenv global 2.5.1
The Ruby install comes with RubyGems, so let’s install the Jekyll gem:
rbenv exec gem install jekyll
Once it’s installed, you can execute it using rbenv exec
, for example, I build
this site using:
rbenv exec jekyll serve --watch --future
Mounting USB Drives
If you have a USB drive you mount from time to time (say, for backups), you can set up a mount directory for it:
$ sudo mkdir /mnt/$USER
$ sudo chown $USER:$USER /mnt/$USER
Then, when the drive is detected:
$ sudo mount -t msdosfs -o -m=644,-M=755 /dev/da0s1 /mnt/$USER
$ # do what you need
$ umount /mnt/$USER
Replace /dev/da0s1
with the path to your device.
The Lisp Keyboard
I use xcape
to override the shift keys so when they are used without
a modifying key they insert a parenthesis. Left shift inserts an open
parenthesis and right shift inserts a close parenthesis. Once I got used to this
I couldn’t live without it. In Linux I use this in my .xsession
:
xcape -e "Shift_L=parenleft;Shift_R=parenright"
In FreeBSD this doesn’t work. More precisely, left shift inserts a 9 and right shift inserts a 0. Others have had this issue. Fortunately, a comment in that issue provides the solution:
xcape -e Shift_L='Shift_L|9'
xcape -e Shift_R='Shift_R|0'
Neofetch
$ sudo pkg install neofetch
Without further ado:
Acknowledgements
The following guides were crucial in writing this article: