JustToThePoint English Website Version
JustToThePoint en español

Arch Linux Post-Installation: Niri, greetd, and Noctalia Shell

The only way to learn mathematics is to do mathematics, Paul Halmos

image info

Introduction

Following the base system setup, the next critical phase is establishing the graphical environment. Unlike traditional desktop environments, a modern Wayland setup requires careful integration of the compositor, display manager, and user interface shell.

This guide provides three automated scripts to bridge that gap: installing Niri, a unique scrollable-tiling Wayland compositor; configuring greetd with tuigreet for a minimal, secure login experience; and deploying Noctalia Shell, a sophisticated Quickshell-based desktop interface. Together, these components create a lean, efficient, and highly customizable graphical session from the ground up.

Niri Installation Script

This script installs Niri, a unique scrollable-tiling Wayland compositor.

#!/usr/bin/env bash
# ── 02-niri.sh ────────────────────────────────────────────────────────────────
# Install Niri — a scrollable-tiling Wayland compositor.
#
# Niri concepts (different from i3):
#   - No workspaces in the traditional sense — windows tile LEFT/RIGHT
#     in an infinite horizontal scroll canvas.
#   - Workspaces are VERTICAL: each column of windows is a workspace.
#   - Overview (Super+O): bird's-eye view of all workspaces.
#   - No fixed workspace count: Workspaces are created/destroyed dynamically
#
# Run: bash 02-niri.sh
# ─────────────────────────────────────────────────────────────────────────────
set -euo pipefail

echo "── 02-niri: installing Niri and Wayland compositor dependencies..."

# ── Niri + XWayland ───────────────────────────────────────────────────────────
# niri: the compositor itself (available in official Arch repos)
# xwayland-satellite: runs XWayland on-demand as a separate process.
sudo pacman -S --needed --noconfirm \
  niri \
  xwayland-satellite

# ── Wayland session support ───────────────────────────────────────────────────
# polkit-kde-agent: Polkit manages system-wide privileges for unprivileged processes.
# qt6-wayland: Qt6 apps run natively on Wayland instead of via XWayland
# brightnessctl: keyboard brightness keys (used in niri keybinds)
# playerctl: media key support (play/pause/next from keyboard)
# swayidle: idle management — lock screen and suspend after inactivity
# swaylock: lock screen
# SwayBG is a simple wallpaper setter
sudo pacman -S --needed --noconfirm \
  polkit-kde-agent \
  qt6-wayland \
  qt5-wayland \
  brightnessctl \
  playerctl \
  swayidle \
  swaylock \
  swaybg

# ── Create config directory ───────────────────────────────────────────────────
# The symlink script (05-symlinks.sh) will populate this with our dotfile.
# We create it now so niri can start even before symlinking.
mkdir -p ~/.config/niri

# ── Wayland session file ──────────────────────────────────────────────────────
# Check if niri installed its own .desktop session file (it should have)
if [[ -f /usr/share/wayland-sessions/niri.desktop ]]; then
  echo "  ✅  Niri session file found at /usr/share/wayland-sessions/niri.desktop"
else
  # Fallback: create it manually so greetd can find the session
  echo "  ⚠️  Creating niri.desktop manually..."
  sudo tee /usr/share/wayland-sessions/niri.desktop > /dev/null << 'SESSION'
[Desktop Entry]
Name=Niri # Displayed in display manager session chooser
Comment=A scrollable-tiling Wayland compositor
Exec=niri-session # The command to launch the compositor session
Type=Application # Marks this as an application entry
SESSION
fi

echo "✅  02-niri: done"
echo "    Next: bash 03-display-manager.sh"

Comprehensive Guide to greetd + tuigreet Display Manager Configuration

greetd is a minimal (simple), compositor-agnostic (it works with any window manager) and flexible login manager daemon which does not make assumptions about what the user wants to launch, should it be console-based or graphical. It is Wayland-native (it does not force Xorg), modular, PAM-based (it uses standard Linux authentication), and uses a single TOML configuration file.

#   Install greetd + tuigreet as the display manager (login screen).
#
#   greetd is a minimal, compositor-agnostic display manager designed for
#   Wayland. It does not carry GTK/Qt dependencies, does not assume a
#   specific desktop, and starts sessions cleanly via PAM.
#
#   Run: bash 03-display-manager.sh
# ─────────────────────────────────────────────────────────────────────────────
set -euo pipefail # Exit on error, undefined vars, pipe failures

echo "── 03-display-manager: installing greetd and tuigreet..."

# ── Disable any existing display manager ──────────────────────────────────────
# Only one display manager can own the login. Disable others first.
for dm in sddm gdm lightdm lxdm; do
  if systemctl is-enabled "$dm" &>/dev/null; then
  # Returns 0 (success) if service is enabled
  # Silenced with &>/dev/null (discards both stdout and stderr)
  # We only care about the exit code
    echo "  ⚠️  Disabling existing display manager: $dm"
    sudo systemctl disable "$dm"
  fi
done

# ── Install ───────────────────────────────────────────────────────────────────
sudo pacman -S --needed --noconfirm greetd greetd-tuigreet
# greetd: The core display manager daemon
# greetd-tuigreet: Terminal UI greeter (separate binary)
# Flags: --needed: Skip packages already installed (idempotent), --noconfirm: Auto-answer yes (for scripting)

# ── greetd config ─────────────────────────────────────────────────────────────
# The config file at /etc/greetd/config.toml tells greetd which greeter to run.
# We write it here; 05-symlinks.sh will later replace it with a symlink to
# dotfiles/myArch/config/greetd/config.toml for version control.
#
# tuigreet flags used:
#   --time          show a clock in the greeter
#   --remember      remember the last username
#   --sessions      path to .desktop session files (greetd finds Niri here)
#   --asterisks     show * characters while typing password (security feedback)
sudo mkdir -p /etc/greetd

