Complete Arch Linux Installation from Scratch: UEFI, KDE Plasma, systemd-boot, and NetworkManager

This version is designed as a genuinely usable fresh installation rather than an ultra-minimal Arch base. It assumes UEFI/GPT, dedicates the entire selected disk to Arch, uses ext4, systemd-boot, NetworkManager, an 8 GiB swap file, and optionally installs KDE Plasma + SDDM + PipeWire + Firefox. KDE is enabled by default. Current Arch documentation supports pacstrap -K, UUID-based fstab, systemd-boot, and NetworkManager in this configuration. ArchWiki

Important: this script erases the entire target disk. It is not for Windows/Arch dual boot. If you intend to retain Windows, do not run this version.

1. Before running the script

Boot the Arch USB in UEFI mode, not legacy/CSM mode. You can confirm with:

ls /sys/firmware/efi/efivars

If that directory exists, you are in UEFI mode. Arch also recommends confirming network connectivity and enabling time synchronization before installation. ArchWiki

For Ethernet, the network will usually work automatically.

For Wi-Fi, first identify the wireless interface:

iwctl device list

Then connect, replacing wlan0 and the network name:

iwctl station wlan0 connect "YOUR WIFI NAME"

Test:

ping -c 3 archlinux.org

Then check your disks:

lsblk -o NAME,SIZE,MODEL,TYPE

You might see, for example:

NAME        SIZE MODEL                 TYPE
sda        28.7G SanDisk USB          disk
nvme0n1   953.9G Samsung SSD          disk

In this example:

/dev/sda       = Arch installation USB
/dev/nvme0n1   = internal SSD

You absolutely do not want to select the USB accidentally.


2. Complete installer script

Create the installer:

nano arch-install.sh

Paste this entire script:

#!/usr/bin/env bash

set -euo pipefail

###############################################################################
# ARCH LINUX FULL-DISK INSTALLER
#
# UEFI + GPT
# ext4
# systemd-boot
# NetworkManager
# swap file
# optional KDE Plasma desktop
#
# WARNING:
# THE SELECTED DISK WILL BE COMPLETELY ERASED.
###############################################################################

# ============================================================================
# USER CONFIGURATION
# ============================================================================

# CHANGE THIS after checking `lsblk`
DISK="/dev/nvme0n1"

# Computer name
HOSTNAME="archlinux"

# Your normal user account
USERNAME="archuser"

# Locale
LOCALE="en_US.UTF-8"

# Console keyboard
KEYMAP="us"

# Time zone
TIMEZONE="America/Mexico_City"

# Swap file size in GiB
SWAP_GIB=8

# Install KDE Plasma desktop?
INSTALL_KDE=true

# Install Bluetooth support?
INSTALL_BLUETOOTH=true

# Install printing support?
INSTALL_PRINTING=true


# ============================================================================
# HELPER FUNCTIONS
# ============================================================================

info() {
    printf '\n\033[1;34m==> %s\033[0m\n' "$1"
}

success() {
    printf '\n\033[1;32m==> %s\033[0m\n' "$1"
}

error() {
    printf '\n\033[1;31mERROR: %s\033[0m\n' "$1" >&2
    exit 1
}

partition_name() {
    local disk="$1"
    local number="$2"

    if [[ "$disk" =~ [0-9]$ ]]; then
        echo "${disk}p${number}"
    else
        echo "${disk}${number}"
    fi
}


# ============================================================================
# BASIC CHECKS
# ============================================================================

[[ $EUID -eq 0 ]] || error "Run this script as root."

[[ -d /sys/firmware/efi/efivars ]] || \
    error "The Arch ISO was not booted in UEFI mode."

[[ -b "$DISK" ]] || \
    error "$DISK is not a valid block device."

DISK_TYPE=$(lsblk -dn -o TYPE "$DISK")

[[ "$DISK_TYPE" == "disk" ]] || \
    error "$DISK does not appear to be a physical disk."

[[ -e "/usr/share/zoneinfo/$TIMEZONE" ]] || \
    error "Invalid timezone: $TIMEZONE"


# ============================================================================
# NETWORK CHECK
# ============================================================================

info "Checking Internet connection..."

if ! ping -c 1 -W 3 archlinux.org >/dev/null 2>&1; then
    error "No Internet connection. Connect Ethernet or Wi-Fi first."
fi

success "Internet connection is working."


# ============================================================================
# TIME
# ============================================================================

info "Enabling network time synchronization..."

timedatectl set-ntp true || true


