Artix Linux Workstation with Dinit and Sway

Updated April 06, 2026 9 minutes

This guide documents setting up Artix Linux with dinit on a ThinkPad X1 Carbon laptop. Artix is an Arch-based distribution that does not use systemd. This setup includes full disk encryption with LUKS + LVM (including encrypted /boot), a sway Wayland desktop managed by Nix home-manager (sway-home), and a setup for development with rootless Podman containers and libvirt QEMU virtual machines.

Hardware

  • ThinkPad X1 Carbon (i7-10610U, 16GB RAM)
  • 1TB NVMe SSD (/dev/nvme0n1)

Partition Layout

/dev/nvme0n1   - 1TB NVMe SSD with GPT partition table
/dev/nvme0n1p1 - EFI System Partition (ESP), 1 GB, FAT32 (unencrypted)
/dev/nvme0n1p2 - LUKS encrypted → LVM container
  ├── lvm-volBoot - /boot, 1 GB
  ├── lvm-volSwap - swap, 16 GB
  └── lvm-volRoot - / root (remaining ~935 GB)

Only the ESP is unencrypted (required by UEFI firmware). Everything else including /boot is inside the LUKS container. On boot, you enter your LUKS passphrase twice: once for GRUB (to read /boot) and once for the initramfs encrypt hook (to mount root).

Create Bootable USB

Download the base ISO and write it with Fedora Media Writer or dd:

  • ISO: artix-base-dinit-20260402-x86_64.iso
  • Mirror: https://mirror.math.princeton.edu/pub/artixlinux/

Boot Live Environment

Login as artix with password artix.

Connect to WiFi

sudo nmtui

Select “Activate a connection” and configure WiFi.

Enable SSH

sudo dinitctl start sshd

Find the IP address:

ip a

SSH in from another machine (password artix):

ssh artix@<ip-address>
sudo su

Disk Partitioning

Install Dependencies

pacman -Sy --noconfirm gptfdisk parted cryptsetup lvm2 dosfstools

Set Variables

List available disks and identify your target drive:

lsblk -d -o NAME,SIZE,MODEL

Set your disk and partition prefix as environment variables. NVMe drives use a p separator (e.g. nvme0n1p1), while other drives don’t (e.g. vda1, sda1):

DISK=/dev/nvme0n1
PART=${DISK}p     # for NVMe: /dev/nvme0n1p1, /dev/nvme0n1p2
# DISK=/dev/vda
# PART=${DISK}    # for virtio/SATA: /dev/vda1, /dev/vda2

Erase the Disk

WARNING: This destroys all data on the target disk.

sgdisk --zap-all ${DISK}
blkdiscard ${DISK}

This wipes the partition table and TRIMs the entire SSD. LUKS encryption makes remaining data inaccessible. A full dd if=/dev/urandom overwrite is unnecessary for a fresh install and would add significant SSD wear.

Create Partitions

parted -s ${DISK} mklabel gpt

# EFI System Partition (1 GB)
parted -s -a optimal ${DISK} mkpart "ESP" fat32 0% 1024MiB
parted -s ${DISK} set 1 esp on

# LUKS partition (rest of disk)
parted -s -a optimal ${DISK} mkpart "LUKS" ext4 1024MiB 100%
parted -s ${DISK} set 2 lvm on

parted -s ${DISK} print

Setup Encryption and Logical Volumes

LUKS Setup

cryptsetup benchmark  # loads kernel crypto modules

cryptsetup --verbose --type luks1 --cipher serpent-xts-plain64 --key-size 512 \
  --hash sha512 --iter-time 10000 --use-random --verify-passphrase luksFormat ${PART}2

cryptsetup luksOpen ${PART}2 lvm-system

LVM Setup

pvcreate /dev/mapper/lvm-system
vgcreate lvmSystem /dev/mapper/lvm-system

