Files
punktfunk/scripts/steamdeck/README.md
T
enricobuehler 861da54066
apple / swift (push) Successful in 1m6s
apple / screenshots (push) Has been cancelled
ci / rust (push) Has been cancelled
ci / web (push) Has been cancelled
ci / docs-site (push) Has been cancelled
ci / bench (push) Has been cancelled
android-screenshots / screenshots (push) Successful in 50s
android / android (push) Successful in 3m25s
docker / build-push (--build-arg FEDORA_VERSION=44, ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora44-rpm) (push) Successful in 5s
docker / build-push (., web/Dockerfile, punktfunk-web) (push) Successful in 33s
docker / build-push (ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora-rpm) (push) Successful in 4s
docker / build-push (ci, ci/rust-ci.Dockerfile, punktfunk-rust-ci) (push) Successful in 4s
windows-host / package (push) Successful in 6m28s
docker / build-push (docs-site, docs-site/Dockerfile, punktfunk-docs) (push) Successful in 52s
windows-msix / package (arm64, C:\Users\Public\ffmpeg-arm64, aarch64-pc-windows-msvc, C:\t-a64) (push) Successful in 1m3s
windows-msix / package (x64, C:\Users\Public\ffmpeg, x86_64-pc-windows-msvc, C:\t) (push) Successful in 1m5s
linux-client-screenshots / screenshots (push) Successful in 2m9s
release / apple (push) Successful in 9m25s
docker / deploy-docs (push) Successful in 20s
web-screenshots / screenshots (push) Successful in 2m33s
deb / build-publish (push) Successful in 3m19s
decky / build-publish (push) Successful in 19s
flatpak / build-publish (push) Successful in 5m9s
rpm / build-publish (bazzite, punktfunk-fedora-rpm) (push) Successful in 9m21s
rpm / build-publish (fedora-44, punktfunk-fedora44-rpm) (push) Successful in 8m38s
feat(web,host/windows): move the web console off :3000 to :47992
Port 3000 collides with half the dev-server ecosystem; 47992 sits next
to the mgmt API (47990) in the punktfunk port family. Updates the run
scripts, systemd/scheduled-task units, Dockerfile, Windows firewall
rule + installer, packaging, and every doc that referenced :3000.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-02 18:17:42 +00:00

