Install a Linux distribution into a target directory using distribution-specific package managers and bootstrap wrappers.

Table of Contents#

  1. Overview
  2. Prerequisites
  3. Bootstrap by Distribution
  4. Post-Bootstrap Configuration
  5. systemd-nspawn as an Alternative
  6. Troubleshooting
  7. See Also
  8. Sources

1. Overview#

Bootstrapping is the process of installing a minimal Linux base system into a target directory. This is the foundation of Linux installation: disk partitions are created, formatted, and mounted (for example to /mnt), then the distribution's package manager installs packages into that mount point.

Most distributions provide specialized wrappers to simplify this process:

DistributionPackage ManagerBootstrap Wrapper
AlpineapkNone (direct apk invocation)
Arch Linuxpacmanpacstrap
Debian/Ubuntuaptdebootstrap
RHEL/Fedora/AlmadnfNone (direct dnf --installroot)
Void Linuxxbpsxbps-install -R <repo> -r <root>
GentooemergeStage3 tarball extraction

These tools can create either chroot environments (for development, testing, or containers) or fully bootable systems.

2. Prerequisites#

  • A functional Linux environment (live USB, existing installation, or another distribution)
  • An active internet connection
  • The relevant package manager or bootstrap wrapper installed
  • A target partition or directory, mounted and ready

3. Bootstrap by Distribution#

3.1 Alpine Linux#

Alpine uses apk directly with mirror URLs and the --initdb flag. There is no official bootstrap wrapper.

apk -X "http://ftp.halifax.rwth-aachen.de/alpine/latest-stable/main" \
    -X "http://ftp.halifax.rwth-aachen.de/alpine/latest-stable/community" \
    -U --allow-untrusted -p /mnt --initdb add alpine-base

To install a minimal base suitable for containers, replace alpine-base with alpine-baselayout.

3.2 Arch Linux#

Arch uses pacstrap, which wraps pacman for bootstrapping into a target directory.

pacstrap -K /mnt base linux linux-firmware

The -K flag initializes an empty pacman keyring in the target. Add extra packages as needed (e.g., base-devel, networkmanager, vim).

3.3 Debian / Ubuntu#

Debian uses debootstrap, which downloads and installs a minimal Debian system.

debootstrap stable /mnt http://deb.debian.org/debian/
  • Replace stable with a specific codename: bookworm (stable), trixie (testing), sid (unstable), or noble for Ubuntu.
  • The --variant= option controls the package set:
    • Default: full base including the Linux kernel
    • --variant=minbase: minimal base (smaller, suitable for containers)
    • --variant=fakechroot: for unprivileged chroot environments
  • For Ubuntu, use a Ubuntu mirror: http://archive.ubuntu.com/ubuntu/

3.4 RHEL / Fedora / AlmaLinux#

RHEL-based systems use dnf with --installroot directly. There is no official bootstrap wrapper.

dnf --releasever=9 --best --repo=alma-baseos \
    --installroot=/mnt --setopt=install_weak_deps=False \
    groupinstall -y base core
  • Repository configuration is sourced from /etc/yum.repos.d/ on the host.
  • Group names vary by distribution: base core (RHEL/Alma), critical-path-base core (Fedora).
  • For Fedora, use --releasever=41 (or current version) and --repo=fedora.

4. Post-Bootstrap Configuration#

After bootstrapping, additional configuration is needed before the system is bootable.

4.1 Generate fstab#

# Arch Linux (genfstab from arch-install-scripts)
genfstab -U /mnt >> /mnt/etc/fstab

# Other distributions (manual)
blkid /dev/<partition> | awk '{print $2}' # get UUID
# Then add entries to /mnt/etc/fstab manually

Example /mnt/etc/fstab entry:

UUID=<partition-uuid>  /     ext4  defaults,noatime  0 1
UUID=<efi-uuid>        /boot vfat  defaults           0 2
UUID=<swap-uuid>       none  swap  defaults           0 0

4.2 Enter the Chroot#

# Arch Linux
arch-chroot /mnt

