A Speed Run Installation of Arch Linux

I switched back to Arch Linux after a rocky, year long relationship with Ubuntu. The switch took longer than I thought it would. As usual, I forgot to multiply my initial estimate by three. To prevent such regressions in the future, I will document the rouch sketch of commands to get a minimal i3 system going.

Buyer beware, you should really follow the Arch installation guide and maybe steal a few tips from this. Doing it the other way around leads to ruin. Here are the specifics of my setup which may not apply to you:

  • I need WiFi to work for 1-2 networks.
  • I prefer wired ethernet if available.
  • I boot into i3 via startx. I don’t want a desktop environment like Gnome, Unity or KDE.
  • Faster is always better. I will add complexity for speed.
  • I will use EFI to boot Linux directly.

Initial Setup to Chroot

This is the initial setup from starting the Live USB to mounting the new system.

# Verify that EFI is enabled.
ls /sys/firmware/efi/efivars

# Do we have internet?
ping www.google.com

# Ensure system clock is accurate.
timedatectl set-ntp true

# Partition disks.
cgdisk /dev/nvme0n1
# Create EFI partition of 512M with code EF00.
# Create Linux partition of the rest with code 8300.
# Swap, meh.

# Format partitions.
mkfs.fat -F32 /dev/nvme0n1p1
mkfs.ext4 /dev/nvme0n1p2

# Mount the file systems.
mkdir -p /mnt/boot
mount /dev/nvme0n1p2 /mnt
mount /dev/nvme0n1p1 /mnt/boot

# Rank Pacman mirrors before downloading the base packages.
cp /mnt/etc/pacman.d/mirrorlist{,.bak}
rankmirrors -n 6 /mnt/etc/pacman.d/mirrorlist.bak > /mnt/etc/pacman.d/mirrorlist

# Install base packages and a passable editor.
pacstrap /mnt base vim sudo

genfstab -U /mnt >> /mnt/etc/fstab

arch-chroot /mnt

Setup Base System

Now that we’re in our new system, get a minimal configuration going.

ln -sf /usr/share/zoneinfo/America/Los_Angeles /etc/localtime
hwclock --systohc

# Uncomment en_US.UTF-8 UTF-8.
vim /etc/locale.gen
locale-gen

echo 'LANG=en_US.UTF-8' >> /etc/locale.conf

echo 'home.d46.us' > /etc/hostname

# Setup EFISTUB for UEFI to load Linux directly without a bootloader like grub.
# Save this in a file for easy editing later.
echo 'efibootmgr -d /dev/nvme0n1 -p 1 -c -L "Arch Linux" \
    -l /vmlinuz-linux \
    -u "root=/dev/nvme0n1p2 rw initrd=/initramfs-linux.img"' \
     > /etc/make-efi.sh
sh /etc/make-efi.sh
# Verify EFI setup, make sure root drive is root partition and you spelled
# everything correctly.
efibootmgr

# Set root password
passwd

dhcpcd
visudo
# Uncomment "%wheel ALL=(ALL) ALL" line
# Uncomment the wheel NOPASSWD line

# Make myself.
useradd -m -g users -G audio,lp,optical,storage,video,wheel,power joe
passwd joe

# Login as joe
su - joe

Install Important Packages and an AUR helper.

A few important packages.

pacman -S base-devel xorg # pick all
pacman -S nvidia nvidia-libgl # pick the nvidia-340-xx
pacman -S git open-ssh tree zsh # pick all

It’s not really an Arch installation until you have an AUR helper. The standard disclaimer about the evils of using AUR helpers applies to this case.

# Create a directory.
AUR_DIR="~/.config/aur"
mkdir -p $AUR_DIR

# Cower is up first, because pacaur depends on it.
git clone https://aur.archlinux.org/cower.git "$AUR_DIR/cower"
cd $AUR_DIR/cower
makepkg -si
# If permission errors try this command:
# gpg --recv-keys --keyserver hkp://pgp.mit.edu 1EB2638FF56C0C53

# Now, pacaur.
git clone https://aur.archlinux.org/pacaur.git "$AUR_DIR/pacaur"
cd $AUR_DIR/pacaur
makepkg -si

# You know what's better than i3, I3-WITH-GAPS
pacaur -S i3-gaps-next-git rcm google-chrome
cd

Setup Dotfiles

This would be so much easier if my dotfiles were public. Getting authentication working is a huge pain. One day I’ll scrape out the non-public stuff and publish my dotfiles again.

ssh-keygen
GH_PASSWORD='MY_PASSWORD'

# Use the OTP code from Google authenticator on the phone
# Can't use single quotes because we're getting the public key in our data.
curl -i -u "jschaf:$GH_PASSWORD" --header "X-GitHub-OTP: 123456" \
    --data "{\"title\": \"Home Desktop\", \"key\": \"$(< ~/.ssh/id_rsa.pub)\"}"\
    https://api.github.com/user/keys

# Use git protocol to force SSH instead of HTTPS and avoid having to
# reauthenticate.
git clone git@github.com:jschaf/dotfiles.git ~/.dotfiles
cd ~/.dotfiles
git submodule update --init

