← Back to Wiki Guides Index

Building Your Own ISO with archiso

Official AcreetionOS Documentation & Step-by-Step Tutorial

Every distribution you have ever booted was assembled from a list of files and a list of packages. Arch ships the tool that does this — archiso — and the recipe it reads is called a profile. This guide is how to build an image of your own: one with your packages, your name on the boot menu, and a pacman configuration you chose.

This guide builds a plain Arch Linux image. It is a starting point. To build an image of this distribution, use the profile in the AcreetionOS repository rather than writing one from scratch — start from what already works and change it.

1. What you need

archiso builds images only on Arch Linux. You need a plain Arch installation, not this distribution's customised one, because the build reads the system's pacman configuration.

On Arch:

sudo pacman -S --needed arch-install-scripts libisoburn squashfs-tools dosfstools e2fsprogs mtools grub

2. What a profile is

A profile is a directory. That directory is the recipe — there is no manifest pointing at a set of files elsewhere. Every profile has the same five parts:

profiledef.sh
The identity of the image: its name, its label, where its files sit on the disc, and which boot loaders to bake in.
packages.x86_64
What goes inside. One package per line. Blank lines and lines starting with # are ignored.
pacman.conf
Where those packages come from while the image is being built.
airootfs/
Files copied onto the image's own root filesystem before the packages are installed.
grub/, syslinux/, efiboot/
The boot menus, one directory per boot loader.

3. A minimal profile

Copy the upstream baseline profile and edit it. It is the right starting point because it is small and it works:

cp -r archiso/configs/baseline ~/my-profile
mkdir -p ~/my-profile/work ~/my-profile/out

profiledef.sh is where the image is described:

iso_name="myflavour"
iso_label="MYFLAVOUR"
iso_publisher="Me"
iso_application="My Flavour Live/Install"
iso_version="2026.11.10"
install_dir="myflavour"

bootmodes=('bios.syslinux' 'uefi.grub')
pacman_conf="pacman.conf"

airootfs_image_type="squashfs"
airootfs_image_tool_options=('-comp' 'zstd' '-Xcompression-level' '19' '-b' '1M')

Two things to know about install_dir: it must be lowercase letters and digits only, and for an ISO build it must be 30 characters or fewer. It is the directory your files live in on the finished disc, and the boot menu points at it.

4. Pinning your mirrors

This is the step most people get wrong, and the failure is confusing. The upstream profiles inherit /etc/pacman.d/mirrorlist — the build machine's mirror list. That makes the build depend on the machine rather than on the profile, and if that machine's mirror list is wrong the build fails after the work directory is already full, with an error that reads like a network fault.

Write your mirrors into the profile instead:

[core]
Server = https://geo.mirror.pkgbuild.com/$repo/os/$arch
Server = https://mirror.rackspace.com/archlinux/$repo/os/$arch

[extra]
Server = https://geo.mirror.pkgbuild.com/$repo/os/$arch
Server = https://mirror.rackspace.com/archlinux/$repo/os/$arch
Write them out in full rather than using Include = mirrorlist. pacman resolves a relative Include against the directory you are standing in, not against the directory of the file that contains it — so a profile with a sidecar mirror list builds from one directory and fails from another, with error: config file mirrorlist could not be read.

5. The image's own pacman configuration

The profile's pacman.conf governs the build. The image has its own configuration at /etc/pacman.conf inside it, and that one is what your users' pacman commands will read.

To control it, put a pacman.conf in airootfs/etc/. It survives the build because /etc/pacman.conf is a backup file of the pacman package: when a backup file already exists and differs from the packaged one, pacman installs the packaged version as .pacnew and leaves yours alone.

6. Building

./archiso/mkarchiso -w ~/my-profile/work -o ~/my-profile/out ~/my-profile

The build does not need root. mkarchiso uses user namespaces for the parts that need privileges, so it works as an ordinary user as long as unprivileged user namespaces are enabled.

Your image lands in out/, named <iso_name>-<iso_version>-<arch>.iso.

7. Testing it

A build that succeeds is not a build that works. At minimum, boot it:

./scripts/run_archiso.sh -i ~/my-profile/out/myflavour-2026.11.10-x86_64.iso

For a headless check, add console=ttyS0,115200 to the kernel command line in your boot menu and boot it under QEMU with -display none -serial stdio. Then check that it reached a login prompt.

8. Errors you will meet

mksquashfs: Unrecognised compressor option -Xbcj

The -X options belong to the compressor, not to mksquashfs. -Xbcj is an xz option; zstd accepts only -Xcompression-level. Copying an option list from one compressor to another fails at the rootfs step. mksquashfs -help-comp <compressor> lists what yours takes.

error: config file mirrorlist could not be read

A relative Include in the profile's pacman.conf. Write the servers out in full.

The image boots, but pacman cannot install anything

The image needs two systemd units, not one:

airootfs/etc/systemd/system/etc-pacman.d-gnupg.mount
airootfs/etc/systemd/system/pacman-init.service
airootfs/etc/systemd/system/multi-user.target.wants/pacman-init.service

The first mounts a tmpfs over /etc/pacman.d/gnupg; the second runs pacman-key --init and pacman-key --populate. Ship only the service and systemd drops it without a word in the boot log, because a missing Requires= dependency is a failed dependency. The image boots, the login prompt appears, and pacman inside it cannot install a single package.

The mount is also why a key shipped in airootfs/etc/pacman.d/gnupg/ is masked at boot: that directory is a fresh tmpfs every time. Add your own key after the mount, not before it.

[mkarchiso] ERROR: Failed to set permissions on '…'

A file_permissions entry in profiledef.sh names a path that does not exist in the image. Files copied out of airootfs/ arrive as mode 644 owned by root, so file_permissions is the only way to give a script an executable bit — but the path has to be real.

9. Where to go next