88 lines
5.3 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# punktfunk host on a Steam Deck
Run a punktfunk **host** on a Steam Deck — stream its Game Mode (or KDE desktop) *to* other devices.
(Streaming *to* a Deck is the client; use the Flatpak + [Decky plugin](../../clients/decky/) instead.)
User-facing guide: **docs-site → "Steam Deck (Host)"** (`docs-site/content/docs/steam-deck-host.md`).
This README is the deep reference for what the scripts do and how to operate them by hand.
## Why build on-device (not a package or prebuilt binary)
SteamOS 3 is an **immutable, read-only Arch** base:
- No `pacman -S` for system libs; `/usr` is read-only and reset on A/B updates.
- A **prebuilt binary is fragile** — it links the system FFmpeg/glibc, and a SteamOS update can bump
those sonames out from under it (the same class of breakage as the NVIDIA-driver-after-update issue).
- The host needs **unsandboxed** `/dev/uinput` + `/dev/uhid`, PipeWire, the compositor, and VAAPI — so
Flatpak (the normal Deck app channel) doesn't fit. Flatpak/Decky are for the *client*.
So the host is built **natively inside a Debian-trixie distrobox** (`pf2`), chosen because its
FFmpeg/glibc ABI matches SteamOS's — the resulting binary runs **natively on SteamOS** (the container
is only the build environment; `punktfunk-host` is launched directly, not via `distrobox enter`). A
rebuild always matches the running OS. Encode is **VAAPI** on the Deck's AMD GPU (NVENC on NVIDIA),
auto-selected by `PUNKTFUNK_ENCODER=auto`.
The web console is the one part that stays in the container at runtime: it's a Nitro **`bun`**
build (`bun` both builds **and runs** it — the bun-preset output uses `Bun.serve` with TLS,
serving HTTPS (HTTP/1.1 over TLS) with the host's identity cert), so its service does
`distrobox enter pf2 -- … bun .output/server/index.mjs`. `bun` is provisioned in the container.
## Scripts
| Script | What it does |
|--------|--------------|
| `install.sh` | Idempotent installer: ensure the `pf2` distrobox + toolchain → build host (+web) → write config → tune sysctl + `input` group (sudo) → install + start `punktfunk-host` / `punktfunk-web` systemd **user** services with linger. |
| `update.sh` | Rebuild from the current source and restart the services (config + pairings persist). `--pull` does `git pull` first. |
```sh
git clone https://git.unom.io/unom/punktfunk ~/punktfunk
bash ~/punktfunk/scripts/steamdeck/install.sh # PIN pairing required (secure default)
bash ~/punktfunk/scripts/steamdeck/install.sh --open # trusted LAN: accept unpaired clients
bash ~/punktfunk/scripts/steamdeck/install.sh --no-web # host only, no web console
bash ~/punktfunk/scripts/steamdeck/install.sh --no-gamestream # native punktfunk/1 only, no Moonlight surface
bash ~/punktfunk/scripts/steamdeck/update.sh # after pulling new source
```
Note: unlike a bare `serve` (native-only by default), the Deck install enables `--gamestream` by
default so stock Moonlight clients work out of the box; `--no-gamestream` turns that surface off.
Env overrides: `PUNKTFUNK_SRC` (source dir, default `~/punktfunk`), `PUNKTFUNK_BOX` (container name,
default `pf2`), `PUNKTFUNK_MGMT_PORT` (47990), `PUNKTFUNK_WEB_PORT` (47992).
## What gets installed
- **Binary:** `~/punktfunk/target-steamos/release/punktfunk-host` (built in `pf2`, run natively).
- **Config:** `~/.config/punktfunk/host.env` (encoder/compositor) and `web.env` (generated web login
password + session secret). Trust material (`cert.pem`, `mgmt-token`, `punktfunk1-paired.json`) lives
here too and persists across updates.
- **Services:** `~/.config/systemd/user/punktfunk-host.service` (runs `serve --gamestream --mgmt-bind
0.0.0.0:47990`, `+ --open` if chosen — `--gamestream` adds the Moonlight-compat planes so the Deck's
Game Mode also streams to stock Moonlight; the native `punktfunk/1` plane is always on) and
`punktfunk-web.service`. Linger is enabled so they run without a login session.
- **System tuning (sudo):** `/etc/sysctl.d/99-punktfunk-net.conf` (32 MB UDP buffers — the #1
high-bitrate lever), `/etc/udev/rules.d/60-punktfunk.rules`, and `$USER` in the `input` group.
## Operating
```sh
systemctl --user status punktfunk-host punktfunk-web
journalctl --user -u punktfunk-host -f # watch sessions / pairing PIN
systemctl --user restart punktfunk-host # after editing host.env
```
Pair from the web console (Devices → arm pairing) or directly from a client with the host's PIN. The
host advertises over mDNS as `_punktfunk._udp`, so clients discover it automatically.
## Gotchas
- **distrobox required.** If missing: `curl -sfL https://raw.githubusercontent.com/89luca89/distrobox/main/install | sh -s -- --prefix ~/.local` (then ensure `~/.local/bin` is on PATH).
- **First build is slow** (~1015 min + ~1 GB toolchain/image). Incremental afterwards.
- **No passwordless sudo** → the installer skips the sysctl/udev/input steps with a warning; high
bitrates will drop packets until you apply `99-punktfunk-net.conf` and join `input` yourself.
- **Game Mode auto-suspend** drops the host off the network on idle — disable it (Settings → Power)
for a headless host.
- **WiFi tx ceiling** ≈ 250 Mbps goodput (a Deck hardware/driver packet-rate limit, band-independent);
fine for 1080p/1440p60. A wired dock lifts it.
- **After a major SteamOS update**, if the host won't start, run `update.sh` to rebuild against the new
base libraries.