Before starting
To successfully deploy Arch Linux with full disk encryption and remote disk unlocking in a cloud environment, you'll need a virtual machine that meets the following requirements:
- Fully virtualized (not a container or OS-level virtualization)
- Sufficient resources (recommended: at least 2 vCPUs, 4 GiB Memory, 40 GiB Disk)
- Fast enough internet connection (e.g. 100 Mbps)
- Pre-installed with widely used Linux distribution (e.g. Debian or Ubuntu)
- Access to console via WebVNC or similar
Additionally, ensure your cloud provider's Terms of Service allow installation of custom Linux distributions.
Booting from a Live CD
To wipe the per-installed OS, and configure the new Arch Linux system, booting from a Live CD is necessary.
In most cases, you can use grml-rescueboot
to generate GRUB configurations for Arch Linux Live CD.
- Install
grml-rescueboot
. - Download the Arch Linux Live CD from here to
/boot/grml
. - Verify the checksum of the downloaded ISO file.
- Check
/etc/default/grub
, and ensure a functional timeout settings exists. - Run
update-grub
to update the GRUB configuration. - Reboot the system.
- Select the Arch Linux Live CD from the GRUB menu.
Alternatively, you can also use netboot.xyz
to boot into the Arch Linux Live CD from the network. See Booting from an existing Linux installation using GRUB.
After booting into the Arch Linux Live CD:
# Change the hostname to the one you want
hostnamectl hostname <hostname>
# Logout and login again to make the new hostname take effect in the shell
logout
# Verify network connectivity
ip a
ping -c 3 archlinux.org
# Reflector is not suitable for our use. So, stop it
systemctl stop reflector.service
# Choose a mirror
# Note: Find the nearest mirrors at https://archlinux.org/mirrorlist/
cat > /etc/pacman.d/mirrorlist <<EOF
[archlinuxcn]
Server = https://mirrors.bfsu.edu.cn/archlinux/\$repo/os/\$arch
Server = https://mirrors.tuna.tsinghua.edu.cn/archlinux/\$repo/os/\$arch
EOF
# Tweak the pacman
sed -e '/#Color/cColor' \
-e '/#VerbosePkgLists/cVerbosePkgLists' \
-e '/#ParallelDownloads/cParallelDownloads = 5' \
-i /etc/pacman.conf
less /etc/pacman.conf
# Add SSH key
echo "<ssh_public_key>" > .ssh/authorized_keys
Partitioning
Considering the UEFI boot method is not widely used for virtual machine, we will use the BIOS boot method. So, the partitioning of the virtual machine is quite simple: One /boot
and one /
, MBR partition table. BTW, the /
will be encrypted.
For example, the partitioning of a virtual machine with a 40 GiB disk will be:
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINTS
loop1 7:1 0 801.9M 1 loop /run/archiso/airootfs
sda 8:0 0 40G 0 disk
├─sda1 8:1 0 1G 0 part /mnt/boot
└─sda2 8:2 0 39G 0 part
└─crypt 254:0 0 39G 0 crypt /mnt
sr0 11:0 1 1024M 0 rom
To archive this partitioning:
# Erase the old partition table
wipefs -a /dev/sda
# Create a new partition table
# 2 Primary partitions, 1 GiB for /boot, the rest for /
echo -e ',1G,L\n,+,\n' | sfdisk /dev/sda
# Format the partitions
mkfs.xfs /dev/sda1
cryptsetup luksFormat /dev/sda2
# SSD specific optimizations
cryptsetup \
--allow-discards \
--perf-no_read_workqueue \
--perf-no_write_workqueue \
--persistent \
open /dev/sda2 crypt
mkfs.xfs /dev/mapper/crypt
# Mount the partitions
mount /dev/mapper/crypt /mnt
mkdir /mnt/boot
mount /dev/sda1 /mnt/boot
# Verify
lsblk
fdisk -l /dev/sda
cryptsetup luksDump /dev/sda2
Installing the base system
# Install the base system
pacstrap -i -K /mnt base base-devel bash-completion busybox grub linux-lts man-db man-pages mc mkinitcpio-systemd-tool openssh python rsync tinyssh vim xfsprogs
# Tweak the pacman
sed -e '/#Color/cColor' \
-e '/#VerbosePkgLists/cVerbosePkgLists' \
-e '/#ParallelDownloads/cParallelDownloads = 5' \
-i /mnt/etc/pacman.conf
less /mnt/etc/pacman.conf
# Link resolv.conf
ln -s /run/systemd/resolve/resolv.conf /mnt/etc/resolv.conf
# Generate fstab
genfstab -U /mnt >> /mnt/etc/fstab
less /mnt/etc/fstab
Configuring the base system
# Chroot into the new system
arch-chroot /mnt
# Set root password
passwd
# Verify mount points
findmnt --verify --verbose
# Set the timezone
ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
date
# Remove services' default configurations
rm -rf /etc/systemd/system
# Enable some services
systemctl enable sshd.service
systemctl enable systemd-networkd.service
systemctl enable systemd-resolved.service
systemctl enable systemd-timesyncd.service
# Set the hostname
echo <hostname> > /etc/hostname
# Generate the locale
sed '/#en_US.UTF-8 UTF-8/cen_US.UTF-8 UTF-8' -i /etc/locale.gen
less /etc/locale.gen
echo 'LANG=en_US.UTF-8' > /etc/locale.conf
locale-gen
# Swapfile
fallocate -l 1G /var/swapfile
chmod 600 /var/swapfile
mkswap /var/swapfile
swapon /var/swapfile
echo -e '\n# /var/swapfile\n/var/swapfile\tnone\tswap\tdefaults\t0 0' >> /etc/fstab
less /etc/fstab
# GRUB
sed -r '/^GRUB_TIMEOUT=/cGRUB_TIMEOUT=3' -i /etc/default/grub
sed -r '/^GRUB_CMDLINE_LINUX_DEFAULT=/cGRUB_CMDLINE_LINUX_DEFAULT="net.ifnames=0 biosdevname=0"' -i /etc/default/grub
less /etc/default/grub
grub-install /dev/sda
grub-mkconfig -o /boot/grub/grub.cfg
Networking and SSH
# Enable DHCP
cat > /etc/systemd/network/20-dhcp.network <<EOF
[Match]
Name=eth*
[Network]
DHCP=yes
EOF
# Update SSH configurations
cat > /etc/ssh/sshd_config.d/30-constellation.conf <<EOF
Port 64022
HostKey /etc/ssh/ssh_host_ed25519_key
PermitRootLogin yes
PasswordAuthentication no
EOF
# Generate SSH host keys
ssh-keygen -A
# Add SSH key
echo "<ssh_public_key>" > /root/.ssh/authorized_keys
Remote unlocking of the LUKS2 encrypted disk
# Make sure busybox, grub, mc, mkinitcpio-systemd-tool, openssh, python, tinyssh are installed
pacman -S --needed busybox grub mc mkinitcpio-systemd-tool openssh python tinyssh
# Generate configurations for initramfs
echo "crypt UUID=$(blkid /dev/sda2 -s UUID -o value) none luks" >> /etc/mkinitcpio-systemd-tool/config/crypttab
echo "UUID=$(blkid /dev/mapper/crypt -s UUID -o value) /sysroot auto x-systemd.device-timeout=9999h 0 1" >> /etc/mkinitcpio-systemd-tool/config/fstab
less /etc/mkinitcpio-systemd-tool/config/crypttab
less /etc/mkinitcpio-systemd-tool/config/fstab
# Update mkinitcpio hooks
sed -r '/^HOOKS=/s/^/#/' -i /etc/mkinitcpio.conf
sed -r '/^#HOOKS=/cHOOKS=(base autodetect modconf block filesystems keyboard fsck systemd systemd-tool)' -i /etc/mkinitcpio.conf
# Change SSH Port
mkdir -p /etc/systemd/system/initrd-tinysshd.service.d
cat > /etc/systemd/system/initrd-tinysshd.service.d/override.conf <<EOF
[Service]
Environment=
Environment=SSHD_PORT=64022
EOF
# Add SSH key
cp /root/.ssh/authorized_keys /etc/mkinitcpio-systemd-tool/config/authorized_keys
# Enable DHCP
cat > /etc/mkinitcpio-systemd-tool/network/initrd-network.network <<EOF
[Match]
Name=eth*
[Network]
DHCP=yes
EOF
# Enable required services
systemctl enable initrd-tinysshd
systemctl enable initrd-debug-progs
systemctl enable initrd-sysroot-mount
systemctl enable initrd-cryptsetup.path
# Update initramfs
mkinitcpio -P
# Verify
lsinitcpio -l /boot/initramfs-linux-lts.img
Cleaning up
# Exit the chroot environment
exit
# Unmount the partitions
swapoff -a
umount -R /mnt
cryptsetup close /dev/mapper/crypt
# Reboot
sync
reboot
(Not so minimal) ArchLinuxCN Repo and Oh-my-zsh
Personally, I prefer to use zsh
as my default shell, and oh-my-zsh
as my shell configuration manager. So, I add the ArchLinuxCN repo and install zsh
and oh-my-zsh
.
# Add ArchLinuxCN repo
# Note: Find the nearest mirrors at https://github.com/archlinuxcn/mirrorlist-repo
cat >> /etc/pacman.conf <<EOF
[archlinuxcn]
Server = https://mirrors.bfsu.edu.cn/archlinuxcn/\$arch
Server = https://mirrors.tuna.tsinghua.edu.cn/archlinuxcn/\$arch
EOF
# Add ArchLinuxCN keyring
pacman -Sy archlinuxcn-keyring
# Oh-my-zsh
pacman -S --needed zsh oh-my-zsh-git
chsh -s /usr/bin/zsh
# Note: See Public/.zshrc
vim ~/.zshrc