System Administration
Package Management
krypt/sh has three layers of package management: low-level tools
(addpkg, delpkg, infopkg) that
operate on binary archives and the package database, the build tool
(mkpkg) that compiles ports into packages, and the
high-level manager (pkg) that resolves
dependencies and orchestrates everything.
Binary package tools
| Command | Description |
|---|---|
| addpkg pkg.tar.gz | Install a binary package archive |
| addpkg -u pkg.tar.gz | Upgrade an installed package |
| delpkg name | Remove an installed package |
| infopkg -i | List all installed packages |
| infopkg -l name | List files owned by a package |
| infopkg -o pattern | Find which package owns a file |
Configuration files under /etc are preserved on upgrade by
default. See addpkg.conf(5) for details.
The pkg package manager
| Command | Description |
|---|---|
| pkg add pkg | Install a package and all dependencies |
| pkg update pkg | Update a package to the ports tree version |
| pkg del pkg | Remove an installed package |
| pkg sysup | Update all outdated packages |
| pkg diff | Show version differences (installed vs ports) |
| pkg depends pkg | Show the dependency tree |
| pkg rdepends pkg | Show reverse dependencies |
| pkg autoremove | Remove orphaned dependency packages |
| pkg lock pkg | Prevent a package from being updated |
pkg searches port directories in the order defined in
/etc/pkg.conf. When multiple ports provide the same
package name, the last match wins. See pkg(8)
and pkg.conf(5).
Typical workflow
# Sync the ports tree # ports -u # See what's outdated # pkg diff # Update everything # pkg sysup # Install something new # pkg add firefox # Clean up # pkg autoremove
Reverse dependency checking (revdep)
When a shared library is updated, binaries linked against the old
version will break — the dynamic linker cannot find the previous
.so name. The revdep tool scans every
installed binary and reports packages with broken library links.
Here is a real-world example: upgrading libvpx and
nettle bumps their soname versions. Any package linked
against the old libraries will fail to start:
$ firefox XPCOMGlueLoad error for file /usr/lib/firefox/libxul.so: Error loading shared library libvpx.so.11: No such file or directory Couldn't load XPCOM.
Instead of guessing which packages are affected, run
revdep to find them all:
# 1. Update the libraries # addpkg -u libvpx#1.15.1-1.pkg.tar.gz # addpkg -u nettle#3.10.1-1.pkg.tar.gz # 2. Find every package with broken links # revdep firefox thunderbird ffmpeg mpv rdfind # 3. Clean, rebuild, and upgrade each one # cd /usr/ports/opt/firefox && mkpkg -c && mkpkg -d && addpkg -u firefox#*.pkg.tar.gz # cd /usr/ports/opt/thunderbird && mkpkg -c && mkpkg -d && addpkg -u thunderbird#*.pkg.tar.gz # cd /usr/ports/opt/ffmpeg && mkpkg -c && mkpkg -d && addpkg -u ffmpeg#*.pkg.tar.gz # cd /usr/ports/opt/mpv && mkpkg -c && mkpkg -d && addpkg -u mpv#*.pkg.tar.gz # cd /usr/ports/opt/rdfind && mkpkg -c && mkpkg -d && addpkg -u rdfind#*.pkg.tar.gz # 4. Verify — should produce no output # revdep
Note the use of mkpkg -c (clean) before rebuilding — the package
version has not changed, only its library dependencies have.
Without cleaning first, mkpkg sees the existing binary as current
and skips the build. Clean removes it, forcing a full rebuild.
/lib. A single library bump can silently break
dozens of packages — revdep catches them all in one pass.
Building Ports
Every package in krypt/sh is defined by a MAKEPKG file — a
shell-like recipe that describes how to fetch, build, and package software.
See MAKEPKG(5) for the full specification.
Syncing ports
# Sync all port collections # ports -u # Sync a specific collection # ports -u core # List all available ports # ports -l
Port collections are configured via /etc/ports/*.rsync files
and synced from rsync.krypt.sh. See
ports(8).
Building a package
# Navigate to a port # cd /usr/ports/opt/nftables # Install build dependencies # pkg prepare # Download and build # mkpkg -d # Install the built package # addpkg name#*.pkg.tar.gz # Upgrade an existing package # addpkg -u name#*.pkg.tar.gz
MAKEPKG anatomy
#!/bin/mkpkg
# *** krypt/sh ***
# description: Shows the full path of shell commands
# url: https://www.gnu.org/software/which/
name=which
version=2.21
release=1
depends=()
source=(https://ftp.gnu.org/gnu/$name/$name-$version.tar.gz)
sha256sums=(abc123...)
build() {
cd $name-$version
./configure --prefix=/
make
make DESTDIR=$PKG install
}
Key arrays: depends=() for runtime dependencies,
makedeps=() for build-time dependencies,
groups=() for declarative user/group creation,
services=() for runit service enablement, and
permissions=() for file ownership. Note:
krypt/sh uses makedeps=(), not makedepends=().
Build configuration
Compiler flags and build settings live in /etc/mkpkg.conf.
Only the shell(), build(), and
post_build() hooks source this file — extract()
and patch() do not need build flags so they skip it.
See mkpkg.conf(5).
Services & Init
krypt/sh uses runit as its init system with a vanilla
setup. The supervised service directory is /service —
not /var/service like some other distributions.
Service definitions live in /etc/sv/ and are activated
by symlinking into /service/.
That said, krypt/sh is not bound to runit. The ports tree ships it as the default, but you are free to build and use the init system of your choice — the system has no hard dependency on any specific init.
Managing services
# Enable a service # ln -s /etc/sv/dhcpcd /service/ # Check status # sv status dhcpcd # Stop / start / restart # sv stop dhcpcd # sv start dhcpcd # sv restart dhcpcd # Disable a service # rm /service/dhcpcd # List enabled services # ls /service/ # List available services # ls /etc/sv/
Service file structure
Each service directory under /etc/sv/ contains a
run script and optionally a log/run
for logging via svlogd. Packages that ship runit
services declare them in the services=() array of
their MAKEPKG file, and addpkg creates the
/service symlink automatically.
Example: simple daemon
A typical service run script for a daemon like dhcpcd:
#!/bin/sh exec 2>&1 exec dhcpcd -B -M
The corresponding log script sends output to svlogd:
#!/bin/sh mkdir -p /var/log/dhcpcd exec svlogd -tt /var/log/dhcpcd
Example: nftables (one-shot)
Services that load configuration and exit (like a firewall) use a
finish script and sv once:
#!/bin/sh exec 2>&1 nft -f /etc/nftables.conf exec pause
Example: seatd with cleanup
Services that create runtime files can use a finish script for cleanup:
#!/bin/sh exec 2>&1 exec seatd -g seat
#!/bin/sh rm -f /run/seatd.sock
run, finish, and
log/run scripts must be executable (chmod 755).
Daemons should run in the foreground — runit supervises the process directly.
Use exec so the daemon replaces the shell process.
Networking
krypt/sh uses simple, traditional networking tools — no NetworkManager,
no systemd-networkd. Network interfaces are configured through
dhcpcd for DHCP, manual ip commands or
boot scripts for static addressing, and wpa_supplicant
for WiFi. All network services run under runit supervision.
Static IP
For a static IP configuration, create a boot script that brings up
the interface. This runs at boot via the /etc/boot.d/
mechanism:
#!/bin/sh ip addr add 192.168.1.100/24 dev eth0 ip link set eth0 up ip route add default via 192.168.1.1
Make it executable with chmod +x /etc/boot.d/network.
Note that krypt/sh uses net.ifnames=0 on the kernel
command line by default, so interfaces use classic names like
eth0 and wlan0 rather than predictable
names like enp3s0.
DHCP
dhcpcd handles DHCP for both wired and wireless
interfaces. Enable it as a runit service:
# Enable the dhcpcd service # ln -s /etc/sv/dhcpcd /service/ # Check it's running # sv status dhcpcd # Or run manually for a specific interface # dhcpcd eth0
By default, dhcpcd will configure all available
interfaces. To restrict it to a specific interface, edit
/etc/dhcpcd.conf and add
allowinterfaces eth0.
WiFi (wpa_supplicant)
WiFi is handled by wpa_supplicant. For a persistent
setup that survives reboots, create a configuration file and a
runit service.
First, generate the configuration:
# Generate a config with your network credentials # wpa_passphrase "MyNetwork" "MyPassword" > /etc/wpa_supplicant.conf # Verify it looks right # cat /etc/wpa_supplicant.conf
Then create a runit service to start it at boot:
#!/bin/sh exec 2>&1 exec wpa_supplicant -i wlan0 -c /etc/wpa_supplicant.conf
# chmod 755 /etc/sv/wpa_supplicant/run # ln -s /etc/sv/wpa_supplicant /service/
With both wpa_supplicant and dhcpcd
running as services, WiFi will connect and obtain an address
automatically at boot. For multiple networks, add additional
network={} blocks to
/etc/wpa_supplicant.conf —
wpa_supplicant will choose the best available one.
/lib/firmware. The linux-firmware
package provides these. Intel chips (iwlwifi) also need the driver
loaded via /etc/rc.modules — see the
Loading modules section.
DNS resolution
DNS is configured in /etc/resolv.conf. When using
dhcpcd, this file is updated automatically. For
static setups, set it manually:
nameserver 1.1.1.1 nameserver 9.9.9.9
If dhcpcd overwrites your manual settings, you can
prevent this by adding nohook resolv.conf to
/etc/dhcpcd.conf, or simply make the file immutable
with chattr +i /etc/resolv.conf.
Firewall (nftables)
krypt/sh uses nftables for firewalling — not
iptables. A sensible default configuration that blocks incoming
connections while allowing outbound traffic:
#!/sbin/nft -f
flush ruleset
table inet filter {
chain input {
type filter hook input priority 0; policy drop;
# Allow established/related connections
ct state established,related accept
# Allow loopback
iif lo accept
# Allow ICMP (ping)
meta l4proto icmp accept
# Allow SSH
tcp dport 22 accept
# Drop everything else
}
chain forward {
type filter hook forward priority 0; policy drop;
}
chain output {
type filter hook output priority 0; policy accept;
}
}
The nftables service loads this configuration at boot as a one-shot service (see Services & Init):
# Enable the nftables service # ln -s /etc/sv/nftables /service/ # Verify rules are loaded # nft list ruleset # Reload after editing nftables.conf # nft -f /etc/nftables.conf
tcp dport { 80, 443 } accept to the input chain.
For more complex setups, nftables supports sets, maps, rate
limiting, and logging — see man nft.
Users & Permissions
krypt/sh does not use Linux-PAM. User management is handled by
traditional shadow utilities — useradd,
usermod, userdel, passwd,
and groupadd. Authentication goes through
/etc/shadow directly.
Adding users
Create a regular user with a home directory and login shell:
# Create a user with home directory # useradd -m -s /bin/bash username # Set password # passwd username # Add to supplementary groups # usermod -aG wheel,audio,video,seat username # Verify # id username
The -m flag creates /home/username.
The XDG runtime directory at /run/user/UID is
created at boot by the /etc/boot.d/xdg-runtime
script for any user with a UID ≥ 1000 (see
Filesystem Layout).
Groups & privileges
Group membership controls hardware and service access. The important groups on an krypt/sh system:
| Group | Purpose |
|---|---|
| wheel | Can use su / doas for root access |
| audio | Direct access to ALSA sound devices |
| video | Direct access to GPU and framebuffer devices |
| seat | Access to seatd for Wayland compositors |
| input | Access to /dev/input devices |
| kvm | Access to /dev/kvm for virtualization |
| disk | Raw disk device access (use with caution) |
Packages that need system groups declare them in the
groups=() array of their MAKEPKG file.
addpkg creates the groups automatically during
installation.
Privilege escalation
Without PAM, sudo does not work out of the box.
krypt/sh provides two alternatives:
su — the traditional tool. Members of the
wheel group can switch to root:
# Switch to root (enter root password) $ su - # Run a single command as root $ su -c 'pkg sysup'
doas — a minimal sudo replacement from OpenBSD. Install it from the ports tree and create a configuration:
# pkg add doas # Allow wheel group members to run commands as root # echo 'permit :wheel' > /etc/doas.conf # Optionally persist authentication for 5 minutes # echo 'permit persist :wheel' > /etc/doas.conf # Set restrictive permissions # chmod 600 /etc/doas.conf
sudo
package has a hard dependency on PAM for session and
authentication handling. Since krypt/sh does not ship PAM,
doas is the recommended alternative — it works
directly with /etc/shadow and has a much smaller
attack surface.
Login shell & environment
The default login shell is set per-user in /etc/passwd
and can be changed with usermod -s /bin/bash username.
Environment setup happens through /etc/profile and
drop-in scripts in /etc/profile.d/.
krypt/sh ships two profile scripts by default:
/etc/profile.d/xdg.sh (XDG base directories) and
/etc/profile.d/path.sh (PATH additions). You can
add your own by dropping executable .sh files in
/etc/profile.d/ — they are sourced in alphabetical
order on login.
Graphics & Wayland
krypt/sh is a pure Wayland system — X11 is not
part of the core. The graphics stack consists of kernel DRM
drivers, Mesa for userspace OpenGL/Vulkan, seatd
for seat management, and a Wayland compositor of your choice.
The graphics stack
The layers involved in getting pixels on screen:
| Layer | Component |
|---|---|
| Kernel | DRM driver (amdgpu, i915, nouveau) |
| Userspace driver | Mesa (radeonsi, iris, nouveau, llvmpipe) |
| Seat management | seatd — grants GPU/input access |
| Wayland protocol | wayland, wayland-protocols |
| Compositor | labwc, sway, or other wlroots-based |
| Toolkit | GTK4, Qt6 (with Wayland backend) |
There is no display manager — you launch the compositor directly from a TTY login. The compositor handles window management, input, and output all in one process.
Seat management (seatd)
seatd is a minimal seat management daemon that
replaces elogind and systemd-logind.
It grants unprivileged users access to GPU, input, and DRM
devices through the seat group.
# Ensure your user is in the seat group # usermod -aG seat username # Enable the seatd service # ln -s /etc/sv/seatd /service/ # Verify it's running # sv status seatd
The seatd runit service runs with
-g seat, restricting access to members of the
seat group. The socket at
/run/seatd.sock is cleaned up by the service's
finish script.
Failed to connect to seat or
libseat: Could not connect, check that seatd is
active and your user is in the seat group.
GPU drivers
GPU drivers are kernel modules loaded via
/etc/rc.modules (see
Loading modules). Mesa provides
the userspace OpenGL and Vulkan implementations:
| GPU | Kernel module | Mesa driver |
|---|---|---|
| AMD Radeon (GCN+) | amdgpu | radeonsi (GL), radv (Vulkan) |
| Intel (Gen 8+) | i915 | iris (GL), anv (Vulkan) |
| Intel (Arc) | xe / i915 | iris (GL), anv (Vulkan) |
| NVIDIA (open) | nouveau | nouveau (GL, limited) |
| Software | — | llvmpipe (CPU fallback) |
Add the appropriate modprobe line to
/etc/rc.modules. AMD and Intel GPUs work well with
the open-source stack. For NVIDIA, the proprietary driver is not
available on musl — nouveau provides basic support but lacks
reclocking on most cards.
/sys/bus/pci/devices/.../power/control.
Compositors (labwc / sway)
krypt/sh ships labwc and sway in the ports tree — both are wlroots-based Wayland compositors. Launch them directly from a TTY after logging in:
# Option A: labwc (stacking compositor, openbox-like) $ labwc # Option B: sway (tiling compositor, i3-like) $ sway
labwc is a stacking window manager similar to
Openbox. Configuration lives in
~/.config/labwc/ with files for
rc.xml (keybinds, window rules),
menu.xml (right-click menu), and
autostart (programs to launch). It is a good choice
if you prefer a traditional floating window experience.
sway is an i3-compatible tiling compositor.
Configuration lives in ~/.config/sway/config. If
you are familiar with i3, the transition is seamless — most
configuration directives work identically.
Both compositors need the XDG_RUNTIME_DIR
environment variable set and seatd running. If
you followed the installation guide, both are already in place.
~/.profile or ~/.bash_profile:
[ "$(tty)" = "/dev/tty1" ] && exec labwc
Troubleshooting
Common graphics issues and how to diagnose them:
| Symptom | Cause / fix |
|---|---|
| Permission denied on /dev/dri | User not in video and seat groups |
| Failed to connect to seat | seatd not running — check sv status seatd |
| No XDG_RUNTIME_DIR | Missing /etc/profile.d/xdg.sh or /etc/boot.d/xdg-runtime |
| Black screen on launch | GPU module not loaded — check /etc/rc.modules |
| Software rendering only | Mesa not finding GPU — run LIBGL_DEBUG=verbose glxinfo |
| Compositor crashes on exit | Normal if seatd.sock isn't cleaned — the finish script handles it |
For debugging, run the compositor with verbose output:
WLR_RENDERER=vulkan sway or
WAYLAND_DEBUG=1 labwc. Check
dmesg for DRM/GPU errors and
lsmod to confirm the right driver is loaded.