Building a Free and Minimal Unix System (Part 2)- Artix runit on plain dm-crypt

In Part 1 I argued that a free system starts below the operating system: firmware, boot, and storage. This post moves from foundations to implementation.

The goal here is a minimal Artix Linux system using runit, installed onto a disk encrypted with plain dm-crypt. The default approach uses a single internal disk. An optional variant places /boot on removable media.

Disk unlocking is handled in the initramfs using a small encrypted key file (root.enc) and a custom hook (xmew).

These are the steps I go through when installing on a new machine. When I was implementing this method, I got a few commands wrong and locked myself out of the system or it wouldn’t boot and I had to start again. For some people this would be enough for them to give up, but I persisted as part of my unix learning and now I know MOST of these steps off by heart.

This is not a beginner guide. Several steps below are destructive and irreversible. If you do not understand a command, stop and learn before proceeding.

I have assumed the user is using UEFI boot loader in some commands (mainly the grub commands). If you are on libreboot or legacy boot then the command is slightly different.

I plan to make this into a simple script to automate this process and eliminate the chance of error.


Read this twice

You are about to erase disks, generate key material, and configure a system that offers very little forgiveness if you make a mistake.

Read each section fully before running commands. Confirm device names on your machine. There is no safety net here by design.


Trade-offs and threat model

This setup prioritises:

  1. Control — you understand exactly what boots, and from where.
  2. Simplicity — fewer layers and abstractions.
  3. Disk secrecy at rest — encrypted storage without identifying metadata.

Plain dm-crypt (important)

Plain dm-crypt is a trade-off, not a universal recommendation.

Pros

Cons

If you want convenience, use LUKS. If you accept responsibility in exchange for simplicity, read on.


Assumptions and device layout

Before doing anything destructive, identify the disks:

lsblk -o NAME,SIZE,TYPE,MOUNTPOINTS,MODEL

Option A — single internal disk

Option B — removable /boot

Do not copy/paste device names. Confirm them on your machine.


Step 1 — Networking (wpa_supplicant)

Artix install media typically does not include iwctl. Use wpa_supplicant.

Create configuration

wpa_passphrase "SSID" "PASSWORD" > /etc/wpa_supplicant/wpa_supplicant.conf

Bring interface up and request DHCP

ip link set wlan0 up
wpa_supplicant -B -i wlan0 -c /etc/wpa_supplicant/wpa_supplicant.conf
dhcpcd wlan0

Verify connectivity

ping -c 3 artixlinux.org

Step 2 — Scramble the internal disk

Before partitioning, scramble the disk so unused space does not reveal structure.

One approach is to map the disk with a random key and write zeros through it. The ciphertext becomes random.

This can take a long time. That is the cost of doing it properly.

Create an encrypted partition on the whole disk using dm-crpyt (plain encryption):

cryptsetup open --type plain --key-file /dev/urandom --sector-size 512 /dev/sda to_be_wiped

Now use dd utility to write all zero’s to the entire disk, then close the encrypted partition (erasing it for good.):

dd if=/dev/zero of=/dev/mapper/to_be_wiped bs=1M status=progress
cryptsetup close to_be_wiped

Step 3 — Partitioning

Now you have a completely erased and clean disk. Use fdisk, cfdisk, or gdisk. The exact tool does not matter; the partitioning does.I prefer cfdisk.

Option A — single disk

Create a GPT with:

Format EFI:

mkfs.fat -F32 /dev/sda1

Option B — removable /boot

USB device:

mkfs.fat -F32 /dev/sdb1

Internal disk:


Step 4 — Create key material and open encrypted root

4.1 Create root.key

dd bs=512 count=1 if=/dev/random of=/root/root.key iflag=fullblock

4.2 Open plain dm-crypt mapping

Option A

cryptsetup -c aes-xts-plain64 -d /root/root.key -s 512 open --type plain /dev/sda2 root

Option B

cryptsetup -c aes-xts-plain64 -d /root/root.key -s 512 open --type plain /dev/sda1 root

4.3 Format and mount

mkfs.ext4 /dev/mapper/root
mount /dev/mapper/root /mnt
mkdir -p /mnt/boot

Mount /boot:

# Option A
mount /dev/sda1 /mnt/boot

# Option B
mount /dev/sdb1 /mnt/boot

Step 5 — Encrypt the key file (root.enc)

Encrypt root.key with OpenSSL (PBKDF2):

This will prompt you for the password to the encrypted key file. Make sure it is a strong password or passphrase and that you remember it.

openssl aes-256-cbc -pbkdf2 -e -in /root/root.key -out /root/root.enc

Step 6 — Install Artix base system (runit)

basestrap /mnt \
  base base-devel \
  linux linux-firmware \
  runit elogind-runit \
  cryptsetup \
  grub efibootmgr \
  git vim

Copy only the encrypted key into the installed system:

cp /root/root.enc /mnt/root/

Do not copy /root/root.key into the installed system.

Generate fstab and then chroot into the system

fstabgen -U /mnt >> /mnt/etc/fstab
artix-chroot /mnt

Step 7 — Users and credentials

Set root password

passwd

Create a normal user and add to the wheel group

useradd -m -G wheel -s /bin/bash shaun
passwd shaun

Enable sudo

pacman -S sudo
visudo

Uncomment:

%wheel ALL=(ALL:ALL) ALL

Step 8 — Install xmew initramfs hook

cd /opt
git clone https://github.com/shaunpitchers/xmew.git
cp /opt/lib/initcpio/install/xmew /lib/initcpio/install/
cp /opt/lib/initcpio/hooks/xmew    /lib/initcpio/hooks/
vim /etc/mkinitcpio.conf

Ensure that the xmew and encrypt hooks are placed in exactly this position, and the encrypted root.enc file is in FILES:

FILES=(/root/root.enc)
HOOKS=(base udev autodetect microcode modconf kms keyboard keymap consolefont block xmew encrypt filesystems fsck)
mkinitcpio -P

Step 9 — Install and configure GRUB (EFI)

grub-install --target=x86_64-efi --efi-directory=/boot --bootloader-id=GRUB
vim /etc/default/grub

Add this to the end of the string on the line GRUB_CMDLINE_LINUX_DEFAULT:

"cryptdevice=/dev/disk/by-id/XXXXXXX_XXXX:root cryptkey=rootfs:/root/root.key crypto=:aes-xts-plain64:512:0:"

Mine looks like this:

GRUB_CMDLINE_LINUX_DEFAULT="loglevel=3 quiet cryptdevice=/dev/disk/by-id/nvme-CT1000P310SSD8_25054DDD88EE-part2:root cryptkey=rootfs:/root/root.key crypto=:aes-xts-plain64:512:0:"
grub-mkconfig -o /boot/grub/grub.cfg

Step 10 — Reboot

exit
umount /mnt/boot
umount /mnt
cryptsetup close root
reboot

What comes next

Part 3 will cover the system and network hardening, and backups for a secure system.