Just Enough Chimera Linux ☯ Daniel Wayne Armstrong

12 min read Original article ↗

Last edited on 2026-04-16 Tagged under  #chimera   #linux   #zfs   #encrypt   #zfsbootmenu 

Chimera Linux is a delightful community-driven Linux distribution built from scratch that does things differently: musl instead of the typical glibc for C library, dinit over systemd for system init, and a userland derived from FreeBSD core tools.

Using the Chimera base install image and working my way through this excellent installation guide for configuring Chimera with the OpenZFS filesystem and the ZFSBootMenu bootloader, I show the choices I make to create an encrypted, minimal Linux system with “just enough” to provide a solid foundation to build upon further: whether that be setting up a desktop, laptop, or server.

ascii kitty

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.

Chimera Linux is installed as the sole operating system on a single disk using a three-partition layout:

  • Partition esp serves as the EFI system partition and is formatted with the fat32 file system.
  • Partition swap provides auto-initialised swap space with encryption at boot courtesy of dm-crypt.
  • Partition pool contains the root filesystem and is formatted with the zfs file system using native encryption.

A few assumptions:

  • Target device is x86_64 architecture using UEFI to boot.
  • Secure boot is disabled on target device.
  • Network access during install uses a wired interface.
  • System does not require hibernation support.

Acquire an installation image

The latest RELEASE as of April, 2026 is 20251220.

The latest live ISO install images are available here: repo.chimera-linux.org

Download chimera-linux-x86_64-LIVE-20251220-base.iso, the sha256sums.txt file, then verify the image integrity:

sha256sum -c --ignore-missing sha256sums.txt

Prepare USB installation medium

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

WARNING
Be very careful to note the proper device (which can be identified with the lsblk command). 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=chimera-linux-x86_64-LIVE-20251220-base.iso of=/dev/sdx

2. Configure the Live Environment

Boot the target device from the Chimera installation media. Login and password is root:chimera.

Set larger console font

If the existing font size appears too small, running:

setfont -d

… will double the size.

Console fonts are located in /usr/share/consolefonts/ and a different font can be set with setfont omitting the path and file extension.

Set temporary console keyboard

Default console keymap is us. Available keymaps are listed in /usr/share/keymaps/.

If some other keymap is desired, set a different keymap temporarily with loadkeys:

loadkeys [keymap]

…where [keymap] is the desired keyboard layout.

Example: I configure the system to use my preferred colemak layout, which is available in /usr/share/keymaps/i386/colemak:

loadkeys colemak/en-latin9

Verify boot mode

Confirm target device is using UEFI boot mode:

cat /sys/firmware/efi/fw_platform_size

If the command returns 64, then system is booted in UEFI with 64-bit x64 UEFI and we are good to go.

NOTE
If the file does not exist, the device is not using UEFI.

Connect to internet

Wired network interfaces should be auto-enabled and connected at boot.

Verify the network interface is active, has been assigned an address, and the internet is reachable:

ip addr
ping -c 5 chimera-linux.org

Remote login to installer

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

Start the sshd daemon:

dinitctl start sshd

Switch to the other computer and ssh into the target device as anon:chimera:

ssh anon@[ip_address]

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

Switch to root:

doas -s

Define ID variable

File /etc/os-release defines variables that describe the current operating system. Use the $ID variable to set the short name of the Linux distribution in later commands:

. /etc/os-release && export ID && echo $ID

Generate hostid

Generate hostid hexadecimal identifier for use by ZFSBootMenu:

zgenhostid "$(hostid)" && hostid

NOTE
Musl doesn’t read /etc/hostid and will always display 00000000. Its not an issue.

3. Prepare the DISK

Set up a custom partition layout on a single disk before implementing the Chimera base installation.

Install:

apk update && apk add --no-interactive gptfdisk parted

Define DISK variables

Identify the disk where Chimera will be installed by listing block devices:

lsblk -f

Set DISK variables for either a SATA or NVMe disk:

SATA

Example disk: sda