lvcreate --contiguous y --size 1G lvmSystem --name volBoot
lvcreate --contiguous y --size 16G lvmSystem --name volSwap
lvcreate --contiguous y --extents +100%FREE lvmSystem --name volRoot

Format Partitions

mkfs.fat -F32 -n ESP ${PART}1
mkfs.ext4 -L BOOT /dev/lvmSystem/volBoot
mkswap -L SWAP /dev/lvmSystem/volSwap   # note the UUID printed here
mkfs.ext4 -L ROOT /dev/lvmSystem/volRoot

Mount Partitions

swapon /dev/lvmSystem/volSwap
mount /dev/lvmSystem/volRoot /mnt
mkdir /mnt/boot
mount /dev/lvmSystem/volBoot /mnt/boot
mkdir /mnt/boot/efi
mount ${PART}1 /mnt/boot/efi

Install Base System

basestrap /mnt base base-devel dinit elogind-dinit
basestrap /mnt linux-hardened linux-hardened-headers linux-firmware
basestrap /mnt lvm2 lvm2-dinit cryptsetup cryptsetup-dinit device-mapper-dinit
basestrap /mnt grub efibootmgr dosfstools
basestrap /mnt networkmanager networkmanager-dinit
basestrap /mnt openssh openssh-dinit
basestrap /mnt nano vi less

System Configuration

Copy WiFi config from live environment

cp -r /etc/NetworkManager/system-connections /mnt/etc/NetworkManager/

Generate fstab

fstabgen -U /mnt >> /mnt/etc/fstab

Enable TRIM for SSD:

sed -i "s/relatime/relatime,discard/g" /mnt/etc/fstab

tmpfs for /tmp (8G = half RAM):

echo 'tmpfs    /tmp    tmpfs    rw,nosuid,nodev,relatime,size=8G,mode=1777    0 0' >> /mnt/etc/fstab

chroot

artix-chroot /mnt /bin/bash --login

You may see tty: ttyname error: No such device — this is harmless and can be ignored.

Re-set the variables from earlier (these are lost when entering the chroot):

DISK=/dev/nvme0n1
PART=${DISK}p     # NVMe; use PART=${DISK} for virtio/SATA
export USERNAME=ryan  # set your desired username

Set root password

passwd

Initialize keyring

pacman -Sy --noconfirm
pacman-key --init
pacman-key --populate artix

Locale

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

Timezone

ln -sf /usr/share/zoneinfo/US/Mountain /etc/localtime
hwclock --systohc

Hostname

echo "yourhostname" > /etc/hostname

Remap Caps Lock to Control

# Console/TTY
echo -e 'include "/usr/share/kbd/keymaps/i386/qwerty/us.map.gz"\nkeycode 58 = Control' > /usr/share/kbd/keymaps/personal.map
echo 'KEYMAP=personal' > /etc/vconsole.conf

# X11
mkdir -p /etc/X11/xorg.conf.d
cat > /etc/X11/xorg.conf.d/00-keyboard.conf <<'EOF'
Section "InputClass"
    Identifier "system-keyboard"
    MatchIsKeyboard "on"
    Option "XkbLayout" "us"
    Option "XkbOptions" "ctrl:nocaps"
EndSection
EOF

Wayland compositors (sway, etc.) need their own config added later.

Disable XON/XOFF flow control

Prevents Ctrl+S from freezing the terminal:

echo 'stty -ixon' >> /etc/profile

mkinitcpio

sed -i 's/^HOOKS=.*/HOOKS=(base udev autodetect microcode modconf block encrypt keyboard keymap consolefont lvm2 resume filesystems fsck)/' /etc/mkinitcpio.conf
mkinitcpio -p linux-hardened

GRUB Configuration

LUKS_UUID=$(blkid -s UUID -o value ${PART}2)
SWAP_UUID=$(blkid -s UUID -o value /dev/lvmSystem/volSwap)

