Files
punktfunk/packaging
enricobuehler 5e106c51cf
apple / swift (push) Successful in 56s
ci / rust (push) Successful in 1m15s
ci / web (push) Successful in 39s
windows-host / package (push) Failing after 2m30s
ci / docs-site (push) Successful in 59s
android / android (push) Successful in 3m16s
deb / build-publish (push) Successful in 2m37s
decky / build-publish (push) Successful in 23s
docker / build-push (--build-arg FEDORA_VERSION=44, ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora44-rpm) (push) Successful in 4s
docker / build-push (., web/Dockerfile, punktfunk-web) (push) Successful in 4s
docker / build-push (ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora-rpm) (push) Successful in 4s
ci / bench (push) Successful in 4m40s
docker / build-push (docs-site, docs-site/Dockerfile, punktfunk-docs) (push) Successful in 46s
docker / build-push (ci, ci/rust-ci.Dockerfile, punktfunk-rust-ci) (push) Successful in 2m22s
rpm / build-publish (bazzite, punktfunk-fedora-rpm) (push) Successful in 8m25s
docker / deploy-docs (push) Successful in 22s
rpm / build-publish (fedora-44, punktfunk-fedora44-rpm) (push) Successful in 8m23s
feat(windows-host): bundle + auto-run the web console in the installer
The Windows host installer shipped only the host exe + SudoVDA driver + FFmpeg, so a
fresh install had no web management console — required for basically every user (status,
paired devices, the PIN pairing flow). The console was only ever set up by hand on the
dev box (build-web.ps1 + a hand-made PunktfunkWeb task whose web-run.cmd wasn't even
committed). Bundle it into the same installer, mirroring the proven Linux punktfunk-web
deploy.

- windows-host.yml builds the Nitro node-server console (bun, deb.yml's shape) + fetches
  a pinned portable Node, smoke-boots it under node (/login == 200) to gate the build, and
  hands web/.output + node.exe to the pack script.
- pack-host-installer.ps1 gains -WebDir/-NodeExe and stages the .output tree, node, and
  the two new scripts into the non-WOW64-redirected build area.
- punktfunk-host.iss lays the payload into {app}\web\.output + {app}\node\node.exe, adds
  a wizard page for the console login password pre-filled with a crypto-random default
  (shown on the finish page; kept on upgrade), and runs web-setup.ps1.
- web-setup.ps1 writes the ACL'd %ProgramData%\punktfunk\web-password (Administrators +
  SYSTEM), registers the PunktfunkWeb scheduled task (boot, SYSTEM, restart-on-failure ->
  web-run.cmd -> node on :3000), opens inbound TCP 3000, and starts it. web-run.cmd
  sources the host's mgmt-token + the password and runs the bundled node.
- The console proxies the host's loopback mgmt API with the host's own
  %ProgramData%\punktfunk\mgmt-token (no host-code change). Uninstall removes the task +
  firewall rule.

Validated locally: bun build -> node-server bundle, node boot serves /login (200) and
gates /api (401). The Windows-only bits (ISCC compile, scheduled task, password page,
firewall) validate on the Windows runner CI + on-glass.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-22 19:28:47 +02:00
..

Packaging punktfunk for Fedora / Bazzite

The punktfunk host is Linux-only and links system FFmpeg (NVENC), PipeWire, Opus and the NVIDIA driver. This directory packages it for the Fedora Atomic / Bazzite world (rpm-ostree + bootc), where most of those deps are already present.

👉 Ubuntu/Debian hosts install via apt from Gitea's package registry — see debian/README.md (apt update && apt upgrade for new builds).

👉 End-to-end Bazzite setup walkthrough (install → udev/group → host.env → service → firewall → verify → troubleshooting): bazzite/README.md. This file is the higher-level packaging rationale.

packaging/
  rpm/punktfunk.spec      # the RPM (builds punktfunk-host from source with cargo)
  bazzite/host.env        # gamescope-default config for a Bazzite appliance
  bazzite/README.md       # step-by-step Bazzite setup guide
  bootc/Containerfile     # bake punktfunk into a Bazzite-based atomic image
  copr/                   # COPR build-from-SCM settings

What's needed beyond base Fedora

Dependency Where it comes from
ffmpeg-libs with NVENC RPM Fusion nonfree (ffmpeg, not ffmpeg-free)
NVIDIA driver (libnvidia-encode, libEGL_nvidia) Bazzite -nvidia images ship it; plain Fedora: akmod-nvidia + xorg-x11-drv-nvidia-cuda
gamescope, PipeWire, wireplumber Bazzite ships these; plain Fedora: dnf install gamescope pipewire wireplumber
opus, libei Fedora base / updates

On Bazzite the only genuinely new runtime bits are ffmpeg-libs (RPM Fusion) + opus + libei — the rest of the stack is already there. The default backend is gamescope (packaging/bazzite/host.env), which the host spawns headless per session — no desktop login.

