Zillowe FoundationZillowe Documentation

Building a ZoiOS Distro

A guide on how to bootstrap and build a ZoiOS distribution (like Parlex Linux) from scratch using Zoi.

Zoi provides a powerful set of tools to act as a "Universal Distro Engine." This allows you to construct an entire, bootable, declarative operating system (ZoiOS) from a standard Linux environment using the zoi system distro build command.

This guide walks you through bootstrapping a ZoiOS system (e.g. Parlex Linux) onto a new disk, assuming the required base packages are available in your configured Zoi registry.

Prerequisites

  1. A Host Linux System: You need a running Linux environment (like an Ubuntu Live USB or a Fedora host) to perform the initial installation.
  2. Zoi CLI Installed: The host system must have the Zoi CLI installed.
  3. Root Privileges: Formatting disks and installing bootloaders requires sudo.
  4. A Configured Registry: Your Zoi instance must be configured to sync with a registry that provides the essential ZoiOS packages (e.g. @parlex/linux, @parlex/glibc, @parlex/systemd).

Step 1: Prepare the system.lua Configuration

The entire state of a ZoiOS machine is defined in a system.lua file. This file acts as the blueprint for your new distribution.

Create a file named target-system.lua:

-- target-system.lua

system({
    hostname = "my-zoios-machine",
    timezone = "UTC",
    locale = "en_US.UTF-8",
    -- Optional kernel parameters
    kernel_params = "quiet splash rw",
})

-- Essential base packages required for a bootable system
packages({
    "@parlex/base",
    "@parlex/linux",
    "@parlex/glibc",
    "@parlex/systemd",
    "@parlex/bash",
    "@parlex/coreutils",
    "@parlex/filesystem",
    "@parlex/dracut",
    "@parlex/grub",
    "@parlex/shadow",
    "@parlex/sudo",
})

services({
    ["systemd-journald"] = { enable = true },
    ["systemd-networkd"] = { enable = true },
    ["systemd-resolved"] = { enable = true },
})

filesystems({
    {
        device = "LABEL=ZOIOS_ROOT",
        mount = "/",
        type = "ext4",
        options = "noatime",
    },
})

Step 2: Partition and Format the Target Disk

Before Zoi can orchestrate the installation, you must partition and format your target disk manually.

Disclaimer: Replace /dev/sdX with your actual target device. Be extremely careful not to format your host machine's drive!

Example Partitioning (UEFI)

Use a tool like parted or fdisk to create:

  1. EFI Partition (e.g. /dev/sdX1, 512MB, format as vfat)
  2. Root Partition (e.g. /dev/sdX2, remainder of disk, format as ext4)
# Example formatting
sudo mkfs.vfat -F 32 -n ZOI_BOOT /dev/sdX1
sudo mkfs.ext4 -L ZOIOS_ROOT /dev/sdX2

Step 3: Run the Universal Distro Builder

Now, simply run the builder. This command establishes the system marker and installs the base packages.

# We mount the target root temporarily so Zoi knows where to install
sudo mount /dev/sdX2 /mnt
sudo mkdir -p /mnt/boot/efi
sudo mount /dev/sdX1 /mnt/boot/efi

# Orchestrate the entire build
sudo zoi system distro build --target /mnt --config ./target-system.lua

What happens under the hood?

In this single step, Zoi:

  1. Initializes Sysroot: Drops the /etc/os-release marker (ID=zoios) so the disk is recognized as ZoiOS.
  2. Bootstrap Installation: Directly installs the entire base package set (@parlex/linux, @parlex/glibc, etc.) into the target Zoi store and then into the system root.
  3. Builds the First Generation: Creates a lightweight record of the installation and links it to the package transaction.
  4. Generates fstab: Writes /etc/fstab based on your system.lua configuration.

Step 4: Finalize the Bootloader and Initramfs

Once the build is complete, you must ensure the bootloader is properly installed and the initramfs (initial ramdisk) is generated. Zoi makes this easy by allowing you to enter an ephemeral shell that is redirected into your new system's root using the --root flag.

1. Generate the Initramfs

ZoiOS systems require an initramfs to handle early boot tasks (like mounting the root partition). You can use any tool you've packaged, such as dracut, mkinitcpio, or booster.