sed -i "s/^GRUB_CMDLINE_LINUX_DEFAULT=.*/GRUB_CMDLINE_LINUX_DEFAULT=\"cryptdevice=UUID=${LUKS_UUID}:lvm-system:allow-discards loglevel=3 quiet resume=UUID=${SWAP_UUID} net.ifnames=0\"/" /etc/default/grub

echo 'GRUB_ENABLE_CRYPTODISK="y"' >> /etc/default/grub
sed -i 's/^GRUB_TIMEOUT=.*/GRUB_TIMEOUT="15"/' /etc/default/grub
sed -i 's/^GRUB_TIMEOUT_STYLE=.*/GRUB_TIMEOUT_STYLE="menu"/' /etc/default/grub
sed -i 's/^GRUB_GFXMODE=.*/GRUB_GFXMODE="auto"/' /etc/default/grub

GRUB Installation (UEFI)

grub-install --target=x86_64-efi --efi-directory=/boot/efi --bootloader-id=artix --recheck
grub-install --target=x86_64-efi --efi-directory=/boot/efi --removable  # fallback
grub-mkconfig -o /boot/grub/grub.cfg

Enable Services (dinit)

The dinitctl --offline enable command is broken on the 20260402 live ISO, so services are enabled by creating symlinks directly:

ln -s /etc/dinit.d/lvm2 /etc/dinit.d/boot.d/
ln -s /etc/dinit.d/NetworkManager /etc/dinit.d/boot.d/
ln -s /etc/dinit.d/elogind /etc/dinit.d/boot.d/
ln -s /etc/dinit.d/dbus /etc/dinit.d/boot.d/
ln -s /etc/dinit.d/sshd /etc/dinit.d/boot.d/

Optional services

pacman -S --noconfirm openntpd openntpd-dinit syslog-ng syslog-ng-dinit acpid acpid-dinit cronie cronie-dinit
ln -s /etc/dinit.d/ntpd /etc/dinit.d/boot.d/
ln -s /etc/dinit.d/syslog-ng /etc/dinit.d/boot.d/
ln -s /etc/dinit.d/acpid /etc/dinit.d/boot.d/
ln -s /etc/dinit.d/cronie /etc/dinit.d/boot.d/

Useful packages

pacman -S --noconfirm bash-completion lsof strace wget htop zip unzip p7zip unrar
pacman -S --noconfirm hdparm smartmontools hwinfo dmidecode
pacman -S --noconfirm rsync nmap inetutils net-tools whois

Create User Account

: ${USERNAME:?must be set}
useradd -m -G wheel -s /bin/bash ${USERNAME}
passwd ${USERNAME}

Enable sudo for the wheel group:

EDITOR=nano visudo

Uncomment the line: %wheel ALL=(ALL:ALL) ALL

Finish Installation

Exit the chroot:

exit

Then unmount and reboot:

umount -R /mnt
swapoff -a
vgchange -an lvmSystem
cryptsetup luksClose lvm-system
sync
reboot

First Boot

SSH in with the username and password you set during install:

ssh ${USERNAME}@<ip-address>
sudo pacman -Syu --noconfirm

Verify mkinitcpio hooks survived the upgrade:

grep "^HOOKS" /etc/mkinitcpio.conf
# Should contain: encrypt lvm2 resume
# If not, re-add them and run: mkinitcpio -p linux-hardened

Disable SSH Password Authentication

Copy your SSH public key to the machine, then disable password login:

ssh-copy-id ${USERNAME}@<ip-address>
sudo sed -i 's/^#\?PasswordAuthentication.*/PasswordAuthentication no/' /etc/ssh/sshd_config
sudo dinitctl restart sshd

If you don’t need SSH running on your laptop, disable it entirely:

sudo dinitctl disable sshd
sudo dinitctl stop sshd

Rootless Podman

