How to automate an Arch Linux installation

For those who have not tried this amazing Linux distro called Arch Linux, I would strongly recommend you give it a try. Try to understand what it is all about before giving these automation scripts a spin. In a nutshell Arch Linux is a minimalist Linux distro for users who are more experienced, likes to mess around the terminal and customize it. Basically it is designed to make it “Yours”.

What Arch Linux differs from the mainstream distros such as Ubuntu, Debian and CentOS is that those have periodic releases. It is good and all, but upgrading to a major version can sometimes be a nightmare and people just do fresh installs every 6 months? Maybe. This is what I love about Arch Linux, there is no notion of “releases”, rather they have this concept called a “rolling release”. What this means is that you just update all your packages and your system will stay updated with the latest and greatest. Updates will happen mostly every day. In fact I have most of my servers running Arch Linux in production and never had stability issues.

The only downside of using Arch Linux is that installation can be lengthy, especially for new users. That is why I am writing this article to inspire new users to give it a try. I am using the following scripts to automate my server deployments. If you are new to Arch and would like to understand how the system works, it is highly recommended that you read and go through the Installation guide from the Arch Linux Wiki.

First of all go download the official ISO and boot it up. You will get something like below, the first option will do for most people.

Arch Linux bootup screen

If you have another machine or installing from a virtual machine, you can enable ssh and install it remotely which I strongly recommend as you won’t be able to copy and paste otherwise! To enable SSH, change your password first then start it up.

Bash
1
2
passwd
systemctl start sshd

If you’re behind a VM, might need to port forward an available port to 22. I’m using VirtualBox with NAT by default so this is needed for me. Then you can ssh like so, IP address might be different.

Bash
1
ssh -p 2222 root@127.0.0.1

If that all works okay, here is the Arch Linux install script to copy (and modify to your preference).

Bash: run.sh
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
#!/bin/bash

PS3='Select Environment: '
options=("Local VM" "Other")
select opt in "${options[@]}"
do
case "$opt" in
"VirtualBox")
DISK=sda
PORT=2222
HOST=127.0.0.1
break
;;
"Other")
DISK=vda
PORT=22
echo -n "HOST: "
read HOST
break
;;
*) echo Invalid;;
esac
done

echo DISK="$DISK", PORT="$PORT", HOST="$HOST"

HOST_ROOT="root@$HOST"
PUBKEY=$(cat ./id_rsa.pub)

# copy your public key, so can ssh without a password later on
ssh -tt -p "$PORT" "$HOST_ROOT" "mkdir -m 700 ~/.ssh; echo $PUBKEY > ~/.ssh/authorized_keys; chmod 600 ~/.ssh/authorized_keys"

# copy install scripts from ./root folder
scp -P "$PORT" ./root/* "$HOST_ROOT:/root"

# run the install script remotely
ssh -tt -p "$PORT" "$HOST_ROOT" "./install.sh $DISK"
Bash: root/install.sh
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#!/bin/bash

DISK="/dev/$1"
PARTITION="${DISK}1"

echo DISK="$DISK", PARTITION="$PARTITION"

parted -s "$DISK" mklabel msdos
parted -s -a optimal "$DISK" mkpart primary ext4 0% 100%
parted -s "$DISK" set 1 boot on
mkfs.ext4 -F "$PARTITION"

# you can find your closest server from: https://www.archlinux.org/mirrorlist/all/
echo 'Server = http://mirror.internode.on.net/pub/archlinux/$repo/os/$arch' > /etc/pacman.d/mirrorlist
mount "$PARTITION" /mnt
pacman -Syy

# would recommend to use linux-lts kernel if you are running a server environment, otherwise just use "linux"
pacstrap /mnt $(pacman -Sqg base | sed 's/^linux$/&-lts/') base-devel grub openssh sudo ntp wget vim
genfstab -p /mnt >> /mnt/etc/fstab

cp ./chroot.sh /mnt
cp ~/.ssh/authorized_keys /mnt
arch-chroot /mnt ./chroot.sh "$DISK"
rm /mnt/chroot.sh
rm /mnt/authorized_keys

umount -R /mnt
systemctl reboot
Bash: root/chroot.sh
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
#!/bin/bash

HOST=myhostname
USERNAME=myusername
HOME_DIR="/home/${USERNAME}"
SWAP_SIZE=4G

echo DISK="$1", HOST="$HOST", USERNAME="$USERNAME", HOME_DIR="$HOME_DIR"

# grub as a bootloader
grub-install --target=i386-pc --recheck "$1"

# This makes the grub timeout 0, it's faster than 5 :)
sudo sed -i 's/GRUB_TIMEOUT=5/GRUB_TIMEOUT=0/g' /etc/default/grub
grub-mkconfig -o /boot/grub/grub.cfg

# run these following essential service by default
systemctl enable sshd.service
systemctl enable dhcpcd.service
systemctl enable ntpd.service

echo "$HOST" > /etc/hostname

# inject vimrc config to default user dir if you like vim
echo -e 'runtime! archlinux.vim\nsyntax on' > /etc/skel/.vimrc

# adding your normal user with additional wheel group so can sudo
useradd -m -G wheel -s /bin/bash "$USERNAME"

# adding public key both to root and user for ssh key access
mkdir -m 700 "$HOME_DIR/.ssh"
mkdir -m 700 /root/.ssh
cp /authorized_keys "/$HOME_DIR/.ssh"
cp /authorized_keys /root/.ssh
chown -R "$USERNAME:$USERNAME" "$HOME_DIR/.ssh"

# adjust your timezone here
ln -f -s /usr/share/zoneinfo/Australia/Melbourne /etc/localtime
hwclock --systohc

# adjust your name servers here if you don't want to use google
echo 'name_servers="8.8.8.8 8.8.4.4"' >> /etc/resolvconf.conf
echo en_US.UTF-8 UTF-8 > /etc/locale.gen
echo LANG=en_US.UTF-8 > /etc/locale.conf
locale-gen

# because we are using ssh keys, make sudo not ask for passwords
echo 'root ALL=(ALL) ALL' > /etc/sudoers
echo '%wheel ALL=(ALL) NOPASSWD: ALL' >> /etc/sudoers

# I like to use vim :)
echo -e 'EDITOR=vim' > /etc/environment

# creating the swap file, if you have enough RAM, you can skip this step
fallocate -l "$SWAP_SIZE" /swapfile
chmod 600 /swapfile
mkswap /swapfile
echo /swapfile none swap defaults 0 0 >> /etc/fstab

# auto-complete these essential commands
echo complete -cf sudo >> /etc/bash.bashrc
echo complete -cf man >> /etc/bash.bashrc

Your file structure locally should look something like this:

1
2
3
4
┌─ root/
│ ├─ chroot.sh
│ └─ install.sh
└─ run.sh

Then you can just invoke the run script, make sure they are all executable using chmod +x and run the ./run.sh script. Make sure you go through the scripts carefully before running it, this will just install a very basic system that is operational.

I might write up another article for a full lightweight desktop environment later on. This is it for now! I hope you guys like it, please comment below if there are any questions.