# ============================================================================
# DISPLAY DISKS
# ============================================================================

echo
echo "Detected storage devices:"
echo

lsblk -o NAME,SIZE,MODEL,FSTYPE,MOUNTPOINTS

echo
echo "================================================================="
echo " WARNING"
echo
echo " Everything on:"
echo
echo "     $DISK"
echo
echo " WILL BE PERMANENTLY ERASED."
echo "================================================================="
echo

read -r -p "Type exactly ERASE $DISK to continue: " CONFIRM

[[ "$CONFIRM" == "ERASE $DISK" ]] || {
    echo "Installation cancelled."
    exit 1
}


# ============================================================================
# PARTITION NAMES
# ============================================================================

ESP_PART=$(partition_name "$DISK" 1)
ROOT_PART=$(partition_name "$DISK" 2)

info "EFI partition will be: $ESP_PART"
info "Root partition will be: $ROOT_PART"


# ============================================================================
# CLEAN PREVIOUS MOUNTS
# ============================================================================

info "Unmounting existing filesystems on target disk..."

while read -r dev; do
    swapoff "$dev" 2>/dev/null || true
    umount "$dev" 2>/dev/null || true
done < <(
    lsblk -lnpo NAME,TYPE "$DISK" |
    awk '$2 == "part" {print $1}'
)

umount -R /mnt 2>/dev/null || true


# ============================================================================
# ERASE PARTITION TABLE
# ============================================================================

info "Erasing old partition signatures..."

wipefs --all --force "$DISK"

sfdisk --delete "$DISK" 2>/dev/null || true


# ============================================================================
# CREATE GPT PARTITIONS
# ============================================================================

info "Creating GPT partition table..."

sfdisk "$DISK" <<EOF
label: gpt
size=1G, type=C12A7328-F81F-11D2-BA4B-00A0C93EC93B, name="EFI System"
type=0FC63DAF-8483-4772-8E79-3D69D8477DE4, name="Arch Linux"
EOF

partprobe "$DISK"
udevadm settle

sleep 2


# ============================================================================
# FORMAT
# ============================================================================

info "Formatting EFI partition as FAT32..."

mkfs.fat -F 32 -n EFI "$ESP_PART"

info "Formatting root partition as ext4..."

mkfs.ext4 -F -L ArchRoot "$ROOT_PART"


# ============================================================================
# MOUNT
# ============================================================================

info "Mounting root filesystem..."

mount "$ROOT_PART" /mnt

mkdir -p /mnt/boot

info "Mounting EFI System Partition at /boot..."

mount "$ESP_PART" /mnt/boot


# ============================================================================
# CPU MICROCODE
# ============================================================================

MICROCODE=""

if grep -q "GenuineIntel" /proc/cpuinfo; then
    MICROCODE="intel-ucode"
    info "Intel CPU detected."
elif grep -q "AuthenticAMD" /proc/cpuinfo; then
    MICROCODE="amd-ucode"
    info "AMD CPU detected."
else
    info "CPU manufacturer not recognized; skipping microcode package."
fi


# ============================================================================
# PACKAGE LIST
# ============================================================================

PACKAGES=(
    base
    linux
    linux-firmware
    base-devel
    sudo
    networkmanager
    git
    nano
    vim
    man-db
    man-pages
    texinfo
    dosfstools
    efibootmgr
)

if [[ -n "$MICROCODE" ]]; then
    PACKAGES+=("$MICROCODE")
fi


# ============================================================================
# KDE PLASMA
# ============================================================================

if [[ "$INSTALL_KDE" == true ]]; then

    info "KDE Plasma installation enabled."

    PACKAGES+=(
        plasma-meta
        sddm
        konsole
        dolphin
        firefox
        pipewire
        pipewire-alsa
        pipewire-pulse
        wireplumber
        mesa
        noto-fonts
        noto-fonts-emoji
    )

fi


# ============================================================================
# BLUETOOTH
# ============================================================================

if [[ "$INSTALL_BLUETOOTH" == true ]]; then

    PACKAGES+=(
        bluez
        bluez-utils
    )

fi


# ============================================================================
# PRINTING
# ============================================================================

if [[ "$INSTALL_PRINTING" == true ]]; then

    PACKAGES+=(
        cups
        cups-pdf
    )

fi


# ============================================================================
# INSTALL BASE SYSTEM
# ============================================================================

info "Installing Arch Linux packages..."

pacstrap -K /mnt "${PACKAGES[@]}"


