Personal reference, but feel free to steal it. UEFI + GPT + btrfs subvolumes on linux-zen. NVMe optimized. dinit as PID 1, no systemd anywhere.
Warning
Everything gets wiped. Run lsblk first and confirm your NVMe name - usually /dev/nvme0n1, but verify.
This uses the Artix Linux ISO, not Arch. Same AUR, same packages, same rolling release, no systemd. Download from artixlinux.org.
loadkeys pl
ping -c 1 artixlinux.org
reflector --country Poland,Germany --age 12 --protocol https --sort rate --save /etc/pacman.d/mirrorlistcfdisk /dev/nvme0n1| Partition | Size | Type | Purpose |
|---|---|---|---|
/dev/nvme0n1p1 |
512M | EFI System | ESP - mounted at /boot, kernel lives here |
/dev/nvme0n1p2 |
32G | Linux swap | Hibernation target - match your RAM |
/dev/nvme0n1p3 |
Rest | Linux filesystem | btrfs |
Note
Swap stays even with ZRAM. ZRAM is the fast in-RAM layer, NVMe swap is the hibernation target. You can't hibernate to ZRAM.
mkfs.fat -F32 /dev/nvme0n1p1
mkswap /dev/nvme0n1p2 && swapon /dev/nvme0n1p2
mkfs.btrfs -f -L artix /dev/nvme0n1p3Mount temporarily and create subvolumes:
mount /dev/nvme0n1p3 /mnt
btrfs subvolume create /mnt/@
btrfs subvolume create /mnt/@home
btrfs subvolume create /mnt/@opt
btrfs subvolume create /mnt/@var_log
btrfs subvolume create /mnt/@pkg
btrfs subvolume create /mnt/@snapshots
umount /mntNote
/var stays inside @ so rollbacks stay consistent. Only /var/log and /var/cache/pacman/pkg are separate - logs and package cache should survive a snapshot restore.
Mount with NVMe-optimized options:
mount -o noatime,compress=zstd:1,ssd,discard=async,space_cache=v2,subvol=@ /dev/nvme0n1p3 /mntNote
compress=zstd:1 - level 1 instead of default 3. On fast NVMe the CPU is the compression bottleneck, not I/O. Level 1 gives ~80% of the savings at 2-3x the throughput.
mkdir -pv /mnt/{boot,home,opt,.snapshots}
mkdir -pv /mnt/var/log /mnt/var/cache/pacman/pkg
mount /dev/nvme0n1p1 /mnt/boot
mount -o noatime,compress=zstd:1,ssd,discard=async,space_cache=v2,subvol=@home /dev/nvme0n1p3 /mnt/home
mount -o noatime,compress=zstd:1,ssd,discard=async,space_cache=v2,subvol=@opt /dev/nvme0n1p3 /mnt/opt
mount -o noatime,compress=zstd:1,ssd,discard=async,space_cache=v2,subvol=@var_log /dev/nvme0n1p3 /mnt/var/log
mount -o noatime,compress=zstd:1,ssd,discard=async,space_cache=v2,subvol=@pkg /dev/nvme0n1p3 /mnt/var/cache/pacman/pkg
mount -o noatime,compress=zstd:1,ssd,discard=async,space_cache=v2,subvol=@snapshots /dev/nvme0n1p3 /mnt/.snapshots
lsblk -fgrep -m1 "vendor_id" /proc/cpuinfo # GenuineIntel or AuthenticAMDNote
Artix uses basestrap instead of pacstrap.
Intel:
basestrap /mnt base base-devel linux-zen linux-zen-headers linux-firmware \
intel-ucode sudo btrfs-progs reflector nvim \
dinit elogind-dinit \
networkmanager networkmanager-dinit \
cronie cronie-dinit \
boosterAMD:
basestrap /mnt base base-devel linux-zen linux-zen-headers linux-firmware \
amd-ucode sudo btrfs-progs reflector nvim \
dinit elogind-dinit \
networkmanager networkmanager-dinit \
cronie cronie-dinit \
boosterTip
Why linux-zen? Lower-latency scheduler, better for desktop and real-time workloads than vanilla linux.
Important
NVIDIA: Use nvidia-dkms, not nvidia. The nvidia package only builds against linux, the module won't exist on linux-zen.
basestrap /mnt nvidia-dkms nvidia-utilsAdd to /etc/booster.yaml after chroot:
modules_force_load: nvidia,nvidia_modeset,nvidia_uvm,nvidia_drmNote
Artix uses fstabgen instead of genfstab.
fstabgen -U /mnt >> /mnt/etc/fstab
cat /mnt/etc/fstab # verify all subvolumes and UUIDs
echo 'tmpfs /tmp tmpfs rw,nosuid,nodev,relatime,size=4G,mode=1777 0 0' >> /mnt/etc/fstabartix-chroot /mnt /bin/bashnvim /etc/locale.gen # uncomment pl_PL.UTF-8 UTF-8
locale-gen
echo LANG=pl_PL.UTF-8 > /etc/locale.conf
echo KEYMAP=pl > /etc/vconsole.conf
ln -sf /usr/share/zoneinfo/Europe/Warsaw /etc/localtime
hwclock --systohc --utc
echo HP-Zbook > /etc/hostnameln -s /etc/dinit.d/NetworkManager /etc/dinit.d/boot.d/pacman -S artix-archlinux-supportAdd to /etc/pacman.conf after [galaxy]:
[extra]
Include = /etc/pacman.d/mirrorlist-arch
[multilib]
Include = /etc/pacman.d/mirrorlist-archImportant
Artix repos (system, world, galaxy) must always be above Arch repos in pacman.conf. Never enable Arch's [core] - it's replaced by [system] and will break everything.
pacman -SyNo reflector.timer without systemd, use cronie:
ln -s /etc/dinit.d/cronie /etc/dinit.d/boot.d/
echo '@weekly root /usr/bin/reflector --country Poland,Germany --age 12 --protocol https --sort rate --save /etc/pacman.d/mirrorlist' >> /etc/cron.d/reflectorpacman-key --recv-key 3056513887B78AEB --keyserver keyserver.ubuntu.com
pacman-key --lsign-key 3056513887B78AEB
pacman -U 'https://cdn-mirror.chaotic.cx/chaotic-aur/chaotic-keyring.pkg.tar.zst'
pacman -U 'https://cdn-mirror.chaotic.cx/chaotic-aur/chaotic-mirrorlist.pkg.tar.zst'Add to /etc/pacman.conf below Artix repos, above Arch:
[chaotic-aur]
Include = /etc/pacman.d/chaotic-mirrorlistpacman -SyReplaces mkinitcpio. Written in Go, faster generation, leaner early userspace, auto-embeds CPU microcode - no separate ucode entry needed in the bootloader.
nvim /etc/booster.yamlcompression: zstd
extra_files: busybox,fsck,fsck.btrfsNote
Booster runs automatically via pacman hook on install and every kernel update. No manual build needed.
No bootloader at all. UEFI loads the kernel directly. ESP is mounted at /boot so vmlinuz and initrd sit on the FAT32 partition and UEFI can read them natively.
Get your UUIDs first:
blkid /dev/nvme0n1p3 # btrfs root - UUID=
blkid /dev/nvme0n1p2 # swap - UUID=Register the boot entry:
efibootmgr -c -d /dev/nvme0n1 -p 1 -L "Artix Linux" \
-l /vmlinuz-linux-zen \
-u "root=UUID=<btrfs-uuid> rootflags=subvol=@ rw rootfstype=btrfs quiet loglevel=3 resume=UUID=<swap-uuid> zswap.enabled=0 initrd=\intel-ucode.img initrd=\booster-linux-zen.img"AMD - swap intel-ucode.img for amd-ucode.img.
Important
NVIDIA + Wayland: Add nvidia-drm.modeset=1 to the -u string.
Verify the entry was created:
efibootmgr -vNote
Secure Boot: Sign the kernel and initrd with sbctl.
sbctl create-keys
sbctl enroll-keys -m
sbctl sign -s /boot/vmlinuz-linux-zen
sbctl sign -s /boot/booster-linux-zen.imgsbctl has a pacman hook that re-signs automatically on kernel updates.
pacman -S zramen zramen-dinit
nvim /etc/zramen.confZRAMEN_SIZE=half
ZRAMEN_ALGO=zstdln -s /etc/dinit.d/zramen /etc/dinit.d/boot.d/Note
half = half your RAM as ZRAM. On 32GB that's 16GB. zstd compresses further so effective capacity is higher. ZRAM gets higher swap priority than NVMe automatically.
Default vm.dirty_ratio=20% on 32GB = ~6GB dirty pages before flush. That destroys desktop latency. Use absolute byte limits instead:
mkdir -p /etc/sysctl.d
cat > /etc/sysctl.d/99-performance.conf << EOF
vm.swappiness=180
vm.page-cluster=0
vm.dirty_background_bytes=67108864
vm.dirty_bytes=268435456
vm.dirty_expire_centisecs=3000
vm.dirty_writeback_centisecs=1500
EOFNote
Background flush starts at 64MB dirty, hard cap at 256MB. On NVMe writing 3-5GB/s this is milliseconds of stall, not seconds.
NVMe has its own internal queue, a software scheduler only adds overhead:
echo 'ACTION=="add|change", KERNEL=="nvme[0-9]*", ATTR{queue/scheduler}="none"' > /etc/udev/rules.d/60-ioscheduler.rulesdiscard=async handles per-op TRIM. Monthly batch as a backup:
echo '@monthly root /usr/bin/fstrim -av' >> /etc/cron.d/fstrimpasswdHandles seat management, power keys, session tracking. Required by Hyprland and most DEs.
ln -s /etc/dinit.d/elogind /etc/dinit.d/boot.d/exit
umount -R /mnt
swapoff /dev/nvme0n1p2
rebootuseradd -m -G wheel,storage,power,audio,video,optical,network -s /bin/bash fixeq
passwd fixeq
EDITOR=nvim visudo # uncomment: %wheel ALL=(ALL:ALL) ALL
sudo pacman -SyuNote
From this point dinit is running as PID 1, so use dinitctl enable instead of manual symlinks - it does the same thing but properly.
sudo pacman -S paruturnstile handles user session activation (replaces systemd --user). dbus needs to run both system-wide and per-user.
sudo pacman -S turnstile turnstile-dinit dbus-dinit dbus-dinit-user
sudo dinitctl enable turnstiledReboot, then enable dbus for both system and user:
sudo dinitctl enable dbus
dinitctl enable dbussudo pacman -S pipewire pipewire-jack pipewire-pulse wireplumber \
pipewire-dinit pipewire-pulse-dinit wireplumber-dinitEnable system-wide and per-user:
sudo dinitctl enable pipewire
dinitctl enable pipewire
sudo dinitctl enable wireplumber
dinitctl enable wireplumber
sudo dinitctl enable pipewire-pulse
dinitctl enable pipewire-pulseparu -S auto-cpufreq
ls /etc/dinit.d/ | grep cpufreq # check if service file existsIf it exists:
sudo dinitctl enable auto-cpufreq
sudo dinitctl start auto-cpufreqIf not, write it manually:
sudo nvim /etc/dinit.d/auto-cpufreqtype = process
command = /usr/bin/auto-cpufreq --daemon
restart = true
sudo dinitctl enable auto-cpufreq
sudo dinitctl start auto-cpufreq
sudo auto-cpufreq --stats| What | Command |
|---|---|
| Enable at boot (daemon running) | dinitctl enable <svc> |
| Enable at boot (from chroot/pre-boot) | ln -s /etc/dinit.d/<svc> /etc/dinit.d/boot.d/ |
| Start now | dinitctl start <svc> |
| Stop | dinitctl stop <svc> |
| Status | dinitctl status <svc> |
| List all | dinitctl list |
| Restart | dinitctl restart <svc> |
Note
sudo dinitctl enable = system service. dinitctl enable without sudo = user service (per-user session).
Monthly via cronie:
echo '@monthly root /usr/bin/btrfs scrub start -B /' >> /etc/cron.d/btrfs-scrubRun manually:
sudo btrfs scrub start / && sudo btrfs scrub status /Run when fragmentation builds up, skip on fresh installs:
sudo btrfs balance start -dusage=50 /sudo btrfs filesystem df /
sudo compsize / # paru -S compsizesudo pacman -S snapper
sudo snapper -c root create-config /
sudo snapper -c root create --description "before update"After restoring a snapshot, rebuild initramfs. no bootloader config update needed:
sudo booster build --force /boot/booster-linux-zen.imgCheck efibootmgr entries:
efibootmgr -v # entry must exist and point to \vmlinuz-linux-zenIf entry is missing, re-register it (see step 7). If entry exists but doesn't boot - wrong UUID in the cmdline string. Delete and recreate:
efibootmgr -B -b <XXXX> # XXXX = boot entry number from efibootmgr -v
# then re-run the efibootmgr -c command from step 7 with correct UUIDsblkid /dev/nvme0n1p2 # UUID must match resume= in your efibootmgr entry
swapon --show # swap must be activeIf UUID is wrong - delete the boot entry and recreate it with the correct one:
efibootmgr -v # find the entry number
efibootmgr -B -b <XXXX>
# re-run efibootmgr -c from step 7 with correct resume=UUIDzramctl
swapon --show
dinitctl status zramenls -la /etc/dinit.d/boot.d/ # symlink must exist
ln -s /etc/dinit.d/<svc> /etc/dinit.d/boot.d/pacman -Q | grep nvidia # must be nvidia-dkms
dkms status
sudo booster build --force /boot/booster-linux-zen.img- Desktop: Hyprland works with elogind out of the box
- GPU drivers:
- AMD:
mesa vulkan-radeon- modesetting is in the kernel, don't installxf86-video-amdgpu - NVIDIA:
nvidia-dkms nvidia-utils lib32-nvidia-utils - Intel:
mesa vulkan-intel intel-media-driver
- AMD:
- Firewall:
ufw ufw-dinit
Done. Go build something.