export DISK="/dev/sda"
export ESP_PART="1"
export SWAP_PART="2"
export POOL_PART="3"
export ESP_DEVICE="${DISK}${ESP_PART}"
export SWAP_DEVICE="${DISK}${SWAP_PART}"
export POOL_DEVICE="${DISK}${POOL_PART}"
echo $ESP_DEVICE && echo $SWAP_DEVICE && echo $POOL_DEVICE

NVMe

Example disk: nvme0n1

export DISK="/dev/nvme0n1"
export ESP_PART="1"
export SWAP_PART="2"
export POOL_PART="3"
export ESP_DEVICE="${DISK}p${ESP_PART}"
export SWAP_DEVICE="${DISK}p${SWAP_PART}"
export POOL_DEVICE="${DISK}p${POOL_PART}"
echo $ESP_DEVICE && echo $SWAP_DEVICE && echo $POOL_DEVICE

Wipe DISK

If there was previously a ZFS pool on DISK, run:

zpool labelclear -f $DISK

If DISK was previously configured with LVM, bring down the volume group:

vgchange -an

Wipe existing file systems and partition table on DISK:

wipefs -af $DISK && sgdisk --zap-all --clear $DISK

Notify the system of changes to the partition table:

partprobe $DISK

Partition DISK

NOTE
Many partitioning guides assign 256-512M of space to the EFI system partition. I like to future-proof the partition for whatever else Linux might want to store there by assigning a more generous 2G of space.

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

NumberSizeCodeFormatUse asMountpoint
12gef00vfatEFI system partition/boot/efi
28g8200swapSwap partition(not applicable)
3->ENDbf00zfsZFS pool partition/

Create the EFI system partition:

sgdisk -n "${ESP_PART}:1m:+2g" -t "${ESP_PART}:ef00" -c 0:esp $DISK

Create the swap partition:

sgdisk -n "${SWAP_PART}:0:+8g" -t "${SWAP_PART}:8200" -c 0:swap $DISK

Create the ZFS pool partition:

sgdisk -n "${POOL_PART}:0:0" -t "${POOL_PART}:bf00" -c 0:pool $DISK

Display DISK layout:

partprobe $DISK && sgdisk -p $DISK

4. ZFS Pool Creation

When adding disks or partitions to ZFS pools, its good practice to refer to them by the symbolic links created in /dev/disk/by-partuuid (UEFI) so that ZFS will identify the right devices even if disk naming should change at some point. Using traditional device nodes like /dev/sda2 may cause intermittent import failures.

So I create a POOL_ID variable:

POOL_ID=/dev/disk/by-partuuid/$( blkid -s PARTUUID -o value $POOL_DEVICE )

Verify:

ls -al /dev/disk/by-partuuid/ && echo "POOL_ID = $POOL_ID"

Create encryption keyfile

Store the encryption passphrase for the ZFS pool in a keyfile:

echo 'SuperSecretPassphrase' > /etc/zfs/zroot.key
chmod 000 /etc/zfs/zroot.key

Create encrypted ZFS pool

Create the pool with native encryption enabled:

zpool create -f \
 -o ashift=12 \
 -o autotrim=on \
 -o compatibility=openzfs-2.3-linux \
 -O acltype=posixacl \
 -O xattr=sa \
 -O compression=lz4 \
 -O encryption=aes-256-gcm \
 -O keylocation=file:///etc/zfs/zroot.key \
 -O keyformat=passphrase \
 -O relatime=on \
 -m none zroot "$POOL_ID"

Create ZFS datasets

NOTE
It is necessary to explicitly set the canmount=noauto on every boot environment you create.

zfs create -o mountpoint=none zroot/ROOT
zfs create -o mountpoint=/ -o canmount=noauto zroot/ROOT/${ID}

Set the preferred boot file system:

zpool set bootfs=zroot/ROOT/${ID} zroot

I create an additional home dataset for each system:

zfs create zroot/ROOT/${ID}/home