sudo pacman -S --noconfirm podman crun slirp4netns fuse-overlayfs
sudo usermod --add-subuids 100000-165535 --add-subgids 100000-165535 ${USERNAME}

# linux-hardened disables unprivileged user namespaces; rootless podman needs them
sudo mkdir -p /etc/sysctl.d
echo 'kernel.unprivileged_userns_clone=1' | sudo tee /etc/sysctl.d/userns.conf
sudo sysctl -w kernel.unprivileged_userns_clone=1

QEMU/libvirt

sudo pacman -S --noconfirm qemu-full virt-manager libvirt libvirt-dinit dnsmasq edk2-ovmf
sudo dinitctl enable libvirtd
sudo dinitctl start libvirtd

User is not added to the libvirt group. virt-manager will prompt for a password via polkit (lxpolkit) when connecting to qemu:///system.

Nix Package Manager

Artix repos don’t have a nix package, so use the single-user install. No daemon or service needed — fine for a personal laptop.

curl -L https://nixos.org/nix/install | sh -s -- --no-daemon

Source the nix profile:

. ~/.nix-profile/etc/profile.d/nix.sh
nix --version

# Make nix available for all login sessions via /etc/profile.d/
sudo ln -s ~/.nix-profile/etc/profile.d/nix.sh /etc/profile.d/nix.sh

Sway Desktop with Nix Home Manager

Install sway and audio stack from pacman (they need system-level access):

sudo pacman -S --noconfirm sway xorg-xwayland dunst libnotify lxsession ttf-font-awesome
sudo pacman -S --noconfirm pipewire pipewire-pulse wireplumber pavucontrol sof-firmware
sudo pacman -S --noconfirm pipewire-dinit wireplumber-dinit
sudo pacman -S --noconfirm xdg-desktop-portal xdg-desktop-portal-gtk xdg-desktop-portal-wlr

Install sway-home

sway-home manages dotfiles and user packages declaratively via Nix home-manager:

sudo pacman -S --noconfirm git just

mv ~/.config ~/.config.orig 2>/dev/null
mv ~/.bashrc ~/.bashrc.orig 2>/dev/null
mv ~/.bash_profile ~/.bash_profile.orig 2>/dev/null

mkdir -p ~/.config/nix
echo 'experimental-features = nix-command flakes' > ~/.config/nix/nix.conf

mkdir -p ~/git/vendor/enigmacurry
git clone https://github.com/enigmacurry/sway-home \
  ~/git/vendor/enigmacurry/sway-home
cd ~/git/vendor/enigmacurry/sway-home
just hm-install

Restart your shell session to pick up the new environment.

User-level dinit for PipeWire

sway-home starts a user-level dinit instance automatically on launch. Set up the user boot service and symlinks so dinit knows what to run:

mkdir -p ~/.config/dinit.d/boot.d
cat > ~/.config/dinit.d/boot <<'EOF'
type = internal
waits-for.d = boot.d
EOF
ln -s /etc/dinit.d/user/dbus ~/.config/dinit.d/boot.d/
ln -s /etc/dinit.d/user/pipewire ~/.config/dinit.d/boot.d/
ln -s /etc/dinit.d/user/wireplumber ~/.config/dinit.d/boot.d/

Create a user dinit service for pipewire-pulse (PulseAudio compatibility):

sudo tee /etc/dinit.d/user/pipewire-pulse <<'EOF'
type = process
command = /usr/bin/pipewire-pulse
depends-on = pipewire
EOF
ln -s /etc/dinit.d/user/pipewire-pulse ~/.config/dinit.d/boot.d/

Login Manager (greetd + tuigreet)

greetd is a minimal login daemon, and tuigreet gives it a clean console TUI where you select your user and session (sway, shell, etc.).

sudo pacman -S --noconfirm greetd greetd-tuigreet greetd-dinit

Configure greetd to use tuigreet with sway as the default session:

sudo tee /etc/greetd/config.toml <<'EOF'
[terminal]
vt = 7

