Arch Linux: Base Install in Virtual Machine
Pre-install steps
Download and verify Arch Linux media
Download the current version of Arch Linux to a location on your filesystem. See the Acquire an installation image and Verify Signature sections of the Arch Linux installation guide for instructions on how to retrieve and verify the current version of Arch Linux.
I used archlinux-2020.08.01-x86_64.iso with kernel 5.7.12-arch1-1
for this gist.
Create Virtual Machine
I'm going to trust that you have a good understanding of your hypervisor of choice for this bit =)
There are a handful of VM settings that really matter for this gist:
- Guest operating system:
- VMware Workstation: Other Linux 6.x or later kernel 64-bit (other6xlinux-64)
- Oracle VirtualBox: Arch Linux x64
- Optical drive for mounting install media
- 20GB virtual disk (commands in this gist are geared toward this size)
- SCSI or SATA disk controller (VMware Paravirtual and LSI Logic were tested, as well as VirtualBox SATA)
- UEFI boot mode:
- VMware Workstation: VM > Settings > Options > Advanced > UEFI
- Oracle VirtualBox: VM > Settings > System > Motherboard > Enable EFI (special OSes only)
- Network adapter connected to a network that provides DHCP (NAT, or usually Bridged)
- Display may need to be configured to accelerate 3D graphics - try this if you get a black screen after an otherwise successful looking boot
Aside from the above, configure the virtual machine to your liking.
Boot system to Arch Linux live distro
Mount the ISO image in the optical drive, start the virtual machine, and boot into the live Arch Linux installation distro.
Install steps
Check system capabilities
Verify boot mode
List contents of the efivars directory to verify boot mode is UEFI:
ls /sys/firmware/efi/efivars
If you get an error indicating that the directory does not exist, the system did not boot using UEFI, and you need to enable UEFI boot in VM settings.
Verify network availability
Use the following commands to check interface status and IP addressing:
ip link
ip addr
Example output:
root@archiso ~ # ip link
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
2: ens33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP mode DEFAULT group default qlen 1000
link/ether 00:0c:29:98:d8:51 brd ff:ff:ff:ff:ff:ff
altname enp2s1
root@archiso ~ # ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
2: ens33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
link/ether 00:0c:29:98:d8:51 brd ff:ff:ff:ff:ff:ff
altname enp2s1
inet 192.168.5.141/24 brd 192.168.5.255 scope global dynamic ens33
valid_lft 1630sec preferred_lft 1630sec
inet6 fe80::20c:29ff:fe98:d851/64 scope link
valid_lft forever preferred_lft forever
Your interface name will vary depending on factors, but lo
is not the one you're looking for - if that's the only interface you see, you'll need to troubleshoot. Some common primary interface names are eth0
, ens33
, ens160
, and enp0s3
. The default in VMware Workstation 15 is ens33
.
Sync network time
Ensure the system clock is synced (this is important for encrypted connections to succeed):
timedatectl set-ntp true
Configure storage
Write partition table
In this step we'll use fdisk
to write a GUID partition table (GPT) to local disk (/dev/sda).
Launch fdisk
:
fdisk /dev/sda
In fdisk
, enter the following commands, pressing enter after each:
g
w
The g
command stages the change to GPT for the disk, the w
command writes it.
Create primary partitions
In this step we'll use parted
to create, name, and set options against the primary partitions required to boot the system and define LVM volumes.
Launch parted
:
parted /dev/sda
In parted
, enter the following commands, pressing enter after each:
mkpart ESP fat32 1MiB 513MiB
mkpart primary 513MiB 1025MiB
mkpart primary 1025MiB 100%
name 1 efi
name 2 boot
name 3 lvm
set 1 boot on
set 3 lvm on
quit
There's a lot to unpack above.
The mkpart
command creates a new partition. The EFI partition is the first partition we define, and it has an ESP
type, will have a fat32
filesystem, and has a 512 MiB total size (starting at the 1MiB
offset, ending at the 513MiB
offset). The next partition is our boot partition, type primary
, size 512 MiB. The last partition is our LVM partition, type primary
, filling the remaining portion of the disk.
With the above explanation, name
should be evident - these are labels that will be useful when managing partitions on the system, and describe the function of each partition.
We then set the boot
flag to on
for the EFI partition (partition 1
), and the lvm
flag to on
for the LVM partition (partition 3
)
You can run parted -l
and lsblk
to verify these changes:
root@archiso ~ # parted -l
Model: VMware, VMware Virtual S (scsi)
Disk /dev/sda: 21.5GB
Sector size (logical/physical): 512B/512B
Partition Table: gpt
Disk Flags:
Number Start End Size File system Name Flags
1 1049kB 538MB 537MB efi boot, esp
2 538MB 1075MB 537MB boot
3 1075MB 21.5GB 20.4GB lvm lvm
root@archiso ~ # lsblk
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT
loop0 7:0 0 549.2M 1 loop /run/archiso/sfs/airootfs
sda 8:0 0 20G 0 disk
├─sda1 8:1 0 512M 0 part
├─sda2 8:2 0 512M 0 part
└─sda3 8:3 0 19G 0 part
sr0 11:0 1 671M 0 rom /run/archiso/bootmnt
Create LVM volumes
First run the pvcreate
command to create a physical volume:
pvcreate /dev/sda3
Next, run the vgcreate
command to create a volume group on our new physical volume:
vgcreate arch /dev/sda3
Last, run the following sequence of lvcreate
commands to create logical volumes on our new volume group:
lvcreate arch -n root -L 5G
lvcreate arch -n var -L 5G
lvcreate arch -n home -L 7G
lvcreate arch -n swap -l 100%FREE
Arguments in the lvcreate
command mean:
arch
: The name of the volume group to create the logical volume on-n name
: The name of the logical volume being created-L #G
: The size of the logical volume-l #%FREE
: What percentage of free extents to allocate to the logical volume
You can use the pvs
, vgs
, lvs
, and lsblk
commands to verify these changes:
root@archiso ~ # pvs
PV VG Fmt Attr PSize PFree
/dev/sda3 arch lvm2 a-- <19.00g 0
root@archiso ~ # vgs
VG #PV #LV #SN Attr VSize VFree
arch 1 4 0 wz--n- <19.00g 0
root@archiso ~ # lvs
LV VG Attr LSize Pool Origin Data% Meta% Move Log Cpy%Sync Convert
home arch -wi-a----- 7.00g
root arch -wi-a----- 5.00g
swap arch -wi-a----- <2.00g
var arch -wi-a----- 5.00g
root@archiso ~ # lsblk
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT
loop0 7:0 0 549.2M 1 loop /run/archiso/sfs/airootfs
sda 8:0 0 20G 0 disk
├─sda1 8:1 0 512M 0 part
├─sda2 8:2 0 512M 0 part
└─sda3 8:3 0 19G 0 part
├─arch-root 254:0 0 5G 0 lvm
├─arch-var 254:1 0 5G 0 lvm
├─arch-home 254:2 0 7G 0 lvm
└─arch-swap 254:3 0 2G 0 lvm
sr0 11:0 1 671M 0 rom /run/archiso/bootmnt
Format partitions and enable swap
Format the efi
partition as FAT32
(also known as vfat
):
mkfs.fat -F32 /dev/sda1
Format the boot
, root
, var
, and home
partitions as ext4
:
mkfs.ext4 /dev/sda2
mkfs.ext4 /dev/arch/root
mkfs.ext4 /dev/arch/var
mkfs.ext4 /dev/arch/home
Format and enable the swap
partition:
mkswap /dev/arch/swap
swapon /dev/arch/swap
You can use blkid -o list
to verify these changes:
root@archiso ~ # blkid -o list
device fs_type label mount point UUID
----------------------------------------------------------------------------------------------------------------------------------------
/dev/sda3 LVM2_member (in use) yjpORe-gJ4d-L2wU-Ybz3-uUne-c9JY-VMXaG7
/dev/sr0 iso9660 ARCH_202008 /run/archiso/bootmnt 2020-08-01-09-10-05-00
/dev/loop0 squashfs /run/archiso/sfs/airootfs
/dev/sda1 vfat (not mounted) 1F44-D088
/dev/sda2 ext4 (not mounted) 1c4bc21a-be8c-44ec-9bf8-98d19f62fa8f
/dev/mapper/arch-root ext4 (not mounted) 9159c405-4203-47a8-8801-9514fe0b0e08
/dev/mapper/arch-var ext4 (not mounted) 7f9a80e7-a1b0-4634-b6ea-39dde1a1ee7e
/dev/mapper/arch-home ext4 (not mounted) 1ec85e3d-78af-45a9-84e8-d14188bda4f5
/dev/mapper/arch-swap swap [SWAP] c21cf436-2af1-46de-848f-8d886885b31e
Mount filesystems
Mount the root filesystem:
mount /dev/arch/root /mnt
Create directories for the efi
, boot
, var
, and home
filesystems:
mkdir /mnt/efi /mnt/boot /mnt/var /mnt/home
Mount the efi
, boot
, var
, and home
filesystems:
mount /dev/sda1 /mnt/efi
mount /dev/sda2 /mnt/boot
mount /dev/arch/var /mnt/var
mount /dev/arch/home /mnt/home
You can use mount|tail -n 5
or lsblk
to verify these mounts:
root@archiso ~ # mount|tail -n 5
/dev/mapper/arch-root on /mnt type ext4 (rw,relatime)
/dev/sda1 on /mnt/efi type vfat (rw,relatime,fmask=0022,dmask=0022,codepage=437,iocharset=iso8859-1,shortname=mixed,utf8,errors=remount-ro)
/dev/sda2 on /mnt/boot type ext4 (rw,relatime)
/dev/mapper/arch-var on /mnt/var type ext4 (rw,relatime)
/dev/mapper/arch-home on /mnt/home type ext4 (rw,relatime)
root@archiso ~ # lsblk
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT
loop0 7:0 0 549.2M 1 loop /run/archiso/sfs/airootfs
sda 8:0 0 20G 0 disk
├─sda1 8:1 0 512M 0 part /mnt/efi
├─sda2 8:2 0 512M 0 part /mnt/boot
└─sda3 8:3 0 19G 0 part
├─arch-root 254:0 0 5G 0 lvm /mnt
├─arch-var 254:1 0 5G 0 lvm /mnt/var
├─arch-home 254:2 0 7G 0 lvm /mnt/home
└─arch-swap 254:3 0 2G 0 lvm [SWAP]
sr0 11:0 1 671M 0 rom /run/archiso/bootmnt
Install packages and chroot into system
Install essential packages
Run the following commands to install essential packages into the mounted partitions:
pacstrap /mnt base linux linux-firmware grub efibootmgr lvm2 vim
Don't worry about any localization related errors you may receive - these will be resolved by future steps.
While the installation guide only includes the base
, linux
and linux-firmware
packages in this command, these packages are the minimum required to progress with installation. The extra packages specified in this guide are:
grub
: The boot loader we'll be usingefibootmgr
: A utility used to modify the EFI boot managerlvm2
: Utilities for logical volume management (LVM)vim
: A text editor
These are the same packages that would install using pacman -S packagename
. You may want to install additional packages - go for it!
Update system's filesystem table
Use the following command to generate fstab format mount entries and append those entries to the new system's /etc/fstab
file:
genfstab -U /mnt >> /mnt/etc/fstab
Chroot into system
Jump into the new system to proceed with configuration steps:
arch-chroot /mnt
Configure System
Set root password
Change the root
user's password so login is possible on first boot into the new system:
passwd
Set time zone and synchronize time
Set the time zone (US/Pacific time in this example):
ln -sf /usr/share/zoneinfo/US/Pacific /etc/localtime
Additional time zones can be found in /usr/share/zoneinfo
, just look around with ls
to find the most relevant one.
Synchronize your system clock and your hardware clock:
hwclock --systohc
Set localization
Edit /etc/locale.gen
and uncomment en_US.UTF-8 UTF-8
and other needed locales (source).
Generate locales with:
locale-gen
Create /etc/locale.conf
and save the following line (or your preferred locale) to it:
LANG=en_US.UTF-8
Configure networking
Run ip link
to identify your interface name (ens33
in this case):
[root@archiso /]# ip link
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
2: ens33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP mode DEFAULT group default qlen 1000
link/ether 00:0c:29:98:d8:51 brd ff:ff:ff:ff:ff:ff
altname enp2s1
Edit /etc/systemd/network/20-wired.network
to configure DHCP for your interface:
[Match]
Name=ens33
[Network]
DHCP=yes
Enable systemd-networkd
and sytemd-resolved
systemd services to start at boot:
systemctl enable systemd-networkd systemd-resolved
If you would prefer to set static addressing, or have multiple network interfaces, I recommend reviewing the systemd-networkd documentation in the Arch Wiki.
Set hostname and hosts aliases
Edit /etc/hostname
and save the following line (or your preferred hostname) to it:
arch.localdomain
Edit /etc/hosts
and save the following lines to it (modifying hostname as needed):
127.0.0.1 localhost
::1 localhost
127.0.1.1 arch.localdomain arch
Update initial ramdisk hooks
The mkinitcpio
program generates the initial ramdisk (initramfs) image based on configuration specified in /etc/mkinitcpio.conf
. Because this gist uses LVM partitions, we need to include lvm2
(the name of our LVM package) to HOOKS
, before filesystems
is specified (these hooks load in order).
Edit /etc/mkinitcpio.conf
and find the line:
HOOKS=(base udev autodetect modconf block filesystems keyboard fsck)
Change the line to include lvm2
before filesystems
:
HOOKS=(base udev autodetect modconf block lvm2 filesystems keyboard fsck)
Generate boot image and configure boot loader (GRUB)
Update initial ramdisk
In order for the /etc/mkinitcpio.conf
change to apply on system boot, we need to update our initial ramdisk (initramfs).
Run the following command to generate a new initramfs image:
mkinitcpio -P
Install GRUB
Run the following command to install the GRUB with an EFI target system/directory:
grub-install --target=x86_64-efi --efi-directory=/efi
Configure GRUB
Generate GRUB configurations under the /boot
and /efi
partitions:
grub-mkconfig -o /boot/grub/grub.cfg
grub-mkconfig -o /efi/EFI/arch/grub.cfg
Post-install steps
Reboot into system
At this point you can exit
chroot, issue reboot
, and log into the system as root
for further configuration. Yay!
References
I used the following references to learn how to install Arch Linux in a virtual machine:
- Arch Wiki: Installation guide
- Arch Wiki: Arch boot process
- Arch Wiki: GRUB
- Arch Wiki: Partitioning
- Arch Wiki: VMware/Install Arch Linux as a guest
- Arch Wiki: systemd-networkd
This runbook started as a gist on GitHub - view it here: https://gist.github.com/miliarch/dd19af34679417b18f1bcdb680728a45