This allows me to keep user config files unique to each boot environment that I might create in the future. It also separates user data from system data, which is useful for ZFS snapshots and enables system rollbacks while leaving user data untouched.

To share data between boot environments, I create a data dataset to store common files:

zfs create -o mountpoint=/data zroot/data

Export and re-import pool for installation

zpool export zroot
zpool import -N -R /mnt zroot
zfs load-key -L prompt zroot

Mount datasets:

zfs mount zroot/ROOT/${ID}
zfs mount zroot/ROOT/${ID}/home
zfs mount zroot/data

Verify:

# mount -t zfs
zroot/ROOT/chimera on /mnt type zfs (rw,relatime,xattr,posixacl,casesensitive)
zroot/ROOT/chimera/home on /mnt/home type zfs (rw,relatime,xattr,posixacl,casesensitive)
root/data on /mnt/data type zfs (rw,relatime,xattr,posixacl,casesensitive)

Update device symlinks:

udevadm trigger

5. Installation

Install the base-full packages:

chimera-bootstrap /mnt

Copy files into the new operating system:

cp /etc/hostid /mnt/etc/
mkdir /mnt/etc/zfs && cp /etc/zfs/zroot.key /mnt/etc/zfs/

6. Configure the New System

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

Enter chroot

chimera-chroot /mnt

Set root password

passwd

Create superuser

Create a user account with superuser privileges:

useradd -m -G wheel [username]

… where [username] is the desired name for the account.

Set a password for [username]:

passwd [username]

(Optional) Give root access to [username] with no password using the doas command:

echo 'permit nopass keepenv [username]' >> /etc/doas.conf

Package manager and extra packages

Add the user subrepo and sync mirrors:

apk add --no-interactive chimera-repo-user && apk update

Identify the processor vendor:

grep vendor_id /proc/cpuinfo

Define a variable for an appropriate microcode package to load updates and security fixes:

UCODE="[vendor]"

… where [vendor] for Intel processors is ucode-intel and AMD processors is ucode-amd.

Install:

apk add --no-interactive $UCODE linux-lts-zfs-bin cryptsetup cryptsetup-scripts-initramfs-tools curl efibootmgr font-terminus

Set console font

NOTE
For terminus font settings, see /usr/share/consolefonts/README.Lat2-Terminus16 for details.

Chimera uses the same console-setup system as Debian.

Example: Use TerminusBold as the console font and increase font size by modifying /etc/default/console-setup:

ACTIVE_CONSOLES="/dev/tty[1-6]"

CHARMAP="UTF-8"

CODESET=guess
FONTFACE=TerminusBold
FONTSIZE=12x24

Set console keyboard

Default keyboard is us. If a keymap alternative is desired, see keyboard(5) for options.

Example: I like to use the colemak keymap (available in /usr/share/keymaps/i386/colemak), which I set by modifying /etc/default/keyboard:

KMAP=colemak/en-latin9

XKBMODEL=pc105
XKBLAYOUT=us

Set timezone

Timezones are located in /usr/share/zoneinfo/[Region]/[City], where [Region] is the geographical region (Africa, America, Europe, …) and the [City] within that region.

Example: Create the /etc/localtime symbolic link to the timezone where Toronto is located:

ln -sf /usr/share/zoneinfo/America/Toronto /etc/localtime && date

Assign hostname

Create the hostname file:

echo [hostname] > /etc/hostname

… where [hostname] is the desired name of the system (single word, no spaces):

echo chimeralinux > /etc/hostname

Enable services

Links to services enabled by the admin are in /etc/dinit.d/boot.d/.

Default logging system on Chimera is syslog-ng.

Enable the service:

dinitctl -o enable syslog-ng

Logs are written to /var/log/messages.

You can configure wired networks statically or dynamically with dhcpcd.

Enable the service:

dinitctl -o enable dhcpcd

Default activity is for dhcpcd to configure all interfaces with DHCP. Changes are made in /etc/dhcpcd.conf. See dhcpcd.conf(5) for more details.

Enable the sshd service to allow remote logins:

dinitctl -o enable sshd