[default_session]
command = "tuigreet --time --remember --remember-session --sessions /usr/share/wayland-sessions"
user = "greeter"
EOF

Create a sway desktop entry so tuigreet can discover it:

sudo mkdir -p /usr/share/wayland-sessions
sudo tee /usr/share/wayland-sessions/sway.desktop <<'EOF'
[Desktop Entry]
Name=Sway
Exec=bash --login -c sway
Type=Application
EOF

Enable and start the service:

sudo dinitctl enable greetd
sudo dinitctl start greetd

You should now see the tuigreet login screen. Select Sway as your session and log in.

First Login to Sway

On first login, sway launches Emacs and Firefox side by side. Emacs needs a one-time setup to finish installing packages:

  1. In Emacs, run M-x my/machine-labels-enable-all
  2. Close Emacs with C-x C-c
  3. Relaunch Emacs from rofi (Super+d, type emacs)
  4. Wait for Emacs to finish installing packages (~5 minutes)

Flatpak

Flatpak is a sandboxed package manager for desktop Linux apps. It runs apps in isolated containers with their own dependencies, so they work across any distro. Browse and install apps from Flathub, the main Flatpak app store.

sudo pacman -S --noconfirm flatpak
flatpak remote-add --if-not-exists flathub https://dl.flathub.org/repo/flathub.flatpakrepo

Log out and back in so XDG_DATA_DIRS picks up the Flatpak path from /etc/profile.d/flatpak.sh. Then install apps by their Flathub app ID:

flatpak install flathub org.fedoraproject.MediaWriter
flatpak install flathub io.github.kolunmi.Bazaar

Using Sway

Sway is a tiling Wayland compositor with vim-style keybindings. The modifier key ($mod) is Super (the Windows/Logo key). Here are the essential shortcuts:

Shortcut Action
$mod+Enter Open terminal
$mod+d App launcher (rofi)
$mod+Shift+q Kill focused window
$mod+h/j/k/l Focus left/down/up/right
$mod+Shift+h/j/k/l Move window left/down/up/right
$mod+1$mod+9 Switch to workspace 1–9
$mod+Shift+1$mod+Shift+9 Move window to workspace 1–9
$mod+b Split horizontal
$mod+v Split vertical
$mod+f Toggle fullscreen
$mod+Shift+Space Toggle floating
$mod+Shift+c Reload sway config
$mod+Shift+e Exit sway

See the Sway wiki for the full documentation, and man 5 sway for config file reference.

Troubleshooting

“device ‘/dev/mapper/lvmSystem-volRoot’ not found. Skipping fsck.”

The encrypt hook was lost from /etc/mkinitcpio.conf (can happen after upgrades). Boot from live USB, decrypt and mount, chroot, re-add encrypt to HOOKS, and run mkinitcpio -p linux-hardened.

Recovery from Live USB

sudo su
cryptsetup benchmark
cryptsetup luksOpen ${PART}2 lvm-system
vgchange -ay lvmSystem
mount /dev/lvmSystem/volRoot /mnt
mount /dev/lvmSystem/volBoot /mnt/boot
mount ${PART}1 /mnt/boot/efi
artix-chroot /mnt /bin/bash

Appendix: Installing in a VM

This guide targets bare metal, but you can also test it in a VM. When creating a VM in virt-manager, check Customize configuration before install. In the overview screen, change the Firmware to OVMF_CODE.fd (UEFI without Secure Boot). Do not use OVMF_CODE.secboot.fd as Artix does not support Secure Boot. The host needs edk2-ovmf installed (pacman -S edk2-ovmf).



You can discuss this blog on Matrix (Element): #blog-rymcg-tech:enigmacurry.com

This blog is copyright EnigmaCurry and dual-licensed CC-BY-SA and MIT. The source is on github: enigmacurry/blog.rymcg.tech and PRs are welcome. ❤️