An opinionated Arch Linux installer.
The target system will closely match the result of following the official installation guide.
Components used:
- GPT partition table
- GRUB boot loader (UEFI or BIOS)
- LVM volume management (optional)
- LUKS full disk encryption (optional)
- Dedicated swap partition/volume, allowing for hibernation (optional)
- Processor microcode updates for the CPU vendor
- Early KMS start for any graphics chip sets
Enabled systemd units:
- systemd-networkd.service (with Multicast DNS enabled)
- systemd-resolved.service (with
stub-resolv.conf) - systemd-timesyncd.service
- reflector.{service,timer}
- sshd.service
- fstrim.timer (if trim is enabled)
- iwd.service (if wireless networking is enabled)
Additional configuration:
- If using both LVM and LUKS, the LVM on LUKS method will be used.
- If wireless networking is enabled, any networks on the live system will be persisted.
- If trim is enabled, discards will be configured in LVM and LUKS.
- A privileged user will be created.
- Any SSH public keys authorized on the live system will be persisted.
- The root account will be locked and denied access over SSH.
See configuration for complete details on customizing the installation.
Boot into the live environment and change the directory to this repository.
Set environment variables to configure installation:
export BOOTSTRAP_TARGET_DEVICE=/dev/sda
export BOOTSTRAP_ADMIN_LOGIN=bob
export BOOTSTRAP_MIRROR_SORT=rate
export BOOTSTRAP_TIMEZONE=America/Chicago
export BOOTSTRAP_ENABLE_LUKS=true
Initialize the environment on the live system:
source ./init
This will validate the configuration and add $PWD/bin to PATH.
Inspect the modified environment:
print-config
Create and mount partitions and file systems:
create-target
Install packages and configure operating system:
install-target
After installation, the target system is left mounted for inspection or further configuration.
If all is well, poweroff and eject the installation media.
The top-level commands, i.e., ./bin/*-target, are intentionally kept extremely simple and easy to read, serving as an outline.
They can also be helpful in other contexts, e.g., troubleshooting the target system.
An offline package repository can be used to minimize bandwidth usage or if the network is not available.
Transfer the package repository to the live system and assign the directory to BOOTSTRAP_PACKAGE_REPO_DIR.
During installation, packages will be pulled only from this repository.
To create a package repository at /var/lib/bootstrap/repo based on packages defined in ./config/packages/**:
./scripts/mkrepo
To see complete usage details:
./scripts/mkrepo -h
The Arch Linux ISO uses cloud-init which can be configured to automate the installation.
The script ./scripts/mkci can be used to create a cloud-init ISO (requires xorriso, jo, and yq).
The generated image will be configured to do the following automatically on the live system:
- Try to mount the following drives:
- A drive with the label
BOOTSTRAPat/mnt/bootstrap - A drive with the label
BOOTSTRAP_REPOat/mnt/bootstrap_repo
- A drive with the label
- Try to set the host name to
$BOOTSTRAP_HOSTNAME - Enable Multicast DNS so the live system can be reached by host name
- Create a configuration file at
/root/bootstrap.envcontaining allBOOTSTRAP_*variables - Create an installation script at
/root/bootstrapthat does the following:- Perform a basic installation using the configuration in
/root/bootstrap.env - Run the script
/root/bootstrap.localafter installation (if it exists and is executable) - Log output to
/root/bootstrap.logand/usr/local/var/log/bootstrap.logon the target system - Copy the configuration file
/root/bootstrap.envto/usr/local/etc/bootstrap.envon the target system - Create a root file system snapshot at
/.snapshots/@/bootstrap(if using btrfs subvolumes)
- Perform a basic installation using the configuration in
To see complete usage details:
./scripts/mkci -h
The script ./scripts/mkvm can be used to bootstrap a virtual machine (requires qemu, xorriso, jo, and yq).
The virtual machine will be booted with a cloud-init image generated using the script described earlier.
Additionally, it will do the following on the guest system:
- Mount
$PWDfrom the host system at/mnt/bootstrap - Try to mount
/var/lib/bootstrap/repofrom the host system at/mnt/bootstrap_repo - Configure offline installation for
/mnt/bootstrap_repo(if mounted) - Forward TCP port
60022on the host system to port22 - Allow SSH connections over vsock on client id
42
To create a virtual machine with the default settings:
./scripts/mkvm /path/to/archlinux.iso /path/to/disk.cow
The virtual machine can be configured as you would expect:
export BOOTSTRAP_HOSTNAME=vm
export BOOTSTRAP_TIMEZONE=America/Chicago
export BOOTSTRAP_ADMIN_LOGIN=frank
./scripts/mkvm /path/to/archlinux.iso /path/to/disk.cow
The following settings are controlled by the script and will be ignored.
BOOTSTRAP_TARGET_DEVICE
BOOTSTRAP_ENABLE_TRIM
BOOTSTRAP_PACKAGE_REPO_DIR
To see complete usage details:
./scripts/mkvm -h
The script ./scripts/inject can make installation over SSH easier:
It will do the following on the live system:
- Authorize the SSH keys with write access to this repository
- Enable Multicast DNS so the live system can be reached by host name
- Fetch an archive of this repository into
/tmp/bootstrap(if the script is not run locally)
If you already have access to the repository in the live system, run the script normally to authorize the keys and enable mDNS:
./scripts/inject
To also download the repository, curl the script into bash:
curl https://git.sr.ht/~jmcantrell/arch-bootstrap/blob/main/scripts/inject | bash -s
If the network is available automatically after booting, you could run the script by using the script boot parameter.
When you see the GRUB menu, press Tab to edit the kernel command line and add the following:
script=https://git.sr.ht/~jmcantrell/arch-bootstrap/blob/main/scripts/inject
The script will be run similarly to the curl command above once the live system has booted.
Installation can be tested in an ephemeral virtual machine using the script ./scripts/test.
The virtual machine will be created using the script described earlier.
After powering off the live system, the new system will be booted.
To test the default settings:
./scripts/test /path/to/archlinux.iso
The virtual machine can be configured as you would expect:
export BOOTSTRAP_TIMEZONE=America/Chicago
export BOOTSTRAP_ADMIN_LOGIN=frank
./scripts/test /path/to/archlinux.iso
To see complete usage details:
./scripts/test -h
The details of the system being installed are controlled entirely by environment variables.
There's only one required variable, BOOTSTRAP_TARGET_DEVICE.
It must be explicitly set because it's so destructive.
Any of the following variables that are needed should be defined and exported before sourcing the initialization script (./init).
The group used to determine privileged user status (default: wheel)
The privileged user's login (default: admin)
The boot firmware interface (default: uefi if /sys/firmware/efi/efivars exists, otherwise bios)
The vendor of the system's CPU (choices: intel or amd, default: parsed from vendor_id in /proc/cpuinfo)
Flag indicating that wired networking will be used (default: set if there are any network interfaces starting with en)
Flag indicating that full disk encryption should be used for the target device (e.g. true)
Flag indicating that LVM should be used (e.g. true)
Flag indicating that a dedicated area for swap should be used (e.g. true)
When LVM is enabled, a logical volume is used instead of a partition.
Flag indicating that TRIM is supported on the target device (default: set if the target device is not a disk with spinning platters)
If LUKS and/or LVM is enabled, they will be configured to issue discards.
The systemd timer for fstrim will also be scheduled.
Flag indicating that wireless networking will be used (default: set if there are any network interfaces starting with wl)
The default console font
The default console font map
The default console unicode font map
Flag indicating that subvolumes should be used for the root file system (e.g. true).
When the file system does not support subvolumes, this setting has no effect.
The default values are taken from the file ./config/file_systems/$BOOTSTRAP_FS_ROOT_KIND/root/subvolumes.
Each line must be of the form NAME MOUNT where NAME is the name of the
subvolume and MOUNT is the path where the subvolume should be mounted in
the new system.
The kind of file system to use for the root partition/volume (choices: ext4, btrfs, or xfs, default: ext4)
The label for the root file system (default: root)
Mount options for the root file system
The default value is taken from the file ./config/file_systems/$BOOTSTRAP_FS_ROOT_KIND/root/options.
Multiple lines are joined together with commas.
The label for the swap file system (default: swap)
The kernel modules used by the system's GPUs (default: parsed from the output of lspci -k, e.g. i915 xe)
Multiple values should be separated with a space.
The system host name (e.g. arch)
The number of seconds of inactivity to wait before putting the display to sleep (e.g. $((10 * 60)))
The kernel log level (e.g. 4)
Extra boot parameters (e.g. acpi_mask_gpe=0x6D)
Flag indicating that quiet should be included in the kernel parameters (e.g. true)
Flag indicating that the LTS kernel should be used by default (e.g. true)
The default keyboard mapping (e.g. us)
The default secondary keyboard mapping
The default language (default: C.UTF-8)
The default language priority list
Multiple values should be separated with a colon.
The default format for locations
The default format for sorting and regular expressions
The default interpretation of byte sequences as characters
The default settings for locale metadata
The default settings related to the measurement system
The default language for messages
The default formatting for monetary-related numeric values
The default format used to address persons
The default formatting rules for non-monetary numeric values
The default settings related to the dimensions of the standard paper size
The default settings that describe the formats for telephone services
The default formatting for date and time values
The path of the key file on the new system used by the kernel to unlock the partition without asking for the passphrase again (slot 1, generated when added, default: /etc/cryptsetup-keys.d/$BOOTSTRAP_LUKS_MAPPER_NAME.key)
The mapper name used for the decrypted partition (default: sys)
The extents of the root logical volume (default: +100%FREE, i.e. use all remaining space)
NOTE: The value needs to be recognizable by lvcreate(8).
The name for the root logical volume (default: root)
The name for the swap logical volume (default: swap)
The size of the swap logical volume (default: $BOOTSTRAP_MEMORY_SIZE)
NOTE: The value needs to be recognizable by lvcreate(8).
The name for the system volume group (default: sys)
The amount of memory available (default: parsed from the output of dmidecode, i.e. same as ram size, e.g. 16G)
The country used for mirror selection (default: US)
See reflector --list-countries for possible values.
The maximum number of the most recently synchronized mirrors (default: 5)
The sort criteria used for mirror selection (default: age)
See reflector --help for possible values.
Look for packages only in this package repository on the live system (e.g. /mnt/repo)
If this is set, it's required to be an absolute path.
If BOOTSTRAP_PACKAGE_REPO_NAME is not set, it will be taken from the first file found in this directory matching *.db.tar.*.
The package repository name for BOOTSTRAP_PACKAGE_REPO_{SERVER,DIR} (e.g. custom)
If BOOTSTRAP_PACKAGE_REPO_SERVER is set, this name must be explicitly set.
If BOOTSTRAP_PACKAGE_REPO_DIR is set and this name is not, the name will be taken from the first file found matching *.db.tar.*.
Look for packages only in this package repository on a remote system (e.g. http://repo.local:8080)
If this is set, it's required to also set BOOTSTRAP_PACKAGE_REPO_NAME.
The name of the boot partition (default: boot)
The size of the boot partition (default: $BOOTSTRAP_PART_BOOT_SIZE_<KIND> where <KIND> is UEFI or BIOS depending on the value of $BOOTSTRAP_BOOT_FIRMWARE)
NOTE: The value needs to be recognizable by sfdisk(8).
The size of BIOS boot partitions (default: 1M)
NOTE: The value needs to be recognizable by sfdisk(8).
The size of UEFI boot partitions (default: 100M)
NOTE: The value needs to be recognizable by sfdisk(8).
The type of the boot partition (default: $BOOTSTRAP_PART_BOOT_TYPE_<KIND> where <KIND> is UEFI or BIOS depending on the value of $BOOTSTRAP_BOOT_FIRMWARE)
The type of BIOS boot partitions (default: 21686148-6449-6E6F-744E-656564454649)
The type of UEFI boot partitions (default: C12A7328-F81F-11D2-BA4B-00A0C93EC93B)
The name of the swap partition (default: swap)
The size of the swap partition (default: $BOOTSTRAP_MEMORY_SIZE)
NOTE: The value needs to be recognizable by sfdisk(8).
The type of the swap partition (default: 0657FD6D-A4AB-43C4-84E5-0933C84B4F4F)
The name of the system partition (default: sys)
The size of the system partition (default: +, i.e. use all remaining space)
NOTE: The value needs to be recognizable by sfdisk(8).
The type of the system partition (default: 0FC63DAF-8483-4772-8E79-3D69D8477DE4)
The disk that will contain the new system (WARNING: all existing data will be destroyed without confirmation, e.g. /path/to/device)
The path where the new system will be mounted on the live system (default: /mnt/target)
The system time zone (default: the time zone in the live environment, if set)
The path where the EFI partition will be mounted on the new system (if applicable, default: /efi)