Format and mount ESP partition

NOTE
Labels on file systems are optional, but helpful. They are a more reliable way to identify the correct partition than simple device nodes and allow for easy mounting without a UUID.

Create a fat32 file system:

mkfs.fat -n ESP -F 32 $ESP_DEVICE

Mount device:

mount --mkdir $ESP_DEVICE /boot/efi

Add partition to fstab:

echo 'LABEL=ESP /boot/efi vfat defaults 0 0' >> /etc/fstab

Enable swap encryption

Using raw dm-crypt enables the system to generate a random, one-time encryption key at boot that requires no action from the user to encrypt swap. At shutdown the key is discarded, rendering any remaining data effectively destroyed.

To allow the use of a label (as previously done with the ESP) to identify the swap partition that can survive an overwrite, a swap offset can be used. Create this offset by writing a tiny, empty file system on SWAP_DEVICE whose sole purpose is to provide a persistent label for swap creation:

mkfs.ext2 -L cryptswap $SWAP_DEVICE 1M

Configure dm-crypt to set up swap on this cryptswap partition at boot by adding an entry to crypttab:

echo 'swap LABEL=cryptswap /dev/urandom plain,swap,offset=2048,cipher=aes-xts-plain64,size=512,sector-size=4096' >> /etc/crypttab

Add swap device to fstab:

echo '/dev/mapper/swap none swap defaults 0 0' >> /etc/fstab

Regenerate initramfs

Encryption key is stored in /etc/zfs and will automatically be copied into the initramfs.

Set UMASK=0077 as default permissions for newly created files and directories:

mkdir -p /etc/initramfs-tools/conf.d
echo 'UMASK=0077' > /etc/initramfs-tools/conf.d/umask.conf

… and set RESUME=none to disable the cryptsetup command from checking/warning about the lack of hibernate/resume support in our swap partition:

echo 'RESUME=none' > /etc/initramfs-tools/conf.d/resume

Regenerate:

update-initramfs -u -k all

Any warning messages along the lines of:

cryptsetup: WARNING: Couldn't determine root device

… can be safely ignored. In this instance the script is looking for a root mapping that doesn’t exit (root encryption is handled in ZFS).

Install the ZBM bootloader to support Root-on-ZFS boot environments on Linux.

Boot properties

NOTE
Add the hibernate=no argument to ensure that no process can trigger a suspend-to-disk action, which is consistent with the goal of using a non-persistent, random-key swap.

Assign command-line arguments to be used when booting the kernel:

zfs set org.zfsbootmenu:commandline="quiet hibernate=no" zroot/ROOT

Configure key caching:

zfs set org.zfsbootmenu:keysource="zroot/ROOT/${ID}" zroot

Prebuilt executable

Install a prebuilt ZBM executable to the ESP:

mkdir -p /boot/efi/EFI/ZBM
curl -o /boot/efi/EFI/ZBM/VMLINUZ.EFI -L https://get.zfsbootmenu.org/efi
cp /boot/efi/EFI/ZBM/VMLINUZ.EFI /boot/efi/EFI/ZBM/VMLINUZ-BACKUP.EFI

EFI boot entries

efibootmgr -c -d "$DISK" -p "$ESP_PART" -L "ZFSBootMenu (Backup)" -l '\EFI\ZBM\VMLINUZ-BACKUP.EFI'
efibootmgr -c -d "$DISK" -p "$ESP_PART" -L "ZFSBootMenu" -l '\EFI\ZBM\VMLINUZ.EFI'

8. Finish Up

Exit chroot, unmount, and export

Exit chroot:

exit

Unmount everything:

umount /mnt/home && umount /mnt/data && umount /mnt/boot/efi && umount -n -R /mnt

Export the zpool:

zpool export zroot

Reboot

reboot

NOTE
When prompted for passphrase to unlock zpool, keymap is us regardless of keymap that might have been set on system.

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

chimeralinux login:

Welcome to Chimera!

9. Resources

Next: Chimera Linux: After the First Boot (TODO)

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