The host's RPM is published to unom's self-hosted Gitea RPM registry (CI builds it on every push), mirroring the Debian/apt setup. Add one repo file, install, and track updates with rpm-ostree upgrade — no COPR account needed. Full guide: rpm/README.md.

# GPG-signed pkgs + Gitea-signed metadata → gpgcheck=1, repo_gpgcheck=1 (see rpm/README.md)
sudo tee /etc/yum.repos.d/punktfunk.repo >/dev/null <<'REPO'
[gitea-unom-bazzite]
name=punktfunk (unom, Bazzite)
baseurl=https://git.unom.io/api/packages/unom/rpm/bazzite
enabled=1
gpgcheck=1
repo_gpgcheck=1
gpgkey=https://git.unom.io/api/packages/unom/rpm/repository.key
       https://git.unom.io/api/packages/unom/generic/punktfunk-keys/1/RPM-GPG-KEY-punktfunk
REPO
rpm-ostree install punktfunk && systemctl reboot
# updates:  rpm-ostree upgrade && systemctl reboot

Option B — COPR (per-host, rpm-ostree install)

  1. Create a COPR project, enable build-from-SCM pointing at this repo, spec path packaging/rpm/punktfunk.spec (see copr/README.md). Under External Repositories add RPM Fusion nonfree so ffmpeg-devel resolves at build time.
  2. On the Bazzite host:
    # RPM Fusion (for the NVENC ffmpeg) — usually already enabled on Bazzite
    rpm-ostree install \
      https://mirrors.rpmfusion.org/free/fedora/rpmfusion-free-release-$(rpm -E %fedora).noarch.rpm \
      https://mirrors.rpmfusion.org/nonfree/fedora/rpmfusion-nonfree-release-$(rpm -E %fedora).noarch.rpm
    # enable the COPR + install punktfunk
    sudo wget -O /etc/yum.repos.d/_copr_punktfunk.repo \
      https://copr.fedorainfracloud.org/coprs/enricobuehler/punktfunk/repo/fedora-$(rpm -E %fedora)/
    rpm-ostree install punktfunk
    systemctl reboot
    

Option B — bootc (image-based, atomic)

Layer punktfunk into a Bazzite image once, then rebase any number of hosts onto it — no per-host drift. See bootc/Containerfile:

podman build -t ghcr.io/<you>/bazzite-punktfunk -f packaging/bootc/Containerfile .
podman push  ghcr.io/<you>/bazzite-punktfunk
# on the target:
sudo bootc switch ghcr.io/<you>/bazzite-punktfunk && systemctl reboot

First-run setup (either option)

ujust add-user-to-input-group           # virtual gamepads need /dev/uinput (then re-login).
                                        # On Bazzite use ujust, NOT `usermod -aG input` (atomic OS — it won't stick).
mkdir -p ~/.config/punktfunk
cp /usr/share/punktfunk/host.env.bazzite ~/.config/punktfunk/host.env   # edit (gamescope app, etc.)
systemctl --user enable --now punktfunk-host

# Management web console (pairing + status) — pulled in by default (the host RPM Recommends it;
# `--no-install-recommends` / headless-only boxes can skip it). Enable it and read the login password:
systemctl --user enable --now punktfunk-web
journalctl --user -u punktfunk-web-init | sed -n 's/.*password generated: //p'   # then open http://<host-ip>:3000

Pair a stock Moonlight client (mDNS-discovered), or connect the native punktfunk/1 client — via the web console at http://<host-ip>:3000 or directly.

⚠️ COPR caveat: COPR's mock chroot has no bun, so a COPR build produces only punktfunk + punktfunk-clientnot punktfunk-web. For the console on a COPR/bootc host, install from the Gitea RPM registry (Option A — it carries punktfunk-web), which is also why bootc/Containerfile installs from there rather than COPR.

Why not Flatpak (for the HOST)?

The host needs unsandboxed access the zero-copy NVENC path, /dev/uinput, the PipeWire graph and the compositor's privileged protocols — a Flatpak sandbox fights all of these. An RPM (or the bootc layer) installs into the host system where those just work.

👉 The client is a different story — it IS shipped as a Flatpak (the only viable Steam Deck install path: SteamOS /usr is read-only and lacks libadwaita/libSDL3). See flatpak/README.md. The client sandbox only needs the GPU render node, Wayland, PipeWire audio, the network and hidraw — all expressible as finish-args.

Building the SRPM/RPM locally (Fedora only)

git archive --format=tar.gz --prefix=punktfunk-0.0.1/ -o ~/rpmbuild/SOURCES/punktfunk-0.0.1.tar.gz HEAD
rpmbuild -ba packaging/rpm/punktfunk.spec     # needs the BuildRequires from the spec

(Not buildable on Debian/Ubuntu — use a Fedora toolbox/container or COPR.)