Archlinux Metal to Desktop Environment

In this I’ll outline a simplified install procedture that will allow you to go from metal to a machine that has a graphical desktop environment. Arch has several principles, the one your should be the most aware of is versatility. Versatility is user choice to build and use systems how they want. In following this guide you’re allowing me to make a significant amount of choices for you. For many folks a first time through the ArchLinux wiki on install procedure is too much to feel like you’re comfortable to make headway. So a trade off is following guides like this to get you’re foot in the door until you feel comfortable swapping out things. You should maintain your own notes on the install procedure, as well as you should consider contributing directly to the ArchLinux wiki or upstream projects documentation. If you find anything wrong with this guide or would like to share improvements please don’t hesitate to contact me!

Our goals will be:

  • install arch from the actual arch media (and not some sissy downstream distribution that tries to make life easier for you)
  • consume the “new breed” of systemd based initramfs
  • install a desktop environment (gnome)
  • perform some hardware tuning (power)
  • install an AUR helper and grab some community packaged helper tools


At this time you should have acquired a copy Arch as an ISO from the mirrors and gotten it onto a bootable disk. From a Linux environment, where dd is available, you should do something like this:

dd if=<archiso.iso> of=/dev/<usb-stick>`

Before you boot into the Arch live environment you’ll want to get into the BIOS and change many settings, you might want to ask other associates about this but you should ensure at minimum to have the following generally set:

  • UEFI boot enabled, delete all other boot records as we’re about to make a new one
  • secure boot disabled (ArchLinux doesn’t have signed bootloader/kernel, however you could roll your own if you ever got brave enough)
  • PXE boot disabled (we don’t want to boot from a network target)

You might also want to update your BIOS before proceeding. Many chip manufactures are not getting hit with problems that are only correctable via BIOS or microcode updates.

From there get into your one time boot menu and select the bootable disk you’ve prepared.

You will now be in the Arch live environment, and are ready to start stage zero. If at any time you are unable to use network, you’ll need to ensure you have a cable plugged in and run systemctl start dhcpcd.service to request an address from the network.

Base Bootable Install

Find which disk you’re going to work on via fdisk:


which will give you an output of the disks in your environment, as well as the partition tables and partitions already on those disks. Figure out which disk you want to use and remember it, it will have a naming convention like /dev/sda or /dev/nvmen1.

Partition your disk, we’ll use GPT for our partition table via a program called cgdisk:

cgdisk /dev/disk

From here you need to delete all partitions, and create new partitions to match something like this:

  • partition 1, sized 1GiB, partition type efi (hex ef00)
  • partition 2, sized 100%, partition type linux (hex 8300)

Partitions show up under /dev/ as a number appended to your disk name, e.g. /dev/sda1 and /dev/sda2 would indicate the first and second partition of the /dev/sda disk respectively. We’ll refer to partitio 1 as disk.1 and partition 2 as disk.2 from hereforth.

We will then lay a FAT32 filesystem in on our first partition, which is going to be our boot partition:

mkfs.vfat -F32 /dev/disk.1

We will then lay a LUKS encryption container in on our second partition, which is going to be a volume group for our root and swap:

cryptsetup --cipher aes-xts-plain64 --key-size 512 --hash sha512 -y --use-random luksFormat /dev/disk.2

LUKS allows you to add up to eight passwords. Just make sure you remember the password you set, if you want to change you can add a password in the future.

We will decrypt and open our LUKS container, mapping it onto a device named luks:

cryptsetup luksOpen /dev/disk.2 luks

This device shows up under /dev/mapper. Formerly we used LVM before laying in our root filesystem, but machines have so much memory now days as well as I never use hibernate. So we’re going to put btrfs right on top of the LUKS container:

mkfs.btrfs /dev/mapper/luks

Note that just by using btrfs you don’t get all of the fancy advantages of a check-summing file-system, to actually get the rebuild benefits you’d need to have at least one parity device, which means you’d have to do a mirror. We don’t typically set up btrfs in a mirror for the root OS. The idea behind our builds are that they are quickly reproducible in the event of a failure to an OS drive, rather than be tolerant to that failure through adding significant install complexity.

We will now mount the filesystems. First we mount root, then we mount our boot partition inside of root. We will pass some arguments to the mount procedure to specifically enable both compression and trim via discard:

mount -o compress=lzo,ssd,autodefrag,discard /dev/mapper/luks /mnt

mkdir /mnt/boot

mount /dev/disk.1 /mnt/boot

We’re now ready to do the most unique step, a pacstrap, where we pass in some minimal packages that we’ll need as we continue the installation procedure. A key assumption here is that you’ll need base-devel, which will increase your install from base by adding developmental packages. We plan to use this with the AUR later. If you want to use our epiphyte mirror add Server =$repo/os/$arch before [core], [extra], and [community] in your /etc/pacman.conf.

pacstrap /mnt base base-devel btrfs-progs vim

We then use genfstab to set up the fstab. We will use something called redirection via the >> directive below. This redirects the output of genfstab and appends it to the file passed in the next argument:

genfstab -pU /mnt >> /mnt/etc/fstab

We now arch-chroot into our newly installed system:

arch-chroot /mnt /bin/bash

Set our timezone:

rm -f /etc/localtime

ln -s /usr/share/zoneinfo/<zone_info> /etc/localtime

hwclock --systohc --utc

Set our hostname:

echo "hal9000" > /etc/hostname

Set and then generate locales:

vim /etc/locale.gen

Find the line that is en_US.UTF-8 UTF-8 and uncomment it, save, then generate the locales


Set the system locale:

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

Set the system keymap:

echo "KEYMAP=us" > /etc/vconsole.conf

Set the root password:


Configure the mkinitcpio for systemd based initramfs:

vim /etc/mkinitcpio.conf

HOOKS=(base systemd autodetect modconf block keyboard sd-vconsole sd-encrypt filesystems fsck)

Generate the initramfs:

mkinitcpio -p linux

Set up the systemd-boot:

bootctl install

Now we’re going to set up several options for our boot, for instance we’ll turn off some things like md support, you’ll need to ensure that all options are on the same line:

vim /boot/loader/entries/arch.conf
title ArchLinux
linux /vmlinuz-linux
initrd /initramfs-linux.img
options noresume hibernate=noresume rd.luks.uuid=<LUKS_UUID> rd.luks.options=discard,tries=0,timeout=0 root=UUID=<VG-ROOT_UUID> rootflags=x-systemd.device-timeout=0

Assuming your system has an nvme drive you’ve been working on it you’ll be looking for the two different UUID entries here:

You’re going to need to know that:

  • rd.luks.uuid : your luks container : /dev/disk.2
  • root=UUID= : your root filesystem : /dev/mapper/luks

You can also examine this via lsblk:

lsblk -f

NAME            FSTYPE          LABEL UUID      MOUNTPOINT
├─nvme0n1p1     vfat            <BOOT_UUID>     /boot
└─nvme0n1p2     crypto_LUKS     <LUKS_UUID>
  └─luks        btrfs           <ROOT_UUIT      /

You can find out the partition UUID by running blkid on the device, which following our convention would be blkid /dev/disk.2. If you don’t want to type it out, you should consider writing the /boot/loader/entries/arch.conf until you get to ...UUID= and use redirection like we have before:

blkid -o value -s UUID /dev/disk.2 >> /boot/loader/entries/arch.conf

Now when you go back into /boot/loader/entries/arch.conf with vim you’ll be able to whittle down to just the UUID without having to transcribe to something as archaic as paper.

It is best to also create a loader entry for your fallback initramfs:

cp /boot/loader/entries/arch.conf /boot/loader/entries/fallback.conf

Change ArchLinux to ArchLinuxFallback, change /initramfs-linux.img to /initramfs-linux-fallback.img

Then ensure that you have the ability to select the fallback:

vim /boot/loader/loader.conf

timeout 1
default arch

Now we close up shop and reboot into the installed system:


umount -R /mnt


At this time you should be able to reboot and get back to your root shell after typing in your encryption password. If you don’t get back in, you need to re-examine your steps and ensure you can pass this stage.

Desktop Environment

Set up network time:

systemctl enable --now systemd-timesyncd.service

Create a user account, as you do not want to be running as root when you’re doing your day-to-day activities. I am partial to using three letter initials as an acronym:

useradd -m -s /bin/bash agd

passwd agd

Edit the sudoers file via visudo so that we can give the wheel group access to sudo privileges.


Uncomment %wheel ALL=(ALL) ALL, save, then add yourself to the wheel group:

usermod -a -G wheel agd

Change to your user and test to see if sudo is working:

su agd

sudo su

And then let’s get the packages for our desktop environment and some other useful tools:

pacman -S gnome gnome-tweak-tool bash-completion htop git file-roller brasero p7zip hexchat keepassxc firefox-developer-edition

Additionally I think these packages are useful, however you may want to wade in and not bloat up your system right off the bat:

pacman -S gmpc mpd mpv mumble gimp darktable rawtherapee libreoffice-fresh nmap materia-gtk-theme papirus-icon-theme noto-fonts ttf-droid ttf-liberation ttf-hack ttf-dejavu

We now have the packages for our desktop environment and we need to enable two critical services, you should read about both of these services to understand what you’re turning on:

systemctl enable gdm.service systemctl enable NetworkManager.service

A note to folks who might see visual aberrations on gnome-shell. The default for gdm is to use wayland/xwayland, which on some very recent versions (3.30) of gnome-shell have a some problems. Wayland is the “future”, but for now if you want to use xorg it can be forced from gdm: uncomment WaylandEnable=false in /etc/gdm/custom.conf.

You should reboot at this time and get a desktop environment. The next steps require copying text that is longer than what you’ve dealt with before.


Now we set up a very basic firewall using nftables:

pacman -S nftables

vim /etc/nftables.conf

flush ruleset

table inet filter {
    chain input {
        type filter hook input priority 0;

        # accept any localhost traffic
        iif lo accept

        # accept traffic originated from us
        ct state established,related accept

        # accept ICMP & IGMP
        ip6 nexthdr icmpv6 icmpv6 type { destination-unreachable, packet-too-big, time-exceeded, parameter-problem, mld-listener-query, mld-listener-report, mld-listener-reduction, nd-router-solicit, nd-router-advert, nd-neighbor-solicit, nd-neighbor-advert, ind-neighbor-solicit, ind-neighbor-advert, mld2-listener-report } accept
        ip protocol icmp icmp type { destination-unreachable, router-solicitation, router-advertisement, time-exceeded, parameter-problem } accept
        ip protocol igmp accept

        # activate the following line to accept common local services
        #tcp dport { 4252 } ct state new accept

        # count and drop any other traffic
        counter drop

systemctl enable --now nftables.service

Hardware Tuning and Power

At this stage you should consider finding other individuals who are running the same hardware you’re installing on. For example you’ll see several edits from me on the ArchLinux wiki page for T470s. This is more critical on newer systems that may require specific modules to be loaded in your mkinitcpio.conf, or module parameters enumerated.

I’ve had good luck with powertop auto-tune, however this can muck with hardware in a way that is undesireable. Consider my guide on selectively tuning settings from powertop via systemd.

It’s a small section within the write up, but its important to consider that your hardware may have idiosyncrasies if you don’t do some research and tune your install properly.

The Arch User Repository

The AUR is a powerful, beautiful, and terrifying aspect of the distribution. You can find almost any software packaged in the AUR if you don’t located it in the projects repositories. The ArchLinux packaging process makes for extremely readable/understandable monolithic PKGBUILD files. When using the AUR you’re essentially consuming packages from non Trusted Users. Many packages spend time in the AUR before they mature enough for a TU to take on, or their packagers become TUs. Before getting started you should familiarize yourself with the idea of the AUR.

You can use AUR helpers to assist in the install/upgrade process for packages. Personally I think enckse’s naaman is perfect. We’ll have to manually install our AUR helper from the AUR to bootstrap ourselves:

sudo pacman -S base-devel

git clone

cd naaman


Review what this PKGBUILD is doing before proceeding.


sudo pacman -U naaman-<vers>-any.pkg.tar.xz

Now you’ve got naaman installed, and you can snag stuff from either the Arch repositories or the AUR repositories. For example I’m partial to these for quality of life:

naaman -S mpdscribble numix-cursor-theme signal-desktop-bin

You can also update all of your AUR packages using the same syntax as pacman:

naaman -Syyu


Make sure you fire up gnome-tweak-tool and familiarize yourself with the many customizations that go beyond the gnome control center. The major things you should consider:

  • enable the user themes extension
  • use the materia-compact application and shell theme
  • use the papirus-light icon theme
  • use the numix-light cursor theme
  • enable Subpixel antialiasing with slight hinting

User Services

Systemd has some wonderful faculties, user services is an incredibly powerful one. For example let’s run a gpg-agent that starts whenever we log in:

systemctl --user enable --now gpg-agent.service

You can check out these services by looking in your ~/.config/systemd directory. If you’re an mpd user this is an excellent way to ensure that your mpd process is always going to have the proper pulseaudio permissions necessary to allow mixing of multiple audio streams.

You can write your own user services, and you’d be surprised to see how many packages already come with the generalizations in place to be run as user services (e.g. syncthing).


You should be in a livable state now, when I’d first began it took me a couple times through before I was able to not make silly mistakes. The major hurdle is always getting yourself to a bootable state after the live media install.

Consider the choices made for you in this guide and re-examine them to ensure that it makes sense for your lifestyle.

Good luck, enjoy your journey with ArchLinux. Read, Contribute, Evangelize.