Arch Linux ARM: Headless RPi 400 Workstation

A guide for a “SD-Safe,” high-performance headless Wayland environment (Sway + WayVNC) with Mesh VPN (Netbird) and ZRAM optimization.

Phase 1: Disk Preparation

Assuming /dev/sda is your SD card on the host machine.

# 1. Wipe and Partition
wipefs -a /dev/sda
fdisk /dev/sda
# [o] (New table)
# [n, p, 1, +512M, t, c] (Boot partition - W95 FAT32)
# [n, p, 2, default, default] (Root partition)
# [w] (Write)

# 2. Format and Mount
mkfs.vfat -F 32 /dev/sda1
mkfs.ext4 /dev/sda2
mount /dev/sda2 /mnt
mkdir -p /mnt/boot
mount /dev/sda1 /mnt/boot

# 3. Base Install
pacstrap -K /mnt base base-devel linux-rpi linux-rpi-headers \
         raspberrypi-bootloader fish openssh nano sudo git \
         base-devel less

Phase 2: System Configuration (Chroot)

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

arch-chroot /mnt

# 1. Locale & Time
ln -sf /usr/share/zoneinfo/Europe/Stockholm /etc/localtime
echo "en_GB.UTF-8 UTF-8" > /etc/locale.gen
locale-gen
echo "LANG=en_GB.UTF-8" > /etc/locale.conf

# 2. Identity
echo "bohrg" > /etc/hostname
passwd # Set root pass

# 3. User setup
useradd -m -G wheel -s /usr/bin/fish jonas
passwd jonas
# visudo -> uncomment %wheel ALL=(ALL:ALL) NOPASSWD: ALL

# 4. Networking (Wired DHCP)
cat <<EOF > /etc/systemd/network/20-wired.network
[Match]
Name=en*
[Network]
DHCP=yes
EOF

systemctl enable systemd-networkd systemd-resolved sshd
exit
umount -R /mnt

Phase 3: First Boot & Keyring Rescue

Boot the Pi, SSH in.

# 1. Fix DNS link
sudo ln -sf /run/systemd/resolve/stub-resolv.conf /etc/resolv.conf

# 2. Fix the "Time Warp" (Crucial for GPG)
sudo timedatectl set-ntp true
# Wait for: "System clock synchronized: yes"

# 3. Seed Keyring
sudo sed -i 's/SigLevel    = Required DatabaseOptional/SigLevel = Never/' /etc/pacman.conf
sudo pacman -Sy archlinuxarm-keyring --noconfirm
sudo sed -i 's/SigLevel = Never/SigLevel = Required DatabaseOptional/' /etc/pacman.conf

sudo pacman-key --init
sudo pacman-key --populate archlinuxarm
sudo pacman -Syu

Phase 4: Remote Access (Netbird & Yay)


# 1. Get Yay
git clone https://aur.archlinux.org/yay-bin.git
cd yay-bin && makepkg -si && cd ..

# 2. Netbird
yay -S netbird-bin
sudo systemctl enable --now netbird@main
sudo netbird up # Follow URL to auth

Phase 5: SD Longevity & Performance Hardening

1. File System Optimization (/etc/fstab)

Edit /etc/fstab to use RAM for tmp and high-performance options for SD:

# Root: noatime, long commit, and writeback mode
UUID=<ROOT_UUID>  /      ext4  rw,noatime,commit=60,data=writeback,barrier=0  0 1
# Boot: noatime and flush for reliable config saving
UUID=<BOOT_UUID>  /boot  vfat  rw,noatime,flush,errors=remount-ro             0 2
# RAM Temp
tmpfs             /tmp   tmpfs defaults,noatime,mode=1777                    0 0

2. Hardware & Boot Optimizations

Edit /boot/config.txt:

gpu_mem=16
arm_boost=1
boot_delay=0
disable_splash=1
hdmi_ignore_hotplug=1
hdmi_blanking=1
camera_auto_detect=0
display_auto_detect=0
dtoverlay=disable-wifi
dtoverlay=disable-bt
dtoverlay=vc4-kms-v3d

Edit /boot/cmdline.txt (All on ONE line):

root=/dev/mmcblk0p2 rw rootwait console=serial0,115200 console=tty1 fsck.repair=yes quiet loglevel=3 ipv6.disable=1 rootflags=data=writeback

3. ZRAM & Volatile Logs

sudo pacman -S zram-generator
# Edit /etc/systemd/zram-generator.conf:
# [zram0]
# zram-size = min(ram / 2, 2048)
# compression-algorithm = zstd

sudo mkdir -p /etc/systemd/journald.conf.d
echo -e "[Journal]\nStorage=volatile\nRuntimeMaxUse=64M" | sudo tee /etc/systemd/journald.conf.d/volatile-logs.conf

sudo reboot
sudo rm -rf /var/log/journal/*

Phase 6: Headless GUI (Sway + WayVNC)

sudo pacman -S sway wayvnc mesa-utils foot fuzzel waybar \
               ttf-firacode-nerd noto-fonts-emoji starship pacman-contrib

# 1. Enable Linger
sudo loginctl enable-linger jonas

# 2. User Service (~/.config/systemd/user/sway-headless.service)
[Unit]
Description=Sway Headless Session
After=network-online.target

[Service]
Type=simple
Environment=XDG_RUNTIME_DIR=/run/user/%U
Environment=WLR_BACKENDS=headless
Environment=WLR_LIBINPUT_NO_DEVICES=1
ExecStart=/usr/bin/sway
Restart=always

[Install]
WantedBy=default.target

systemctl --user enable --now sway-headless

Phase 7: Finishing Touches

# 1. Shell
echo "starship init fish | source" >> ~/.config/fish/config.fish

# 2. Auto-clean Package Cache
sudo systemctl enable --now paccache.timer


Final “Sanity” Thoughts

Tip for the future: If I ever notice wayvnc feeling sluggish, I can add -r (for relaxed rendering) to the wayvnc command in your Sway config, but over a Netbird connection in the same country, the default performance should be crisp.