Installing Arch Linux on my Intel NUC
While I used to fiddle with Arch, and other Linux distros when I was younger, I don’t run it as my daily driver nowadays.
If I were to reinstall Arch Linux tomorrow, I would still dogfood my own guide and expect that it should be fairly seemless.
While I don’t expect much has changed, you should know that I’m not actively verifying that these steps haven’t changed or anything like that.
It’s that time again where I decide to reinstall Arch Linux and likely end up bashing my head against a wall. I have an old blog post on my Github but it could be better so this is an extended version mainly for my own future reference.
Please note that this isn’t some guide for pros or that I expect to have the most 100% correct or efficient method of installing. It’s just what I know works for me.
Getting online
As I’m installing on an Intel NUC, I’m going to assume you might like it run it mainly via WiFi so we’ll start by getting online. You can do this graphically by running wifi-menu
.
wifi-menu
Once you’ve set up a profile, you’ll see a new entry when using the ifconfig
command and you can confirm you’re online with ping archlinux.org -c 3
.
Setting up your hard drive
Personally, I wouldn’t, and probably couldn’t (yet) install Arch Linux as a dual boot partition. That is, alongside another operating system such as Windows or macOS. You might like to and that’s great but this isn’t the guide for you :)
First, we need to see what our current devices are:
fdisk -l
You may see a few. In my case, my hard drive has a few /dev/sda<number>
entries and my USB has 2 /dev/sdb<number>
entries. For the purposes of this guide, I’ll be assuming that your hard drive is under /dev/sda
but when installing to, say, a Macbook, I’ve found that the hard drive can be under /dev/sdb
.
My hard drive will end up looking as follows once I’ve set it up:
SIZE | PURPOSE | LOCATION |
---|---|---|
500M | Boot Sector | /boot |
20G | System Root | / |
8G | Swap Space | N/A |
437G | Home Directory | /home |
I’m targeting a UEFI BIOS so we’ll be using GPT for our partition table.
The following uses gparted which you may or may not be familiar with if you’ve only use GUI installers before. Just follow along and I’ll comment what each segment is roughly doing. From hereon in, URLs prefixed by a tilde (~) indicate resources where you can read further information if you’re the curious sort.
The following WILL wipe your hard drive so ensure that this is what you’d like to do and/or that you’ve backed up everything from any currently installed OS
Partitioning
# Launched parted, passing our hard drive as an argument
parted /dev/sda
# Create a partition table using the GUID Partition Table (GPT) format.
# This wipes your drive(!)
mklabel gpt
# Create a 499M boot sector that will live at /boot
# ESP is short for EFI System Partition and are always formatted as FAT32
# We start at 1MiB instead of 0 because MBR/GPT both use the first block
# ~ https://unix.stackexchange.com/a/286325
# We use 550MiB as Rod Smith reports possible bugs with ESPs below 512MiB
# ~ http://www.rodsbooks.com/efi-bootloaders/principles.html
mkpart ESP fat32 1MiB 551MiB
# Set the boot flag to ON on partition number 1
# ~ https://www.gnu.org/software/parted/manual/html_node/set.html
set 1 boot on
# Create a 20G ext4 partition that will live at /
mkpart primary ext4 551MiB 20.5GiB
# Create an 8G swap partition
mkpart primary linux-swap 20.5GiB 28.5GiB
# Allocate the remaining space which will be used by users at /home/{user}
mkpart primary 28.5GiB 100%
# All done!
quit
Now that are partitions are set up, running fdisk -l
again should show the following:
DEVICE | FORMAT | LOCATION |
---|---|---|
/dev/sda1 | ESP | /boot |
/dev/sda2 | ext4 | / |
/dev/sda4 | ext4 | /home |
Making file systems
We don’t need any utilites to create our file systems, we can just do ‘em straight outta the box like so:
# Create a 32bit VFAT filesystem for our boot partition
# VFAT is essentially FAT32 with support for longer filenames. See below for more details.
# ~ http://wiki.linuxquestions.org/wiki/VFAT
# ~ https://unix.stackexchange.com/a/263731
mkfs.vfat -F32 /dev/sda1
# Create an ext4 filesystem for our root partition
mkfs.ext4 /dev/sda2
# Prepare a swap area
mkswap /dev/sda3
# Activate our created swap area
swapon /dev/sda3
# Create an ext4 filesystem for our home partition
mkfs.ext4 /dev/sda4
Now that our hard drive is completely set up, we’re ready to mount our file systems.
Mounting our new file systems
Just as a reminder, here’s where we want our partitions to end up
DEVICE | FORMAT | LOCATION |
---|---|---|
/dev/sda1 | ESP | /boot |
/dev/sda2 | ext4 | / |
/dev/sda4 | ext4 | /home |
Here’s how this layout translates into mount commands:
# Mount our root partition to /mnt
# NOTE: /mnt doesn't persist once we're in our bash prompt
# For example, /mnt/home becomes just /home
mount /dev/sda2 /mnt
# Create a folder which our ESP partition will be mounted to
mkdir /mnt/boot
# Mount our ESP partition to /boot
mount /dev/sda1 /mnt/boot
# Create a home folder where all of our user directories will live
mkdir /mnt/home
# Mount the home partition to /home
mount /dev/sda4 /mnt/home
Nice! We’re completely done and can start to actually install and configure Arch Linux.
Installing base packages
Now we need to download and install the base packages for Arch Linux to our /mnt
which will becomes our root (/
) later on.
pacstrap /mnt base
For the curious, the base
group contains a number of default libraries and utilties you may have used such as man
, openssl
, bash
, iptables
and gcc
to name a few.
You can view the pacstrap
script itself here. I thought it would be quite longer!
The script also runs the mkinitcpio
bash script which you can learn more about here.
This entire process may take a few minutes so feel free to read ahead while you wait.
Set up bash
With Arch Linux installed, we can finally move off of our live USB and start a bash process to set up our freshly initialised system after 2 more quick steps
Step 1 is generating a file systems table, referred to as fstab
going forward. This is done so that all devices (/dev/sdaX) specificied in the file are mounted automatically on startup.
genfstab -U /mnt >> /mnt/etc/fstab
The -U
flag denotes that we want to identify our devices using UUIDs, instead of labels, as noted here.
Step 2 is even quicker!
arch-chroot /mnt
arch-chroot
, seen here changes the root directory to, well, /
which is our new root directory. As we’re still on the live USB, we specify it as /mnt
instead.
arch-chroot
is also able to take some flags following the root partition such as arch-chroot /mnt /bin/bash
. It’s worth noting that the preceeding example is actually fairly pointless seeing as arch-chroot
already defaults to bash
anyway.
Huzzah! We’re finally in our new system but will it boot? Not quite yet and we’ve still a lot to set up so let’s carry on.
Updates and other dependencies (optional)
At this point, I like to run a system upgrade using pacman -Syu
just in case. As we’ve just pulled our dependencies minutes ago, it’ll likely find nothing but I reckon it feels good, haha.
I also need some extra bits and pieces for later at this point. We couldn’t have fetched these earlier as trying to run pacman
, the Arch Linux package manager, from the live USB would attempt to install to the USB itself and error out.
I need the following bits:
PACKAGE | PURPOSE |
---|---|
dialog | A library for console-based UIs like wifi-menu |
intel-ucode | Micro-code updates for Intel CPUs |
wpa_supplicant | Used to connect to wireless networks (put simply) |
That should be everything for now. The other bits (netctl
and dhcpcd
) were already installed as part of the base
group from earlier. If you’re using Ethernet, you can basically skip this entire step hence why it’s marked as optional.
Honestly, we don’t really need dialog
as we could just use netctl
directly but I find it more user friendly and I’m not a masochist, haha.
You might as well also enable dhcpcd
if you need it for ethernet with systemctl enable dhcpcd
.
Generating locale
Popular software often ships in a number of languages but in order to show the correct language, currency and so on, it needs to know where you live. We achieve this by generating and setting a locale.
To do so, edit /etc/locale.gen
and uncomment your respective locale. In short, the format is {language}_{country code}.{character encoding}
. As an example, I’m in New Zealand so I uncomment the line en_NZ.UTF-8 UTF-8
. If in doubt, just opt for utf-8
.
I just use nano
but if you prefer, this would be an alright time to run pacman -S vim
.
Once you’ve done that, you’ll need to generate the locale files and export your language to your environment
locale-gen
export LANG={xx}_{yy}.UTF-8
If done successfully, echo $LANG
will display your locale.
For reference, the actual locale-gen
script can be seen here as part of glibc, the GNU implementation of the C standard library. I always wondered where it was from!
Timezone
Selecting our timezone is fairly straightforward thanks to an interactive program called tzselect
. Running it will show a list of continents and oceans. Selecting one will drill down to display countries.
Once you’ve confirmed the output, it will mention appending the timezone to a file. Instead, we want to symlink that timezone to a file. In my case, the timezone is Pacific/Auckland
but of course, you’ll want to input your respective timezone instead.
ln -s /usr/share/zoneinfo/Pacific/Auckland /etc/localtime
Setting hardware clock
The last of our locale related setups is configuring the system clock. To do that, we’ll tell our hardware clock to set the system time using the --hctosys
option. You can read more about hwclock
and how it differs from system time here
hwclock --systohc
Hostname setup
We like life to be simple (but no simpler) and giving our computer/server a unique name is an important part of that process. For this bit, let’s assume we want to name our system weinerdog
because it sounds silly.
echo weinerdog > /etc/hostname
Oh, that was easy. We also need to tell our system that weinerdog
is an alias for 127.0.0.1
, just like localhost
is. We could fire up our favourite editor but it’s likely /etc/hosts
is empty so just do the following:
echo 127.0.0.1 localhost weinerdog > /etc/hosts
How quick was that, huh?
Set a root password
We’ll be using this password to login, which I sometimes forget. It should be different than the password for the user account we’ll be making soon but I’d be lying if I said I have a super secure password. You have bigger problems if you think this writeup will give you top notch security anyway. I’m just here for a usable system!
passwd
Just type in your password twice. Not much more to it than that.
Installing a boot manager
We’ll be using systemd-boot
as our EFI boot manager. I couldn’t tell you anything about it other than it works and that’s good enough.
bootctl --path=/boot install
The above command copies the systemd-boot
binary to our EFI System Partition (/boot
) and adds it as the default EFI application to be loaded as stated here.
Configuring the boot manager
Now that we have a boot manager, we need to tell it what to boot exactly. We’ll create a new arch.conf
entry using nano
:
nano /boot/loader/entries/arch.conf
and enter the following
title Arch Linux
linux /vmlinuz-linux
initrd /intel-ucode.img
initrd /initramfs-linux.img
options root=/dev/sda2 rw elevator=deadline quiet splash resume=/dev/sda3 nmi_watchdog=0
NOTE: The line initrd /intel-ucode.img
ONLY applies if you installed the intel-ucode
package from earlier which anyone with an Intel CPU should do.
As for the options, I couldn’t say if you need, or don’t need, any of them but it’s worked fine for me so far. I’ll probably read up on them in depth shortly and update this post as required.
Once that’s created, set it as the default configuration:
echo "default arch" > /boot/loader/loader.conf
and now you’re ready to reboot into a nicely working system!
exit
reboot
I’ve still got a lot to learn about Arch Linux but so far, the above setup has worked well for me.
There’s still more that goes into a system but this is enough to get past the pesky initial setup which gave me hours upon hours of grief as a beginner, which I still am essentially.