# ============================================================================
# CREATE SWAP FILE
# ============================================================================

if (( SWAP_GIB > 0 )); then

    info "Creating ${SWAP_GIB} GiB swap file..."

    mkswap \
        -U clear \
        --size "${SWAP_GIB}G" \
        --file /mnt/swapfile

fi


# ============================================================================
# FSTAB
# ============================================================================

info "Generating /etc/fstab..."

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

if (( SWAP_GIB > 0 )); then
    echo '/swapfile none swap defaults 0 0' >> /mnt/etc/fstab
fi

echo
echo "Generated fstab:"
echo
cat /mnt/etc/fstab


# ============================================================================
# TIMEZONE
# ============================================================================

info "Configuring timezone: $TIMEZONE"

ln -sf \
    "/usr/share/zoneinfo/$TIMEZONE" \
    /mnt/etc/localtime

arch-chroot /mnt hwclock --systohc


# ============================================================================
# LOCALE
# ============================================================================

info "Configuring locale: $LOCALE"

sed -i \
    "s/^#${LOCALE} UTF-8/${LOCALE} UTF-8/" \
    /mnt/etc/locale.gen

if ! grep -Fqx "${LOCALE} UTF-8" /mnt/etc/locale.gen; then
    echo "${LOCALE} UTF-8" >> /mnt/etc/locale.gen
fi

arch-chroot /mnt locale-gen

echo "LANG=$LOCALE" > /mnt/etc/locale.conf


# ============================================================================
# CONSOLE KEYBOARD
# ============================================================================

echo "KEYMAP=$KEYMAP" > /mnt/etc/vconsole.conf


# ============================================================================
# HOSTNAME
# ============================================================================

info "Setting hostname to: $HOSTNAME"

echo "$HOSTNAME" > /mnt/etc/hostname

cat > /mnt/etc/hosts <<EOF
127.0.0.1   localhost
::1         localhost
127.0.1.1   ${HOSTNAME}.localdomain ${HOSTNAME}
EOF


# ============================================================================
# INITRAMFS
# ============================================================================

info "Generating initramfs..."

arch-chroot /mnt mkinitcpio -P


# ============================================================================
# USER
# ============================================================================

info "Creating user: $USERNAME"

arch-chroot /mnt \
    useradd \
    -m \
    -G wheel \
    -s /bin/bash \
    "$USERNAME"


# ============================================================================
# PASSWORDS
# ============================================================================

echo
echo "Set the ROOT password:"
echo

arch-chroot /mnt passwd root

echo
echo "Set the password for $USERNAME:"
echo

arch-chroot /mnt passwd "$USERNAME"


# ============================================================================
# SUDO
# ============================================================================

info "Configuring sudo..."

mkdir -p /mnt/etc/sudoers.d

echo '%wheel ALL=(ALL:ALL) ALL' \
    > /mnt/etc/sudoers.d/10-wheel

chmod 440 /mnt/etc/sudoers.d/10-wheel

arch-chroot /mnt visudo -cf /etc/sudoers


# ============================================================================
# NETWORKMANAGER
# ============================================================================

info "Enabling NetworkManager..."

arch-chroot /mnt \
    systemctl enable NetworkManager.service


# ============================================================================
# TIME SYNCHRONIZATION
# ============================================================================

arch-chroot /mnt \
    systemctl enable systemd-timesyncd.service


# ============================================================================
# BLUETOOTH
# ============================================================================

if [[ "$INSTALL_BLUETOOTH" == true ]]; then

    info "Enabling Bluetooth..."

    arch-chroot /mnt \
        systemctl enable bluetooth.service

fi


# ============================================================================
# PRINTING
# ============================================================================

if [[ "$INSTALL_PRINTING" == true ]]; then

    info "Enabling CUPS printing..."

    arch-chroot /mnt \
        systemctl enable cups.service

fi


# ============================================================================
# KDE / SDDM
# ============================================================================

if [[ "$INSTALL_KDE" == true ]]; then

    info "Enabling SDDM graphical login..."

    arch-chroot /mnt \
        systemctl enable sddm.service

fi


# ============================================================================
# SYSTEMD-BOOT
# ============================================================================

info "Installing systemd-boot..."

bootctl \
    --esp-path=/mnt/boot \
    install


# ============================================================================
# ROOT UUID
# ============================================================================

ROOT_UUID=$(blkid -s UUID -o value "$ROOT_PART")

[[ -n "$ROOT_UUID" ]] || \
    error "Unable to determine root filesystem UUID."


