A base install boots to a console and nothing else. There is no display manager, no desktop, no driver auto-installer and no daemon quietly fixing things behind you. Everything below is a step you take deliberately, in order.
The order matters more than any single command here. A device whose
driver was never loaded does not exist as far as the rest of the system
is concerned - it has no interface name, no /dev node, and
every tool that looks for it correctly reports that it is not there.
Most "my wifi does not work" and "X will not start" reports are really
"the driver never loaded", one layer further down than where the error
appeared.
Do this before touching networking or graphics.
Most wireless cards, and every modern GPU, need a firmware blob the
kernel loads into the device at probe time. The kernel module alone is
not enough: without the blob the driver loads, fails to bring the
hardware up, and logs the failure to dmesg where nothing
else looks.
scraps add linux-firmware # ~390 MB installed - Intel/Atheros/Realtek wifi, AMD/Intel GPU scraps add wireless-regdb # regulatory database, see "regulatory domain" below
eudev is the device manager. Its daemon,
udevd, reacts to new uevents - a device plugged in
while the system is running. Hardware that was already present at boot
announced itself before any daemon was listening, so those events have
to be replayed once at startup. That replay is the coldplug pass, and it
is what actually loads drivers for the hardware already in the machine.
scraps add eudev # both services want to be enabled: the daemon, and the coldplug pass : > /etc/scraplinux/services/udevd : > /etc/scraplinux/services/udev-trigger # regenerate the service files for whichever init is running scraplinux-init-setup s66 # or: busybox, openrc, runit, dinit, nitro
Verify all three of these before moving on. If udevadm
does not run, nothing below it can work:
udevadm --version # must print a version lsmod | grep -i iwlwifi # your driver, loaded ip link # your interface, present
If ip link shows only lo, no driver is
loaded. Load one by hand and read why it did or did not take:
doas modprobe iwlwifi # or ath9k, rtw88, mt76 - whatever the card is dmesg | tail -40 # firmware loaded? rejected? missing? lspci -nnk | grep -iA3 network # what the card actually is, and which driver claims it
A module that inserts cleanly but still produces no interface is
almost always a missing firmware blob - dmesg names the
file it wanted.
Nothing here works until ip link shows the interface.
If it does not, go back to the previous section.
ip link set eth0 up udhcpc -i eth0 # busybox DHCP client
rc.d/network does exactly this on every boot, picking
the first non-loopback, non-wireless interface it finds.
wifi-connect # scan, pick a network, enter the passphrase wifi-connect <ssid> <psk> # no prompts wifi-connect scan
On success it writes the SSID, passphrase and interface to
/etc/scraplinux/network.conf, and rc.d/wifi
reconnects from that file on every subsequent boot.
The same thing wifi-connect does, one step at a time:
iw dev # confirm the wireless interface exists ip link set wlan0 up wpa_passphrase '<ssid>' '<psk>' > /etc/wpa_supplicant.conf wpa_supplicant -B -i wlan0 -c /etc/wpa_supplicant.conf udhcpc -i wlan0
With no regulatory database the kernel stays in world domain
00, where most 5 GHz channels are receive-only. The access
point appears in a scan and the card is then forbidden to transmit to
it - which looks exactly like a wrong passphrase.
scraps add wireless-regdb WIFI_COUNTRY=US wifi-connect # set a country code for one run
Both X11 and Wayland need permission to open the GPU and the input
devices. On systemd distributions logind hands that out; here it is
seatd (small, recommended) or elogind (the
logind fork, if something you run expects its D-Bus interface).
scraps add seatd : > /etc/scraplinux/services/seatd scraplinux-init-setup s66 # your user needs to be in these groups doas usermod -aG seat,video,input <user>
Log out and back in afterwards - group membership is read at login, so a shell you were already sitting in will not have it.
scraps add xorg-server xorg-xinit xf86-input-libinput mesa libglvnd scraps add ttf-dejavu # X with no fonts starts and looks broken
xf86-input-libinput is not optional. Without it the X
server starts, draws, and has no keyboard or mouse driver at all - a
running session you cannot type into, which reads as a freeze.
Pick a window manager and tell startx to run it. The
last line of .xinitrc is the session: when it exits, X
exits.
scraps add dwm dmenu st # or: openbox, icewm, xfwm4 printf '#!/bin/sh\nexec dwm\n' > ~/.xinitrc chmod +x ~/.xinitrc startx
If X dies immediately, the reason is in the log, not on the console:
grep -E '\(EE\)|\(WW\)' /var/log/Xorg.0.log
A Wayland compositor is the display server and the window manager at
once, so there is no startx equivalent - you run the
compositor directly.
scraps add wayland scraps add dwl # or: labwc, niri, sway, swayfx, hyprland, i3wl scraps add foot fuzzel waybar mako # terminal, launcher, bar, notifications
Wayland requires XDG_RUNTIME_DIR - it is where the
compositor puts its socket. On systemd distributions logind creates it
at login. Here, if you are not running elogind, nothing does, and every
compositor exits immediately with a message about the runtime
directory. Set it before launching:
export XDG_RUNTIME_DIR=/run/user/$(id -u) mkdir -p "$XDG_RUNTIME_DIR" chmod 700 "$XDG_RUNTIME_DIR"
Put those three lines in your shell profile rather than retyping them. Then start the compositor:
dwl # bare dbus-run-session dwl # with a session bus dbus-run-session dwl -s ~/.config/dwl/autostart.sh # and a startup script
Wrap it in dbus-run-session if you want a notification
daemon, a system tray, or anything else that talks over the session bus
- without one, mako and tray applets start and then find
nothing to talk to.
i3wl is a prebuilt option here: a dwl fork with
i3-style tiling, a tray and a status bar, shipped with its own
launcher.
scraps add i3wl i3wl # wraps dbus-run-session itself
In order. Each step is only worth attempting once the one above it is true.
udevadm --version | device manager works at all |
lsmod | the driver for your hardware is loaded |
ip link | the network interface exists |
ping -c1 1.1.1.1 | routing and DHCP work |
ls /dev/dri | the GPU node exists |
echo $XDG_RUNTIME_DIR | set, for Wayland |