Arch Linux Install Script
Arch Linux Install Script
Many new Linux users eventually gravitate toward a more minimal Linux distro where they essentially get to build their own distro, according to their own preferences rather than Canonical’s or another big distro sponsor. Arch Linux is a terrific destination for these intermediate Linux users, because there is a lot of freedom and choice. You get to build your own distro, since you install it by hand. After you’ve installed Arch by hand a few times, you’ll probably want to create your own Arch install script.
Since you’ve already installed the distro by hand several times, you probably already have a list of preferred applications and ways of installing Arch. This script will reflect the simplest possible steps that are automated yet easily comprehended by someone not totally brand new to bash scripting.
This script, named simplest.sh
, is mainly a skeleton that you can modify and that can grow
with your growing scripting skills. WARNING: I’m using an MBR disk label here. This will
probably not work with a UEFI Motherboard or EFI bios. For that you should really use a GPT
disk label with an EFI partition formatted with FAT-32. My other install scripts use this
format, or they are capable of branching to install with GPT disk label and EFI-friendly
partitioning scheme according to whether a fully compliant EFI bios exists. I’ll revisit
this later.
When you boot up the archiso
disk image from your thumbdrive or ISO file, you’ll need to
fetch this script. From a terminal, you can get it by typing
curl -O https://raw.githubusercontent.com/deepbsd/farchi/master/simplest.sh
The simplest.sh
file will appear in your root directory. You should edit the variables to
conform to your preferences. For example, if you have a 20G virtual drive (or hard drive)
and 2G of RAM, you’ll perhaps want 10G of root partition and 4G of swap partition. You’ll
want your own hostname and so on. You’ll need to edit the script before you run it,
obviously. For testing on a VM I usually create a 30G virtual disk with 1G of RAM.
You can grab the Farchi script like this:
curl -O https://raw.githubusercontent.com/deepbsd/farchi/master/farchi.sh
Obviously, my username on Github is deepbsd. The name of the repo is farchi. And you’ll want
to snag the master branch of that repo.
Here’s my simplest.sh
script, which should just give you a starting place for your own
script. This script does not install X. You can have that as a future exercise! Or you can
use my install_x.sh
script at the same location if you need ideas. But if you just want
to install a basic, vanilla Arch system, this script takes about 5-7 minutes on my
i5-4690k with 32G of RAM and an NVME SSD, depending on network speed, mostly. Because of
the number of dependencies for X, installing X takes about twice that long.
1 #!/usr/bin/env bash
2 ## This is the simplest possible Arch Linux install script I think...
3 HOSTNAME="marbie1"
4 #VIDEO_DRIVER="xf86-video-vmware"
5 IN_DEVICE=/dev/sda
6 BOOT_DEVICE="${IN_DEVICE}1"
7 ROOT_DEVICE="${IN_DEVICE}2"
8 SWAP_DEVICE="${IN_DEVICE}3"
9 HOME_DEVICE="${IN_DEVICE}4"
10 BOOT_SIZE=512M
11 SWAP_SIZE=2G
12 ROOT_SIZE=13G
13 HOME_SIZE= # Take whatever is left over after other partitions
14 TIME_ZONE="America/New_York"
15 LOCALE="en_US.UTF-8"
16 #KEYBOARD="us" # change if you need to
17 FILESYSTEM=ext4
18 use_bcm4360(){ return 1; } # return 0 for "truthy" and 1 for "falsy"
19 if $(use_bcm4360) ; then
20 WIRELESSDRIVERS="broadcom-wl-dkms"
21 else
22 WIRELESSDRIVERS=""
23 fi
24 BASE_SYSTEM=( base base-devel linux linux-headers linux-firmware dkms vim iwd )
25 devel_stuff=( git nodejs npm npm-check-updates ruby )
26 printing_stuff=( system-config-printer foomatic-db foomatic-db-engine gutenprint cups cups-pdf cups-filters cups-pk-helper ghostscript gsfonts )
27 multimedia_stuff=( brasero sox eog shotwell imagemagick sox cmus mpg123 alsa-utils cheese )
28 # VERIFY BOOT MODE
29 efi_boot_mode(){
30 [[ -d /sys/firmware/efi/efivars ]] && return 0
31 return 1
32 }
33 # All purpose error
34 error(){ echo "Error: $1" && exit 1; }
35 ###############################
36 ### START SCRIPT HERE
37 ###############################
38 ### Check that reflector is done
39 clear
40 echo "Waiting until reflector has finished updating mirrorlist..."
41 while true; do
42 pgrep -x reflector &>/dev/null || break
43 echo -n '.'
44 sleep 2
45 done
46 ### Test internet connection
47 clear
48 echo "Testing internet connection..."
49 $(ping -c 3 archlinux.org &>/dev/null) || (error "Not Connected to Network!!!")
50 echo "Good! We're connected!!!" && sleep 3
51 ## Check time and date before installation
52 timedatectl set-ntp true
53 echo && echo "Date/Time service Status is . . . "
54 timedatectl status
55 sleep 4
56 $(efi_boot_mode) && error "You have a UEFI Bios; Please use the Farchi or Darchi script for installation"
57 #### Could just use cfdisk to partition drive
58 #cfdisk "$IN_DEVICE" # for non-EFI VM: /boot 512M; / 13G; Swap 2G; Home Remainder
59 ### NOTE: Drive partitioning is one of those highly customizable areas where your
60 ### personal preferences and needs will dictate your choices. Many options
61 ### exist here. An MBR disklabel is very old, limited, and may well inspire
62 ### you to investigate other options, which is a good exercise. But, MBR is pretty
63 ### simple and reliable, within its constraints. Bon voyage!
64 # Using sfdisk because we're talking MBR disktable now...
65 cat > /tmp/sfdisk.cmd << EOF
66 $BOOT_DEVICE : start= 2048, size=+$BOOT_SIZE, type=83, bootable
67 $ROOT_DEVICE : size=+$ROOT_SIZE, type=83
68 $SWAP_DEVICE : size=+$SWAP_SIZE, type=82
69 $HOME_DEVICE : type=83
70 EOF
71 sfdisk "$IN_DEVICE" < /tmp/sfdisk.cmd
72 ##### Format filesystems
73 mkfs.ext4 "$BOOT_DEVICE" # /boot
74 mkfs.ext4 "$ROOT_DEVICE" # /
75 mkswap "$SWAP_DEVICE" # swap partition
76 mkfs.ext4 "$HOME_DEVICE" # /home
77 #### Mount filesystems
78 mount "$ROOT_DEVICE" /mnt
79 mkdir /mnt/boot && mount "$BOOT_DEVICE" /mnt/boot
80 swapon "$SWAP_DEVICE"
81 mkdir /mnt/home && mount "$HOME_DEVICE" /mnt/home
82 lsblk && echo "Here're your new block devices. (Type any key to continue...)" ; read empty
83 ### Install base system
84 clear
85 echo && echo "Press any key to continue to install BASE SYSTEM..."; read empty
86 pacstrap /mnt "${BASE_SYSTEM[@]}"
87 echo && echo "Base system installed. Press any key to continue..."; read empty
88 # GENERATE FSTAB
89 echo "Generating fstab..."
90 genfstab -U /mnt >> /mnt/etc/fstab
91 cat /mnt/etc/fstab
92 echo && echo "Here's your fstab. Type any key to continue..."; read empty
93 ## SET UP TIMEZONE AND LOCALE
94 clear
95 echo && echo "setting timezone to $TIME_ZONE..."
96 arch-chroot /mnt ln -sf /usr/share/zoneinfo/"$TIME_ZONE" /etc/localtime
97 arch-chroot /mnt hwclock --systohc --utc
98 arch-chroot /mnt date
99 echo && echo "Here's the date info, hit any key to continue..."; read empty
100 ## SET UP LOCALE
101 clear
102 echo && echo "setting locale to $LOCALE ..."
103 arch-chroot /mnt sed -i "s/#$LOCALE/$LOCALE/g" /etc/locale.gen
104 arch-chroot /mnt locale-gen
105 echo "LANG=$LOCALE" > /mnt/etc/locale.conf
106 export LANG="$LOCALE"
107 cat /mnt/etc/locale.conf
108 echo && echo "Here's your /mnt/etc/locale.conf. Type any key to continue."; read empty
109 ## HOSTNAME
110 clear
111 echo && echo "Setting hostname..."; sleep 3
112 echo "$HOSTNAME" > /mnt/etc/hostname
113 cat > /mnt/etc/hosts <<HOSTS
114 127.0.0.1 localhost
115 ::1 localhost
116 127.0.1.1 $HOSTNAME.localdomain $HOSTNAME
117 HOSTS
118 echo && echo "/etc/hostname and /etc/hosts files configured..."
119 echo "/etc/hostname . . . "
120 cat /mnt/etc/hostname
121 echo "/etc/hosts . . ."
122 cat /mnt/etc/hosts
123 echo && echo "Here are /etc/hostname and /etc/hosts. Type any key to continue "; read empty
124 ## SET ROOT PASSWD
125 clear
126 echo "Setting ROOT password..."
127 arch-chroot /mnt passwd
128 ## INSTALLING MORE ESSENTIALS
129 clear
130 echo && echo "Enabling dhcpcd, pambase, sshd and NetworkManager services..." && echo
131 arch-chroot /mnt pacman -S git openssh networkmanager dhcpcd man-db man-pages pambase
132 arch-chroot /mnt systemctl enable dhcpcd.service
133 arch-chroot /mnt systemctl enable sshd.service
134 arch-chroot /mnt systemctl enable NetworkManager.service
135 arch-chroot /mnt systemctl enable systemd-homed
136 echo && echo "Press any key to continue..."; read empty
137 ## ADD USER ACCT
138 clear
139 echo && echo "Adding sudo + user acct..."
140 sleep 2
141 arch-chroot /mnt pacman -S sudo bash-completion sshpass
142 arch-chroot /mnt sed -i 's/# %wheel/%wheel/g' /etc/sudoers
143 arch-chroot /mnt sed -i 's/%wheel ALL=(ALL) NOPASSWD: ALL/# %wheel ALL=(ALL) NOPASSWD: ALL/g' /etc/sudoers
144 echo && echo "Please provide a username: "; read sudo_user
145 echo && echo "Creating $sudo_user and adding $sudo_user to sudoers..."
146 arch-chroot /mnt useradd -m -G wheel "$sudo_user"
147 echo && echo "Password for $sudo_user?"
148 arch-chroot /mnt passwd "$sudo_user"
149 ## INSTALL WIFI
150 $(use_bcm4360) && arch-chroot /mnt pacman -S "$WIRELESSDRIVERS"
151 [[ "$?" -eq 0 ]] && echo "Wifi Driver successfully installed!"; sleep 5
152 ## Not installing X in this script...
153 ## INSTALL GRUB
154 clear
155 echo "Installing grub..." && sleep 4
156 arch-chroot /mnt pacman -S grub os-prober
157 ## We're not checking for EFI; We're assuming MBR
158 arch-chroot /mnt grub-install "$IN_DEVICE"
159 echo "configuring /boot/grub/grub.cfg..."
160 arch-chroot /mnt grub-mkconfig -o /boot/grub/grub.cfg
161 [[ "$?" -eq 0 ]] && echo "mbr bootloader installed..."
162 echo "Your system is installed. Type shutdown -h now to shutdown system and remove bootable media, then restart"
163 read empty
Notes About Simplest.sh
As I mentioned, I’m using an MBR disk label. You’ll want to change this if you’re installing to a newer motherboard or BIOS.
The first thing to do is set up my variable names as preferences. Things like partition names and sizes, hostname, wifi driver, video chipset driver, swap space size, root partition size (I assume a 30G VM disk to start with), timezone, keyboard layout (US is assumed), and locale and filesystem format (I assume ext4).
I normally include a few extra packages with dependencies, like printing and networking utilities, a few multimedia things and some development goodies. I could easily include X and an appropriate display manager and desktop environment or window manager. I happen to like Cinnamon, but I normally install XFCE and i3wm as well, just to have options (sometimes I like to switch things up!). For this script, I opted out of installing X, but you can check out my Farchi script or my Darchi script. You can see how I branch conditionally from preferences. I figure you’ll want to just see if the script works for you.
If you want to modify the script to create create GPT partitions, you could use sgdisk
.
That’s what I use in the Farchi and Darchi scripts. You could create all the partitions with
simply using cfdisk
, but I think it’s a good exercise to automate it. Plus, sfdisk
and
sgdisk
are really fast. You can create partitions and volume groups in 3 seconds or less!
It’s wicked fast!
You could use a phrase something like this to create partitions using sgdisk:
1 if $(efi_boot_mode); then
2 sgdisk -Z "$IN_DEVICE"
3 sgdisk -n 1::+"$EFI_SIZE" -t 1:ef00 -c 1:EFI "$IN_DEVICE"
4 sgdisk -n 2::+"$ROOT_SIZE" -t 2:8300 -c 2:ROOT "$IN_DEVICE"
5 sgdisk -n 3::+"$SWAP_SIZE" -t 3:8200 -c 3:SWAP "$IN_DEVICE"
6 sgdisk -n 4 -c 4:HOME "$IN_DEVICE"
7 fi
Of course, these variables would have to be defined, and so on. You’d have to define the
efi_boot_mode function something like I did in the simplest.sh
script. And you’d have to
complete the rest of the conditional accordingly.
Further, you’d need to install the EFI boot manager instead of a normal non-efi boot loader.
I typically use GRUB with the efi-bootmanager
package and the --target
and
--efi-directory
flags. Works fine for me so far.
When you’re installing packages and their dependencies, you’ll want to pause at certain
times to see if any packages installed with a non-zero exit status. You’ll want to take note
of any errors and determine whether they are significant. Normally they are not. For
example, sometimes a package gets installed twice, but this is not a problem. Pacman is
happy to reinstall packages usually. But I’ve included some read
statements to allow
seeing the final notes of a process before the screen clears and any errors or information
scrolls past, away from your notice.
I like to use ‘here’ documents. You’ll see me using arrays and associative arrays in bash.
Also I use &&
instead of if/then
where it saves time and doesn’t obscure readability. I
like to pipe unneccesary output to /dev/null
when I’m checking exit statuses for functions.
Finally, I’m still experimenting with systemd-homed
and pambase
. I’ve had some problems
when installing X: I have trouble using sudo
from an X terminal. Not sure why that is, but
reinstalling pambase
and systemd-homed
solved the problem. I’m still not sure how this
problem got started in the first place, but I assumed there was a package change by the
maintainers. More study for me in the future! You should probably experiement with this
situation and see what works best for you.
Conclusion
Hopefully this will get you started with installing Arch linux automatically. When I first
started, I simply used cfdisk /dev/sda
to create my partitions. This script was much
rougher and more ragged. But it evolved. The Farchi and Darchi scripts are more evolved.
You can see that in just more than 150 lines of Bash, an entire system get installed. If you
wanted to install X, that’s probably another 50-75 lines. So you can see it doesn’t take a
whole lot of scripting to get your basic Arch system up and running! I’m hoping you’ll be
able to borrow this script to get started on your own journey. Bon voyage!