Skip to main content
  1. Posts/

Complete Guide to install Arch Linux on bare metal from scratch

·1751 words

Init #

I won’t be go deep with the content how to make a bootable USB with Arch Linux iso image. In my case, I have used KAIST Mirror service to download verified and reliable Arch Linux ISO images.

When you first enter the BIOS settings using UEFI USB. It will start with some familiar black screen like below.

Install Arch Linux (x86_64) without speakup and etc...
# Welcome to Arch Linux
root@archiso ~ #

Partioning disk #

ip addr show

lsblk
# Output
NAME   MAJ:MIN RM   SIZE RO TYPE MOUNTPOINTS
loop0    7:0    0 766.5M  1 loop /run/archiso/airootfs
sda      8:0    0 447.1G  0 disk
├─sda1   8:1    0   529M  0 part
├─sda2   8:2    0    99M  0 part
├─sda3   8:3    0    16M  0 part
├─sda4   8:4    0 445.8G  0 part
└─sda5   8:5    0   677M  0 part
sdb      8:16   1   3.8G  0 disk
├─sdb1   8:17   1   917M  0 part
└─sdb2   8:18   1    15M  0 part

# choose partition drive you want to use
# sdb seems to be the UEFI USB
fdisk /dev/sda 

#### Welcome to fdisk (util-linux 2.39.3) ####

# print layout
Command: p
---
Disk model: Maxtor Z1 SSD 48
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: gpt
Disk identifier: 3BC240C3-0837-446D-A76B-BFD95820AFEC

Device         Start       End   Sectors   Size Type
/dev/sda1       2048   1085439   1083392   529M Windows recovery environment
/dev/sda2    1085440   1288191    202752    99M EFI System
/dev/sda3    1288192   1320959     32768    16M Microsoft reserved
/dev/sda4    1320960 936312831 934991872 445.8G Microsoft basic data
/dev/sda5  936312832 937699327   1386496   677M Windows recovery environment
---

# give empty partion table
Command: g
---
Created a new GPT disklabel (GUID: 03DAC614-9A82-414F-99D3-87701165B8BD).
---
Command: p # now empty 
---
Disk /dev/sda: 447.13 GiB, 480103981056 bytes, 937703088 sectors
Disk model: Maxtor Z1 SSD 48
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: gpt
Disk identifier: 03DAC614-9A82-414F-99D3-87701165B8BD
---
Command: n # new partition
---
Partition number (1-128, default 1): 1
First sector (2048-937703054, default 2048): 2048
Last sector, +/-sectors or +/-size{K,M,G,T,P} (2048-937703054, default 937701375): +1G

Created a new partition 1 of type 'Linux filesystem' and of size 1 GiB.
Partition #1 contains a ntfs signature.

Do you want to remove the signature? [Y]es/[N]o: Y # !! will wipe out 

## end of creating first partion for boot process

Command: n
Partition number (2-128, default 2):
First sector (2099200-937703054, default 2099200):
Last sector, +/-sectors or +/-size{K,M,G,T,P} (2099200-937703054, default 937701375): +1G

Created a new partition 2 of type 'Linux filesystem' and of size 1 GiB.

Command: p # current status
---
Disk /dev/sda: 447.13 GiB, 480103981056 bytes, 937703088 sectors
Disk model: Maxtor Z1 SSD 48
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: gpt
Disk identifier: 03DAC614-9A82-414F-99D3-87701165B8BD

Device       Start     End Sectors Size Type
/dev/sda1     2048 2099199 2097152   1G Linux filesystem
/dev/sda2  2099200 4196351 2097152   1G Linux filesystem

Filesystem/RAID signature on partition 1 will be wiped.
---

# 3rd partition will be used to install Linux

Command (m for help): n
Partition number (3-128, default 3):
First sector (4196352-937703054, default 4196352):
Last sector, +/-sectors or +/-size{K,M,G,T,P} (4196352-937703054, default 937701375): # also leave blank to make sure to allocate all remaining space

Created a new partition 3 of type 'Linux filesystem' and of size 445.1 GiB.

Command: t
Partition number (1-3, default 3):
Partition type or alias (type L to list all): 44

Changed type of partition 'Linux filesystem' to 'Linux LVM'.

Command: p # current status
---
Disk /dev/sda: 447.13 GiB, 480103981056 bytes, 937703088 sectors
Disk model: Maxtor Z1 SSD 48
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: gpt
Disk identifier: 03DAC614-9A82-414F-99D3-87701165B8BD

Device       Start       End   Sectors   Size Type
/dev/sda1     2048   2099199   2097152     1G Linux filesystem
/dev/sda2  2099200   4196351   2097152     1G Linux filesystem
/dev/sda3  4196352 937701375 933505024 445.1G Linux LVM

Filesystem/RAID signature on partition 1 will be wiped.
---