# ── Enable greetd ─────────────────────────────────────────────────────────────
# greetd replaces getty on VT1. We enable it as a systemd service.
sudo systemctl enable greetd

echo "✅  03-display-manager: done — greetd enabled, will start on next boot"
echo "    Next: bash 04-noctalia.sh"

greetd Configuration Structure:

[terminal] # Configures the virtual terminal where greetd runs
vt = 1

[default_session] # Defines what to run (greeter) and as which user
command = "tuigreet --time --remember --sessions /usr/share/wayland-sessions --asterisks --greeting 'Welcome back, nmaximo7'"
user = "greeter"
# command: The actual command to execute for the greeter; user: System user that runs the greeter (security isolation)
tuigreet \
  --time \              # Show clock in greeter
  --remember \          # Remember last username (cached in /var/cache/tuigreet)
  --sessions /usr/share/wayland-sessions \  # Where to find .desktop session files
  --asterisks \         # Show * when typing password (privacy vs feedback)
  --greeting 'Welcome back, nmaximo7'  # Custom greeting text

Noctalia Shell Installation Script

This script installs Noctalia Shell, a Quickshell-based desktop shell for Wayland. Quickshell is a declarative framework for building Wayland desktop shells using QML. Quickshell is like a “React for Wayland shells” - you describe your UI declaratively, and it handles the low-level Wayland communication.

Noctalia maintains its own fork (noctalia-qs).

#!/usr/bin/env bash
# ── 04-noctalia.sh ────────────────────────────────────────────────────────────
# Install Noctalia Shell — a Quickshell-based desktop shell for Wayland.
#
# Architecture (as of Noctalia v4.6+):
#   noctalia-qs  = Noctalia's own fork of the Quickshell runtime (AUR)
#   noctalia-shell = the shell config/QML code that runs on noctalia-qs (AUR)
#   noctalia-shell pulls noctalia-qs as a dependency automatically.
#
#   IMPORTANT: noctalia-qs conflicts with quickshell and quickshell-git.
#   Both must be removed before installing. This script handles that.
#
# Start command (in niri config.kdl):
#   spawn-at-startup "noctalia-qs" "-c" "noctalia-shell"
#   NOT "noctalia-shell" directly — the binary is noctalia-qs.
#
# Run: bash 04-noctalia.sh
# ─────────────────────────────────────────────────────────────────────────────
set -euo pipefail

echo "── 04-noctalia: installing Noctalia Shell..."

# ── Conflict resolution ───────────────────────────────────────────────────────
# noctalia-qs conflicts with quickshell and quickshell-git.
# We use paru -R (not pacman -R) because these are AUR packages —
# pacman -R can fail with "target not found" for AUR-installed packages
# even when pacman -Qi shows them as installed.
# --noconfirm + --nodeps removes them without asking about dependents.
for pkg in quickshell quickshell-git; do
  if paru -Qi "$pkg" &>/dev/null 2>&1; then
    # The script attempts three removal methods
    echo "  ⚠️  Removing conflicting package: $pkg"
    # Method 1: paru -R (preferred for AUR packages)
    paru -R --noconfirm --nodeps "$pkg" 2>/dev/null || \
      # Method 2: sudo pacman -R (fallback for official packages)
      sudo pacman -R --noconfirm --nodeps "$pkg" 2>/dev/null || \
      # Method 3: Manual instruction if both fail
      echo "  ℹ️  Could not remove $pkg automatically — remove manually if install fails"
  else
    echo "  ✅  $pkg not installed, no conflict"
  fi
done

# ── Install from AUR ──────────────────────────────────────────────────────────
# noctalia-shell pulls noctalia-qs as a dependency.
# noctalia-qs builds from source — 10-30 min on first install.
# Subsequent updates use the build cache and are much faster.
echo "  ⏳  Building noctalia-shell from AUR (may take 10-30 minutes)..."
paru -S --needed --noconfirm noctalia-shell

# ── Config directory ──────────────────────────────────────────────────────────
# ~/.config/noctalia/ is where Noctalia reads settings.json.
# 05-symlinks.sh will symlink dotfiles/myArch/config/noctalia/settings.json here.
mkdir -p ~/.config/noctalia

# ── Verify installation ───────────────────────────────────────────────────────
# The binary installed by noctalia-qs is `noctalia-qs` (not `noctalia-shell`).
# noctalia-shell is the config name passed with -c, not an executable.
echo
if command -v noctalia-qs &>/dev/null; then
  echo "  ✅  noctalia-qs binary found: $(which noctalia-qs)"
  echo "  ℹ️   Start with: noctalia-qs -c noctalia-shell"
  echo "  ℹ️   In niri config.kdl use: spawn-at-startup \"noctalia-qs\" \"-c\" \"noctalia-shell\""
else
  echo "  ⚠️  noctalia-qs not found in PATH — check paru output above"
fi

echo
echo "✅  04-noctalia: done"
echo "    Next: bash 05-symlinks.sh"
Bitcoin donation

JustToThePoint Copyright © 2011 - 2026 Anawim. ALL RIGHTS RESERVED. Bilingual e-books, articles, and videos to help your child and your entire family succeed, develop a healthy lifestyle, and have a lot of fun. Social Issues, Join us.

This website uses cookies to improve your navigation experience.
By continuing, you are consenting to our use of cookies, in accordance with our Cookies Policy and Website Terms and Conditions of use.