# Init dotfiles.
cd ~
# Setup RCM config file before we invoke rcup so it knows which folders and
# files to link.  Otherwise it ignores the config.
ln -s ~/.dotfiles/rcrc ~/.rcrc
# Make it verbose so we know what it did and include our linux stuff.
rcup -t linux -v
# Verify .dotfiles look good.
ls -al

Setup Auto Login to TTY1

Why waste precious seconds logging in, when systemd will do it for you?

WARNING: This is giant gaping security hole, but super convenient.

# Auto login to TTY1.
# https://wiki.archlinux.org/index.php/Getty#Automatic_login_to_virtual_console
echo "[Service]
Type=Simple
ExecStart=
ExecStart=-/usr/bin/agetty --autologin $USER --noclear %I \$TERM" \
     > /etc/systemd/system/getty@tty1.service.d/override.conf

Setup Networking

This networking setup will enable WiFi and wired with a preference for wired.

pacman -S wpa_supplicant

systemctl start systemd-networkd.service
systemctl enable systemd-networkd.service

systemctl start systemd-resolved.service
systemctl enable systemd-resolved.service

rm /etc/resolv.conf
ln -s /run/systemd/resolve/resolv.conf /etc/resolv.conf

systemctl enable wpa_supplicant@wlp2s0.service
[Match]
Name=enp1s0

[Network]
DHCP=ipv4

[DHCP]
RouteMetric=10
[Match]
Name=wlp2s0

[Network]
DHCP=ipv4

[DHCP]
RouteMetric=20
# Run this command.
# wpa_passphrase MYSSID passphrase > /etc/wpa_supplicant/wpa_supplicant-wlp2s0.conf
ctrl_interface=/var/run/wpa_supplicant
ctrl_interface_group=wheel
update_config=1
fast_reauth=1
ap_scan=1

network={
        ssid="MYSSID"
        # psk="passphrase"
        psk=HASHED_PASSWORD
}

Bonus Steps

Useful Packages

sudo pacman -S xdg-utils xclip feh python
pacaur -S ripgrep

# Needed for Chrome u2f (Yubikey) to work.
sudo pacman -S libu2f-host

# Custom init functions.
init-fonts
init-tmux-plugin-manager
init-wallpapers

Printing

# To enable printing from gtk apps and to enable finding printers on the
# network.
sudo pacman -S cups gtk3-print-backends avahi nss-mdns

systemctl enable avahi-daemon.service
systemctl start avahi-daemon.service

systemctl enable org.cups.cupsd.service cups-browsed.service
systemctl start org.cups.cupsd.service cups-browsed.service
# <snip.
# Add `mdns_minimal [NOTFOUND=return]` before resolve.
hosts: files mymachines mdns_minimal [NOTFOUND=return] resolve [!UNAVAIL=return] dns myhostname
# <snip>
# Add lp to allow users in lp group to administrate printers.
# Probably not a good idea if you have a big network.
SystemGroup sys root lp

Then visit http://localhost:631/ and “Add Printer”. Use your root username and password.

Improve TTY or Virtual Console.

The default color scheme for the virtual console is not pleasing on the eyes. Here’s how we fix that.

pacman -S terminus-fonts
pacaur -S mkinitcpio-colors-git setcolors-git
KEYMAP=us

# From terminus-fonts repository.  Fonts at /usr/share/kbd/consolefonts
# README for font name info: https://files.ax86.net/terminus-ttf/README.Terminus.txt
# ter: Terminus
# 1: Codepages ISO8859-1, ISO8859-15, Windows-1252
# 22: Font size
# n: normal
FONT=ter-122n
FONT_MAP=8859-1

# Font Colors - Read by mkinitcpio colors hook which writes it to the initramfs
# /consoloecolors to be loaded by setcolors.
# mkinitcpio-colors: https://github.com/EvanPurkhiser/mkinitcpio-colors
# setcolors: https://github.com/EvanPurkhiser/linux-vt-setcolors
# Arch Forum: https://bbs.archlinux.org/viewtopic.php?pid=1313384
COLOR_0=171717 # black
COLOR_8=2B2B2B # darkgrey
COLOR_1=D75F5F # darkred
COLOR_9=E33636 # red
COLOR_2=87AF5F # darkgreen
COLOR_10=98E34D # green
COLOR_3=D7AF87 # brown
COLOR_11=FFD75F # yellow
COLOR_4=8787AF # darkblue
COLOR_12=7373C9 # blue
COLOR_5=BD53A5 # darkmagenta
COLOR_13=D633B2 # magenta
COLOR_6=5FAFAF # darkcyan
COLOR_14=44C9C9 # cyan
COLOR_7=C9C9C9 # lightgrey
COLOR_15=CCCCCC # white

Docker

sudo pacman -S docker
pacaur -S  google-cloud-sdk
sudo tee /etc/modules-load.d/loop.conf <<< "loop"
systemctl enable docker.service
systemctl start docker.service

# WARNING: docker group is root equivalent.  But sooo handy.
sudo gpasswd -a "$USER" docker

# Yes, really restart.
sudo shutdown -r now

# Verify that it worked.
docker info
Published on by .