# Example: Generating initramfs using dracut
sudo zoi system distro chroot /mnt
dracut --kver 7.1.4-arch1-1 --force /boot/initramfs-linux.img

2. Install the Bootloader

Now install your bootloader (e.g. GRUB) to the disk:

# Finalize the bootloader using Zoi chroot
# This automatically handles mounting /dev, /proc, and /sys into the target
sudo zoi system distro chroot /mnt
grub-install --target=x86_64-efi --efi-directory=/boot/efi --removable
grub-mkconfig -o /boot/grub/grub.cfg

3. Post-Build Package Management

Once the OS is bootstrapped, you can continue to manage its package database and configuration from the host using the --root flag. This is useful for installing extra tools or setting up custom registries inside the new OS before first boot.

# Set a custom registry inside the target OS
sudo zoi sync set /path/to/my-registry --root /mnt

# Sync the package database into the target root's system store (/var/lib/zoi)
# Zoi automatically uses --scope system when --root is specified.
sudo zoi sync --root /mnt

# Install additional packages directly into the target OS
sudo zoi install @parlex/neovim @parlex/git --root /mnt

Isolated State

When using --root, Zoi is fully isolated. Transaction logs, audit history, and local configuration files are stored within the target's /var/lib/zoi and ~/.zoi directories. By default, metadata is synced to the system-wide store (/var/lib/zoi/pkgs/db), ensuring the new OS is ready for use even without a pre-configured user home.

Pro Tip

Using zoi system distro chroot /mnt is preferred over manual chroot because it leverages Zoi's sandbox engine to safely bridge your host's system devices into the target environment automatically.

Step 5: Reboot

Unmount the filesystems and reboot into your newly built ZoiOS system!

sudo umount -R /mnt
sudo reboot

Creating a Bootable USB Stick

You can use Zoi to create a fully persistent, declarative ZoiOS USB stick. This is perfect for a portable "Swiss Army Knife" OS or a secure live environment.

1. Prepare the Configuration

Create a usb-system.lua file. It should look like a standard ZoiOS configuration but optimized for USB (e.g. using ext4 or btrfs with noatime).

2. Partition and Format the USB

Assuming your USB is /dev/sdX:

# Create EFI and Root partitions
sudo parted /dev/sdX -- mklabel gpt
sudo parted /dev/sdX -- mkpart ESP fat32 1MiB 512MiB
sudo parted /dev/sdX -- set 1 esp on
sudo parted /dev/sdX -- mkpart primary ext4 512MiB 100%

# Format and Label
sudo mkfs.vfat -F 32 -n ZOI_BOOT /dev/sdX1
sudo mkfs.ext4 -L ZOI_ROOT /dev/sdX2

3. Mount and Build

sudo mkdir -p /mnt/zoi-usb
sudo mount /dev/sdX2 /mnt/zoi-usb
sudo mkdir -p /mnt/zoi-usb/boot/efi
sudo mount /dev/sdX1 /mnt/zoi-usb/boot/efi

# Bootstrap the OS
sudo zoi system distro build --target /mnt/zoi-usb --config ./usb-system.lua

4. Finalize the Bootloader

Use Zoi chroot to install GRUB to the USB's EFI partition in removable mode:

sudo zoi system distro chroot /mnt/zoi-usb
grub-install --target=x86_64-efi --efi-directory=/boot/efi --removable
grub-mkconfig -o /boot/grub/grub.cfg

5. Cleanup and Boot

sudo umount -R /mnt/zoi-usb
sync

How It Works: The ZoiOS Guard

You might wonder why you can't run zoi system apply on a standard Ubuntu or macOS host.

Zoi includes a ZoiOS Environment Guard. Commands like zoi system apply, list, and rollback check for specific OS markers (like ID=zoios or ID=parlex in /etc/os-release). If the system is not a recognized ZoiOS distribution, these commands are safely disabled to prevent accidental damage to a standard generic Linux environment.

The zoi system distro build command is explicitly allowed on generic systems so that you can bootstrap new disks, and its primary job is to establish that initial marker so the target disk becomes a valid ZoiOS environment.


A software organization

2026 © All Rights Reserved.

  • All the content is available under CC BY-SA 4.0, expect where otherwise stated.

Last updated on