# Other distributions (manual bind mounts)
mount --bind /dev  /mnt/dev
mount --bind /proc /mnt/proc
mount --bind /sys  /mnt/sys
mount --bind /run  /mnt/run
chroot /mnt /bin/bash

4.3 Basic System Configuration#

Run these commands inside the chroot:

# Set timezone
ln -sf /usr/share/zoneinfo/<Region>/<City> /etc/localtime
hwclock --systohc

# Set locale (uncomment desired locale in /etc/locale.gen first)
locale-gen
echo "LANG=en_US.UTF-8" > /etc/locale.conf

# Set hostname
echo "<hostname>" > /etc/hostname

# Set root password
passwd

4.4 Install and Configure the Bootloader#

GRUB (UEFI)#

# Install GRUB
pacman -S grub efibootmgr   # Arch
apt install grub-efi-amd64   # Debian

# Install to EFI partition
grub-install --target=x86_64-efi --efi-directory=/boot --bootloader-id=GRUB

# Generate config
grub-mkconfig -o /boot/grub/grub.cfg

systemd-boot (UEFI, simpler alternative)#

bootctl install

# Create /boot/loader/entries/arch.conf
cat > /boot/loader/entries/arch.conf << 'EOF'
title   Arch Linux
linux   /vmlinuz-linux
initrd  /initramfs-linux.img
options root=UUID=<root-uuid> rw
EOF

4.5 Install the Kernel (if not already included)#

# Arch
pacman -S linux linux-firmware

# Debian (usually included by debootstrap)
apt install linux-image-amd64 linux-headers-amd64

# RHEL/Alma
dnf install kernel kernel-core

4.6 Network Configuration#

# systemd-networkd (minimal)
cat > /etc/systemd/network/20-wired.network << 'EOF'
[Match]
Name=en*

[Network]
DHCP=yes
EOF
systemctl enable systemd-networkd systemd-resolved

# Or install NetworkManager
pacman -S networkmanager   # Arch
systemctl enable NetworkManager

4.7 Unmount and Reboot#

exit            # leave chroot
umount -R /mnt  # recursive unmount
reboot

5. systemd-nspawn as an Alternative#

systemd-nspawn provides a lightweight container environment that is more isolated than a plain chroot. It automatically sets up /dev, /proc, and /sys without manual bind mounts.

Quick Start#

# Boot into the bootstrapped system as a container
systemd-nspawn -bD /mnt

# Or get an interactive shell without booting init
systemd-nspawn -D /mnt

Persistent Containers with machinectl#

# Move bootstrapped directory to /var/lib/machines/
mv /mnt /var/lib/machines/<name>

# Start and enable the container
machinectl start <name>
machinectl enable <name>

# Get a shell inside
machinectl shell <name>

Advantages over chroot#

  • Automatic /proc, /sys, /dev setup
  • Process isolation (PID namespace)
  • Optional network isolation (--network-veth)
  • Managed by machinectl for persistent containers
  • Supports boot into full init system (-b flag)

Troubleshooting#

IssueCauseSolution
debootstrap fails with GPG errorsMissing keyring for target releaseInstall debian-archive-keyring on host, or use --no-check-gpg (insecure)
pacstrap cannot resolve mirrorsNo DNS in targetEnsure /etc/resolv.conf exists on host; pacstrap inherits host networking
dnf --installroot missing groupsWrong --releasever or repo nameVerify with dnf --releasever=<ver> group list on host first
Chroot fails with "exec format error"Architecture mismatch (e.g., ARM on x86)Install qemu-user-static and binfmt-support for cross-arch chroot
System boots to emergency shellMissing or incorrect /etc/fstabBoot from live USB, mount root, fix fstab UUIDs with blkid
GRUB error: "no such device"EFI partition not mounted during grub-installMount EFI partition to /boot or /boot/efi and rerun grub-install
No network after first bootNetwork service not enabledEnable NetworkManager or systemd-networkd inside chroot before rebooting

See Also#

Sources#