# fully committing, *NO GOING BACK*
Command: w

The partition table has been altered.
Calling ioctl() to re-read partition table.
Syncing disks.

# now it will exit fdisk

Formatting Partitions #

# Now, continue in `root@archiso ~` shell 
mkfs.fat -F32 /dev/sda1 # partition 1
# output
mkfs.fat 4.2 (2021-01-31)

mkfs.ext4 /dev/sda2 #partition 2
# output, in my case discarding Windows
mke2fs 1.47.0 (5-Feb-2023)
/dev/sda2 contains `Windows Event Trace Log' data
Proceed anyway? (y,N) y
Discarding device blocks: done
Creating filesystem with 262144 4k blocks and 65536 inodes
Filesystem UUID: 1fc4b74a-1b58-4d37-a882-d8bff3506a15
Superblock backups stored on blocks:
	32768, 98304, 163840, 229376

Allocating group tables: done
Writing inode tables: done
Creating journal (8192 blocks): done
Writing superblocks and filesystem accounting information: done

Encrypt partition #

cryptsetup luksFormat /dev/sda3 # Where all of our data goes in

WARNING!
========
This will overwrite data on /dev/sda3 irrevocably.

Are you sure? (Type 'yes' in capital letters): YES
Enter passphrase for /dev/sda3: # password needed for every boot
Verify passphrase:
cryptsetup luksFormat /dev/sda3  23.89s user 0.41s system 67% cpu 35.883 total

# now its partition is encrypted

Configure LVM (Logical Volume Manager) #

# `lvm` here is just an arbitrary value
cryptsetup open --type luks /dev/sda3 lvm 
# output
cryptsetup open --type luks /dev/sda3 lvm  6.74s user 0.08s system 168% cpu 4.054 total

# create a volume for lvm
pvcreate /dev/mapper/lvm 
  Physical volume "/dev/mapper/lvm" successfully created.

# create volume group
vgcreate volgroup0 /dev/mapper/lvm
  Volume group "volgroup0" successfully created

# create logical volume
lvcreate -L 30GB volgroup0 -n lv_root # named lv_root in this section, and its for our root filesystem
  Logical volume "lv_root" created.

lvcreate -L 250GB volgroup0 -n lv_home # can adjust this value, in this case just want to have unclaimed space for it
  Logical volume "lv_home" created.

# clarify
vgdisplay 
  --- Volume group ---
  VG Name               volgroup0
  System ID
  Format                lvm2
  Metadata Areas        1
  Metadata Sequence No  3
  VG Access             read/write
  VG Status             resizable
  MAX LV                0
  Cur LV                2
  Open LV               0
  Max PV                0
  Cur PV                1
  Act PV                1
  VG Size               445.11 GiB
  PE Size               4.00 MiB
  Total PE              113949
  Alloc PE / Size       71680 / 280.00 GiB
  Free  PE / Size       42269 / 165.11 GiB
  VG UUID               6DaiIX-OPYe-0OOf-7jjY-uvCm-hAU0-2MezI2

lvdisplay
  --- Logical volume ---
  LV Path                /dev/volgroup0/lv_root
  LV Name                lv_root
  VG Name                volgroup0
  LV UUID                4TCrsv-ej1s-ztKb-N6xk-kZGr-gJPT-11ExxE
  LV Write Access        read/write
  LV Creation host, time archiso, 2024-03-01 00:18:42 +0000
  LV Status              available
  # open                 0
  LV Size                30.00 GiB
  Current LE             7680
  Segments               1
  Allocation             inherit
  Read ahead sectors     auto
  - currently set to     256
  Block device           254:1

  --- Logical volume ---
  LV Path                /dev/volgroup0/lv_home
  LV Name                lv_home
  VG Name                volgroup0
  LV UUID                Au9nJC-vduG-807c-jAyZ-J3kB-C2nz-iETE4D
  LV Write Access        read/write
  LV Creation host, time archiso, 2024-03-01 00:23:09 +0000
  LV Status              available
  # open                 0
  LV Size                250.00 GiB
  Current LE             64000
  Segments               1
  Allocation             inherit
  Read ahead sectors     auto
  - currently set to     256
  Block device           254:2

modprobe dm_mod 
vgscan
  Found volume group "volgroup0" using metadata type lvm2
vgchange -ay # activate all volumes
  2 logical volume(s) in volume group "volgroup0" now active

mkfs.ext4 /dev/volgroup0/lv_root
# output
mke2fs 1.47.0 (5-Feb-2023)
Creating filesystem with 7864320 4k blocks and 1966080 inodes
Filesystem UUID: 5337cf64-d898-49bb-ac62-974dff350ab2
Superblock backups stored on blocks:
	32768, 98304, 163840, 229376, 294912, 819200, 884736, 1605632, 2654208,
	4096000

Allocating group tables: done
Writing inode tables: done
Creating journal (32768 blocks): done
Writing superblocks and filesystem accounting information: done

mkfs.ext4 /dev/volgroup0/lv_home
# output
mke2fs 1.47.0 (5-Feb-2023)
Creating filesystem with 65536000 4k blocks and 16384000 inodes
Filesystem UUID: 75c4f8d6-d48a-41a0-9202-47a06776c0d3
Superblock backups stored on blocks:
	32768, 98304, 163840, 229376, 294912, 819200, 884736, 1605632, 2654208,
	4096000, 7962624, 11239424, 20480000, 23887872

Allocating group tables: done
Writing inode tables: done
Creating journal (262144 blocks): done
Writing superblocks and filesystem accounting information: done

mount /dev/volgroup0/lv_root /mnt
mkdir /mnt/boot
mount /dev/sda2 /mnt/boot

mkdir /mnt/home
mount /dev/volgroup0/lv_home /mnt/home

Install required packages #

If you interested in wha pacstrap do: https://www.reddit.com/r/archlinux/comments/o94huw/difference_between_pacman_s_and_pacstrap/

pacstrap -i /mnt base 
# ...
# pacstrap -i /mnt base  9.59s user 4.23s system 70% cpu 19.467 total

# edit fstab file
# to mount at boot time
genfstab -U -p /mnt >> /mnt/etc/fstab
cat /mnt/etc/fstab

# Static information about the filesystems.
# See fstab(5) for details.

# <file system> <dir> <type> <options> <dump> <pass>
# /dev/mapper/volgroup0-lv_root
UUID=5337cf64-d898-49bb-ac62-974dff350ab2	/         	ext4      	rw,relatime	0 1

# /dev/sda2
UUID=1fc4b74a-1b58-4d37-a882-d8bff3506a15	/boot     	ext4      	rw,relatime	0 2

# /dev/mapper/volgroup0-lv_home
UUID=75c4f8d6-d48a-41a0-9202-47a06776c0d3	/home     	ext4      	rw,relatime	0 2

# If you've followed the step well, it should look like this

Finish installation with arch-chroot #

https://wiki.archlinux.org/title/chroot https://man.archlinux.org/man/extra/arch-install-scripts/arch-chroot.8.en

arch-chroot /mnt
# command prompt changed

passwd
---
New password:
Retype new password:
passwd: password updated successfully

useradd -m -g users -G wheel jaehong21
# primary group: users
# wheel to access sudo
passwd jaehong21
---
New password:
Retype new password:
passwd: password updated successfully

Install packages #

pacman -S base-devel dosfstools grub efibootmgr lvm2 mtools vim networkmanager openssh os-prober sudo 
# os-prober (when dual boot is needed)
# pacman -S gnome gnome-tweaks (for GUI desktop)

# (Optional)
systemctl enable sshd

Install Linux kernel #

pacman -S linux linux-headers 
# optional (for fail-safe, backup kernel)
pacman -S linux-lts linux-lts-headers
# optional (for hardwares)
pacman -S linux-firmware

Install GPU driver #

lspci # giving PCI info
# If you have Intel or AMD GPU
pacman -S mesa

# If you have NVIDIA GPU
pacman -S nvidia nvidia-utils
pacman -S nvidia-lts # for linux-lts

# for Intel
pacman -S intel-media-driver
# for AMD
pacman -S libva-mesa-driver
# for NVIDIA
# video decoding is included

Generate RAM Disk for kernel #

vim /etc/mkinitpio.conf
# at the HOOKS line
# add `encrypt lvm2` between `block` and `filesystems` 

# without it kernel don't know how to deal with encryption & lvm2

mkinitcpio -p linux 
# check in the 
# -> Running build hook: []
# if there is `encrypt` and `lvm2`

mkinitcpio -p linux-lts # need to do for every kernel installed

Configure locale, GRUB #

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

vim /etc/default/grub
# GRUB_CMDLINE_DEFAULT
# between `loglevel=3` and `quiet`, add `cryptdevice=/dev/sda3:volgroup0`

# still in status in arch-chroot at /mnt
mkdir /boot/EFI
mount /dev/sda1 /boot/EFI

grub-install --target=x86_64-efi --bootloader-id=grub_uefi --recheck
---
Installing for x86_64-efi platform.
Installation finished. No error reported.

cp /usr/share/locale/en\@quot/LC_MESSAGES/grub.mo /boot/grub/locale/en.mo

grub-mkconfig -o /boot/grub/grub.cfg

# if gnome is installed, shows login screen
# gdm: gnome display manager
systemctl enable gdm 

systemctl enable NetworkManager

# exit chroot
exit 
umount -a # unmount everything
# can ignore errors

reboot
# now it will show the gnome GUI

It’s done !!

Reference #

  1. https://youtu.be/FxeriGuJKTM?si=5T1mrY9TA3MutMb4