Files
punktfunk/docs-site/content/docs/headless-box.md
T
enricobuehler e586961e0b
ci / rust (push) Has been cancelled
docs(site): make docs-site the knowledge base — status tracker + setup guides
Per the new docs workflow (docs-site = KB layer; repo docs/ keeps design notes):
- Add a canonical Status & Progress tracker (status.md): milestones, per-box live
  state, and a dated progress log — the go-forward place to track progress.
- Add setup guides: GNOME/Mutter host (gnome-box — Secure Boot MOK enroll, the
  libnvidia-gl EGL fix, autologin, screen-lock disable, appliance unit), headless
  KDE box, and Bazzite host (ujust input group, gamescope session, gotchas).
- Roadmap is now canonical in docs-site (synced the skew-handshake section 12
  update); removed the repo docs/roadmap.md copy and repointed README to docs-site.
- Nav (meta.json) + landing cards updated; site builds (bun run build).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-12 11:33:39 +00:00

2.6 KiB

title, description
title description
Headless KDE Box Setup Run punktfunk on a headless box with a nested KWin/Plasma session — the boot-appliance pattern.

How to run a punktfunk host on a headless box (no physical display / KMS scanout) using the KWin backend: a nested headless Plasma session on WAYLAND_DISPLAY=wayland-kde, captured into a per-client virtual output. This is the dev-box pattern (a QEMU VM with a passthrough NVIDIA GPU, no KMS scanout → everything renders offscreen via renderD128).

Requirements

  • KWin ≥ 6.5.6 (headless --virtual gained createVirtualOutput), or a DRM backend. On a box with no KMS scanout, kwin --drm is impossible — use the headless/virtual path below.
  • NVIDIA driver with GL/EGL userspace (see Linux Host Setup for the build deps).

Bring up the session

The headless Plasma session is launched by scripts/headless/run-headless-kde.sh, which starts kwin --virtual on wayland-kde plus the full Plasma desktop (portals, polkit agent, a supervised plasmashell). It sets the env Plasma needs — notably XDG_MENU_PREFIX=plasma-, without which plasmashell runs but the launcher menu is empty:

# shell 1 — the compositor session
bash scripts/headless/run-headless-kde.sh 1920x1080

# shell 2 — the host
WAYLAND_DISPLAY=wayland-kde XDG_CURRENT_DESKTOP=KDE PUNKTFUNK_VIDEO_SOURCE=virtual \
  PUNKTFUNK_ZEROCOPY=1 cargo run -rp punktfunk-host -- serve --native

Boot appliance (no login, comes up at boot)

Two user systemd units bring the whole thing up at boot with no interaction:

cp scripts/punktfunk-kde-session.service scripts/punktfunk-host.service ~/.config/systemd/user/
cp scripts/host.env.example ~/.config/punktfunk/host.env    # edit for the kwin backend
systemctl --user daemon-reload
systemctl --user enable punktfunk-kde-session punktfunk-host
sudo loginctl enable-linger "$USER"   # start user units at boot WITHOUT a login
reboot

punktfunk-kde-session.service runs the headless KWin/Plasma session; punktfunk-host.service (serve --native) After=s it and starts listening immediately (it only touches the compositor per session, so the ordering is soft). host.env for this backend:

WAYLAND_DISPLAY=wayland-kde
XDG_CURRENT_DESKTOP=KDE
PUNKTFUNK_COMPOSITOR=kwin
PUNKTFUNK_VIDEO_SOURCE=virtual
PUNKTFUNK_ZEROCOPY=1

Other backends

The same box can stream a nested app (no desktop) via the gamescope backend, or attach to GNOME (GNOME Box Setup) or Sway/wlroots. Each compositor keeps its own VirtualDisplay backend — there's no cross-compositor protocol for client-sized outputs.