# ============================================================================
# SYSTEMD-BOOT LOADER CONFIGURATION
# ============================================================================

mkdir -p /mnt/boot/loader/entries

cat > /mnt/boot/loader/loader.conf <<EOF
default arch.conf
timeout 4
console-mode max
editor no
EOF


# ============================================================================
# ARCH BOOT ENTRY
# ============================================================================

cat > /mnt/boot/loader/entries/arch.conf <<EOF
title   Arch Linux
linux   /vmlinuz-linux
initrd  /initramfs-linux.img
options root=UUID=${ROOT_UUID} rw
EOF


# ============================================================================
# FALLBACK BOOT ENTRY
# ============================================================================

cat > /mnt/boot/loader/entries/arch-fallback.conf <<EOF
title   Arch Linux (fallback initramfs)
linux   /vmlinuz-linux
initrd  /initramfs-linux-fallback.img
options root=UUID=${ROOT_UUID} rw
EOF


# ============================================================================
# VERIFY BOOT FILES
# ============================================================================

info "Checking EFI boot installation..."

bootctl \
    --esp-path=/mnt/boot \
    status || true

echo
echo "Boot entries:"
echo

cat /mnt/boot/loader/entries/arch.conf

echo


# ============================================================================
# FINAL PACKAGE DATABASE UPDATE
# ============================================================================

info "Refreshing package database inside installed system..."

arch-chroot /mnt pacman -Syy


# ============================================================================
# FINISH
# ============================================================================

sync

echo
echo "================================================================="
echo
echo " ARCH LINUX INSTALLATION COMPLETE"
echo
echo "================================================================="
echo
echo
echo "Disk:          $DISK"
echo "EFI:           $ESP_PART"
echo "Root:          $ROOT_PART"
echo "Hostname:      $HOSTNAME"
echo "User:          $USERNAME"
echo "Timezone:      $TIMEZONE"
echo "Locale:        $LOCALE"
echo "Swap:          ${SWAP_GIB} GiB"
echo "KDE Plasma:    $INSTALL_KDE"
echo "Bluetooth:     $INSTALL_BLUETOOTH"
echo "Printing:      $INSTALL_PRINTING"
echo
echo "DO NOT run the script again."
echo
echo "Next:"
echo
echo "    umount -R /mnt"
echo "    reboot"
echo
echo "Remove the Arch USB drive during reboot."
echo
echo "================================================================="

3. Edit these values first

At the very top, pay particular attention to:

DISK="/dev/nvme0n1"
HOSTNAME="archlinux"
USERNAME="archuser"
TIMEZONE="America/Mexico_City"
SWAP_GIB=8
INSTALL_KDE=true

For example, if you want your username to be ben:

USERNAME="ben"

If the internal disk appears as /dev/sda rather than NVMe:

DISK="/dev/sda"

Do not guess the disk name. Run lsblk first.

The timezone shown above is a valid Arch timezone for central Mexico. The installer generates en_US.UTF-8 according to the standard Arch locale procedure. ArchWiki

4. Run it

Save in nano with Ctrl+O, Enter, then Ctrl+X.

Make it executable:

chmod +x arch-install.sh

Then:

./arch-install.sh

The script deliberately requires you to enter something such as:

ERASE /dev/nvme0n1

before partitioning begins.

It will later stop twice so you can securely enter the root password and your normal user’s password.

5. When it finishes

Run:

umount -R /mnt

Then:

reboot

Remove the Arch USB.

If everything has gone correctly, systemd-boot → Arch Linux → SDDM → KDE Plasma should appear. Arch currently recommends plasma-meta as one of the standard ways to install Plasma, and enabling sddm.service provides graphical login. ArchWiki

NetworkManager is enabled, so both Ethernet and Wi-Fi can be managed normally once you reach Plasma. The current Arch NetworkManager package includes wpa_supplicant, so an additional Wi-Fi daemon does not need to be manually enabled. Arch Linux

The script also installs the appropriate Intel or AMD microcode package. Current Arch guidance recommends these updates for both Intel and AMD processors, and modern mkinitcpio can incorporate microcode into the generated initramfs. ArchWiki

One change I would make before you actually run this on your machine is tailor the installation to your hardware—particularly NVIDIA vs AMD/Intel graphics, laptop vs desktop, SSD/NVMe layout, and whether Windows should be preserved. If this is going onto one of your existing Windows/Nobara computers, I would use a hardware-specific version rather than blindly running the generic full-disk installer above.