docs: restructure host setup by distro, configuration by compositor
apple / swift (push) Successful in 1m8s
apple / screenshots (push) Successful in 5m33s
android / android (push) Successful in 4m43s
arch / build-publish (push) Successful in 5m38s
ci / web (push) Successful in 1m3s
ci / docs-site (push) Successful in 1m17s
ci / rust (push) Successful in 4m48s
ci / bench (push) Successful in 5m7s
decky / build-publish (push) Successful in 14s
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 5s
docker / build-push (ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora-rpm) (push) Successful in 3s
docker / build-push (ci, ci/rust-ci.Dockerfile, punktfunk-rust-ci) (push) Successful in 4s
deb / build-publish (push) Successful in 4m29s
docker / build-push (docs-site, docs-site/Dockerfile, punktfunk-docs) (push) Successful in 1m16s
rpm / build-publish (43, bazzite, punktfunk-fedora-rpm) (push) Successful in 10m24s
docker / deploy-docs (push) Successful in 6s
rpm / build-publish (44, fedora-44, punktfunk-fedora44-rpm) (push) Successful in 10m3s

Split the docs' single distro×desktop axis (ubuntu-gnome / ubuntu-kde / fedora-kde) into two,
which deduplicates the shared mechanics and scales to distros that run several desktops (Arch):

- Install the host — per distro/OS (ubuntu, fedora, arch, bazzite, steamos-host, windows-host):
  GPU driver + package + input group, then a canonical "Configure your desktop" funnel.
- Configure your desktop — per compositor (kde, gnome, gamescope, sway): host.env, compositor
  quirks, the headless session, and starting the host.

New shared web-console page (enable · login password · arm pairing) removes the console/password
block that was copy-pasted across all seven host pages. Merged ubuntu-gnome + ubuntu-kde into
ubuntu; renamed fedora-kde to fedora; kept bazzite and steamos-host as dedicated appliance guides
(trimmed of duplication). Moved the KWin headless session, the GNOME EGL/lock traps, and the
gamescope attach/managed model out of the distro pages onto their compositor pages.

Fixed while restructuring: distro-specific paths on kde (kde-desktop-setup.sh is Fedora/Bazzite-only;
the .deb ships host.env.kde under /usr/share/punktfunk-host), the interactive "start the host" step
that was lost in the merge, sway over-claiming Hyprland, and a pre-existing broken anchor in
how-it-works.

Removal of the three old pages was captured by the preceding commit 8ebb614 (a concurrent commit
swept up the staged git-rm); the net docs tree is correct. Fumadocs build + internal link/anchor
check green.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-07-05 21:04:31 +00:00
parent 8ebb61400c
commit 69fcb6e0b1
21 changed files with 854 additions and 192 deletions
+23 -35
View File
@@ -58,25 +58,30 @@ tuning, and example configs. Updates later are just `sudo pacman -Syu`.
## 4. Configure and run ## 4. Configure and run
The host runs as a systemd **`--user`** service — it needs your session's PipeWire and D-Bus. The host runs as a systemd **`--user`** service — it needs your session's PipeWire and D-Bus. Copy a
Copy a starting config, enable the service, and enable linger so it starts at boot without a login: starting config:
```sh ```sh
mkdir -p ~/.config/punktfunk mkdir -p ~/.config/punktfunk
cp /usr/share/punktfunk/host.env.example ~/.config/punktfunk/host.env # then edit cp /usr/share/punktfunk/host.env.example ~/.config/punktfunk/host.env
```
How the host creates its virtual display and injects input depends on your desktop, not your distro —
edit `host.env` for the desktop you run, following its page for the exact settings and any quirks:
- [KDE Plasma (KWin)](/docs/kde)
- [GNOME (Mutter)](/docs/gnome)
- [Steam / gamescope](/docs/gamescope)
- [Sway / wlroots](/docs/sway)
Then enable the service and turn on linger so it starts at boot without a login:
```sh
systemctl --user daemon-reload systemctl --user daemon-reload
systemctl --user enable --now punktfunk-host systemctl --user enable --now punktfunk-host
sudo loginctl enable-linger "$USER" sudo loginctl enable-linger "$USER"
``` ```
Which compositor the host captures depends on your desktop — it drives a per-client virtual output
via KWin (Plasma), Mutter (GNOME), or wlroots (Sway), or spawns a headless **gamescope** session
per connect. For a headless appliance, the package also ships `punktfunk-kde-session.service`
(a dedicated `kwin --virtual` session, same as the [Fedora KDE](/docs/fedora-kde#3-kwin-streaming-session)
guide — `cp /usr/share/punktfunk/host.env.kde ~/.config/punktfunk/host.env` and enable it alongside
the host). See [Configuration](/docs/configuration) for every knob and
[Running as a Service](/docs/running-as-a-service) for the service model.
Check it came up: Check it came up:
```sh ```sh
@@ -84,27 +89,10 @@ systemctl --user status punktfunk-host # active
journalctl --user -u punktfunk-host -f # watch a client connect journalctl --user -u punktfunk-host -f # watch a client connect
``` ```
### Web console Enable the browser console, find your login password, and arm PIN pairing from
[The Web Console](/docs/web-console). For a headless KWin appliance that streams at boot with no
The console (status, paired devices, arm pairing) ships as `punktfunk-web` — enable it, then open graphical login, see [KDE → Headless session](/docs/kde#headless-session). Full reference:
`http://<host-ip>:47992`: [Configuration](/docs/configuration) · [Running as a Service](/docs/running-as-a-service).
```sh
systemctl --user enable --now punktfunk-web
```
#### Console login password
On first start `punktfunk-web-init` generates a random login password and saves it to
`~/.config/punktfunk/web-password` (as `PUNKTFUNK_UI_PASSWORD=…`). Read it back at any time:
```sh
journalctl --user -u punktfunk-web-init | sed -n 's/.*password generated: //p'
sed -n 's/^PUNKTFUNK_UI_PASSWORD=//p' ~/.config/punktfunk/web-password
```
To set your own, edit that file and `systemctl --user restart punktfunk-web`. Forgot it? See
[Forgot your Password?](/docs/forgot-password).
## 5. Open the firewall (if you have one) ## 5. Open the firewall (if you have one)
@@ -147,9 +135,9 @@ opened. Full port lists (`nftables`, explicit ports) are in
## 6. Connect a client ## 6. Connect a client
From any [client](/docs/clients), `--discover` finds the host on the LAN. On first connect, complete From any [client](/docs/clients), `--discover` finds the host on the LAN. On first connect, complete
the **PIN pairing** arm it from the host's web console, which displays a 4-digit PIN to type into the **PIN pairing**: arm it from [The Web Console](/docs/web-console#arm-pairing), which displays a
the client. (Pairing is required by default; pass `serve --open` only if you deliberately want to 4-digit PIN to type into the client. (Pairing is required by default; pass `serve --open` only if
disable it.) See [Clients](/docs/clients) and [Pairing](/docs/pairing). you deliberately want to disable it.) See [Clients](/docs/clients) for per-platform setup.
## Appendix — build from source (PKGBUILD) ## Appendix — build from source (PKGBUILD)
+18 -32
View File
@@ -16,8 +16,8 @@ mid-stream. You flip between Gaming Mode and Desktop with Bazzite's normal Steam
`host.env` forces a mode. `host.env` forces a mode.
> Ideal for a dedicated game-streaming box that you also occasionally want as a remote desktop. For a > Ideal for a dedicated game-streaming box that you also occasionally want as a remote desktop. For a
> pure desktop machine, [Ubuntu/Fedora KDE](/docs/ubuntu-kde) or [GNOME](/docs/ubuntu-gnome) are > pure desktop machine, install on [Ubuntu](/docs/ubuntu) or [Fedora](/docs/fedora) and configure the
> simpler. > [KDE](/docs/kde) or [GNOME](/docs/gnome) desktop directly — simpler.
> New here? Read [Security & Safe Use](/docs/security) first — a streaming host is remote control of > New here? Read [Security & Safe Use](/docs/security) first — a streaming host is remote control of
> the machine, so keep it on a trusted LAN or VPN and require pairing. > the machine, so keep it on a trusted LAN or VPN and require pairing.
@@ -60,7 +60,7 @@ For a fully baked appliance image there's also a **bootc** Containerfile that in
from the registry at image-build time — see `packaging/bootc/` in the repo. Plain `rpm-ostree` from the registry at image-build time — see `packaging/bootc/` in the repo. Plain `rpm-ostree`
layering from the [RPM registry](https://git.unom.io/unom/-/packages) keeps working too (see layering from the [RPM registry](https://git.unom.io/unom/-/packages) keeps working too (see
`packaging/bazzite/README.md`), but the sysext is the supported default. Building from source `packaging/bazzite/README.md`), but the sysext is the supported default. Building from source
also works (Bazzite is Fedora Atomic underneath — same steps as [Fedora KDE](/docs/fedora-kde)). also works (Bazzite is Fedora Atomic underneath — same steps as [Fedora](/docs/fedora)).
## Allow controller input ## Allow controller input
@@ -99,15 +99,14 @@ PUNKTFUNK_GAMESCOPE_ATTACH=1 # Gaming Mode = attach to the box's own session
For Gaming Mode there are two models (pick one; the shipped default is **attach**): For Gaming Mode there are two models (pick one; the shipped default is **attach**):
- **Attach** (`PUNKTFUNK_GAMESCOPE_ATTACH=1`, the default) — the **box** owns its gamescope session - **Attach** (`PUNKTFUNK_GAMESCOPE_ATTACH=1`, the default) — the **box** owns its gamescope session,
and decides Gaming vs Desktop via the normal Steam UI. The host just attaches to whatever's live the host attaches to whatever's live and never tears it down, and the streamed game-mode resolution
and never tears it down, so switching Desktop ↔ Game is rock-solid and disconnecting leaves the box is the box's own gamescope mode. Switching Desktop ↔ Game is rock-solid.
where it was. The streamed game-mode resolution is the box's gamescope mode - **Managed** (`PUNKTFUNK_GAMESCOPE_MANAGED=1`, and remove the attach line) — the host launches its
(`SCREEN_WIDTH/HEIGHT` in `/etc/gamescope-session-plus/sessions.d/steam`), not the client's. **own** gamescope at the *client's* exact resolution and refresh. Client-mode-following, but there
- **Managed** (`PUNKTFUNK_GAMESCOPE_MANAGED=1`, and remove the attach line) — the host tears the must be no physical gaming session already running.
box's gamescope down on connect and launches its **own** at the *client's* exact resolution and
refresh, restoring on idle. Client-mode-following, but it can't coexist with a box-owned game-mode Full treatment: [Steam / gamescope → Attach vs managed](/docs/gamescope#attach-vs-managed).
session, and there must be **no physical gaming session already running**.
Mid-stream Gaming ↔ Desktop following (`PUNKTFUNK_SESSION_WATCH`) is **on by default** on Mid-stream Gaming ↔ Desktop following (`PUNKTFUNK_SESSION_WATCH`) is **on by default** on
Bazzite/SteamOS. See [Configuration](/docs/configuration) for the full list of knobs. Bazzite/SteamOS. See [Configuration](/docs/configuration) for the full list of knobs.
@@ -116,8 +115,8 @@ Bazzite/SteamOS. See [Configuration](/docs/configuration) for the full list of k
The **virtual output** (video) for the Desktop session needs no config — the host package ships an The **virtual output** (video) for the Desktop session needs no config — the host package ships an
`io.unom.Punktfunk.Host.desktop` file whose `X-KDE-Wayland-Interfaces` grants the host KWin's `io.unom.Punktfunk.Host.desktop` file whose `X-KDE-Wayland-Interfaces` grants the host KWin's
restricted screencast protocol on a normal interactive Plasma session (least-privilege, the same restricted screencast protocol on a normal interactive Plasma session (background:
mechanism krfb/krdp use). After a **fresh host install, log out and back into the Desktop session [KDE Plasma](/docs/kde)). After a **fresh host install, log out and back into the Desktop session
once** so KWin re-reads that grant. once** so KWin re-reads that grant.
The one thing a normal KDE login lacks is the RemoteDesktop grant for headless **input** injection. The one thing a normal KDE login lacks is the RemoteDesktop grant for headless **input** injection.
@@ -138,26 +137,11 @@ Desktop; it follows whichever the box is in.
```sh ```sh
systemctl --user enable --now punktfunk-host systemctl --user enable --now punktfunk-host
# Web console (pairing + status) — enable it and read the auto-generated login password, systemctl --user enable --now punktfunk-web # web console: pairing + status
# then open http://<host-ip>:47992:
systemctl --user enable --now punktfunk-web
journalctl --user -u punktfunk-web-init | sed -n 's/.*password generated: //p'
``` ```
### Console login password Then open [The Web Console](/docs/web-console) for the login password and to
[arm pairing](/docs/web-console#arm-pairing).
The console is password-protected. On first start `punktfunk-web-init` generates a random login
password and saves it to `~/.config/punktfunk/web-password` (as `PUNKTFUNK_UI_PASSWORD=…`). Read it
back at any time — from the init service's journal, or straight from the file:
```sh
journalctl --user -u punktfunk-web-init | sed -n 's/.*password generated: //p'
sed -n 's/^PUNKTFUNK_UI_PASSWORD=//p' ~/.config/punktfunk/web-password
```
To set your own password, edit that file (`PUNKTFUNK_UI_PASSWORD=<your-password>`) and restart the
console: `systemctl --user restart punktfunk-web`. Forgot it? This is the recovery path linked from
the console login screen — see [Forgot your Password?](/docs/forgot-password).
## Good to know ## Good to know
@@ -170,5 +154,7 @@ These apply to the **Gaming Mode (gamescope)** path; the KDE Desktop path is una
- **HDR isn't supported yet** on the gamescope path — gamescope's capture output is 8-bit. SDR streams - **HDR isn't supported yet** on the gamescope path — gamescope's capture output is 8-bit. SDR streams
normally. normally.
Canonical list: [gamescope → Known limits](/docs/gamescope#known-limits).
Then [connect a client](/docs/clients) — Moonlight works great for couch gaming, and the Apple app for Then [connect a client](/docs/clients) — Moonlight works great for couch gaming, and the Apple app for
Apple TV / iPad. Apple TV / iPad.
+4 -2
View File
@@ -48,8 +48,8 @@ let you pick a mode or default to the device's display.)
## gamescope / session following (Linux, Bazzite/SteamOS) ## gamescope / session following (Linux, Bazzite/SteamOS)
Two mutually-exclusive models for a Steam/gamescope box. See [Bazzite](/docs/bazzite) for the full Two mutually-exclusive models for a Steam/gamescope box. See [Steam / gamescope](/docs/gamescope) for
picture. the full picture (and [Bazzite](/docs/bazzite) for that distro's specifics).
| Setting | Values | Meaning | | Setting | Values | Meaning |
|---|---|---| |---|---|---|
@@ -62,6 +62,8 @@ picture.
## Compositor-specific (Linux) ## Compositor-specific (Linux)
See your desktop page ([KDE](/docs/kde), [GNOME](/docs/gnome)) for when to set these.
> **Managing virtual displays** — keep-alive after disconnect, exclusive vs. extend, and (on > **Managing virtual displays** — keep-alive after disconnect, exclusive vs. extend, and (on
> Windows/KDE) persistent per-client scaling — now has its own settings surface in the web console > Windows/KDE) persistent per-client scaling — now has its own settings surface in the web console
> and `display-settings.json`. See [Virtual displays](/docs/virtual-displays). The two > and `display-settings.json`. See [Virtual displays](/docs/virtual-displays). The two
+138
View File
@@ -0,0 +1,138 @@
---
title: Fedora
description: Install the punktfunk host on Fedora from the RPM registry.
---
Install a punktfunk host on **Fedora** from the self-hosted RPM registry. The host installs as an
RPM-managed systemd **`--user`** service and updates with `dnf upgrade` like the rest of your
system — no building required. It works with either **KDE Plasma** or **GNOME**; the
desktop-specific setup (which compositor captures, headless sessions, quirks) lives on the
[desktop configure pages](#3-configure-your-desktop). Host encode is **NVENC on NVIDIA** and **VAAPI on
AMD/Intel** (`PUNKTFUNK_ENCODER=auto` picks per GPU).
> New here? Read [Security & Safe Use](/docs/security) first — a streaming host is remote control of
> the machine, so keep it on a trusted LAN or VPN and require pairing.
Install is two parts: **GPU driver****host RPM**. Then point the host at your desktop from the
[desktop configure pages](#3-configure-your-desktop).
## 1. NVIDIA driver (RPM Fusion akmod)
Enable RPM Fusion (free + nonfree), then install the akmod driver + CUDA. RPM Fusion's nonfree
NVIDIA repo is sometimes pre-enabled on some spins; the full free/nonfree repos below are still
needed (they carry the NVENC ffmpeg in the next step).
```sh
sudo dnf 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
sudo dnf install akmod-nvidia xorg-x11-drv-nvidia-cuda
```
**NVENC ffmpeg.** Fedora ships `ffmpeg-free`, which is built **without** NVENC — the host can't
encode with it. Swap to RPM Fusion's ffmpeg:
```sh
sudo dnf install --allowerasing ffmpeg ffmpeg-libs
ffmpeg -hide_banner -encoders | grep nvenc # expect hevc_nvenc / av1_nvenc / h264_nvenc
```
**Secure Boot.** If `mokutil --sb-state` says *enabled*, the akmod module is signed with a
locally-generated key that must be enrolled once:
```sh
sudo akmods --force # build + sign the module
sudo mokutil --import /etc/pki/akmods/certs/public_key.der # set a one-time password
sudo reboot
```
On the next boot a blue **MOK Manager** screen appears **on the machine's console** (not over
SSH): *Enroll MOK → Continue → Yes → (the password) → Reboot*. Then verify:
```sh
nvidia-smi # driver loads
ffmpeg -hide_banner -encoders | grep nvenc
```
(Or disable Secure Boot in firmware to skip the MOK step — fine for a dedicated test box.)
**AMD / Intel (VAAPI).** No akmod needed — the Mesa stack provides the VAAPI encoder. Install the
freeworld VAAPI drivers for full codec support (`mesa-va-drivers-freeworld` for AMD from RPM Fusion,
`intel-media-driver` for Intel); on a desktop these are usually already present. The host auto-picks
VAAPI on these GPUs.
## 2. Install the host (RPM)
The host is published to the self-hosted Gitea RPM registry, in a per-Fedora-release group (an RPM
is soname-coupled to its base, so Fedora 44 has its own `fedora-44` group). Add the repo and
install:
```sh
sudo tee /etc/yum.repos.d/punktfunk.repo >/dev/null <<'REPO'
[punktfunk]
name=punktfunk
baseurl=https://git.unom.io/api/packages/unom/rpm/fedora-44
enabled=1
# Packages are GPG-signed (gpgcheck=1) AND the repo metadata is Gitea-signed (repo_gpgcheck=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
sudo dnf install punktfunk
sudo usermod -aG input "$USER" # /dev/uinput access for virtual gamepads (re-login to apply)
```
Updates later are just `sudo dnf upgrade punktfunk`. The package ships the systemd user units, the
udev rule, the UDP socket-buffer sysctl tuning, and example configs.
> No matching `fedora-NN` group for your release yet? Build one with the same toolchain CI uses —
> `docker build --build-arg FEDORA_VERSION=NN -f ci/fedora-rpm.Dockerfile -t pf-rpm ci` then run
> `packaging/rpm/build-rpm.sh` inside it — or build from source (appendix below).
## 3. Configure your desktop
How the host creates its virtual display and injects input depends on your desktop, not your distro.
Continue on the page for the desktop you run — it covers your `host.env`, any compositor quirks, and
starting the host:
- [KDE Plasma (KWin)](/docs/kde)
- [GNOME (Mutter)](/docs/gnome)
- [Steam / gamescope](/docs/gamescope)
- [Sway / wlroots](/docs/sway)
Enable the browser management console (status, paired devices, arm pairing) — see
[Web Console](/docs/web-console).
For a headless KWin appliance that streams at boot with no graphical login, see
[KDE → Headless session](/docs/kde#headless-session).
Full config reference: [Configuration](/docs/configuration). Service model:
[Running as a Service](/docs/running-as-a-service).
## 4. Connect a client
From any [client](/docs/clients), `--discover` finds the host on the LAN. On first connect, complete
the **PIN pairing** — arm it from the host's [web console](/docs/web-console#arm-pairing), which
displays a 4-digit PIN to type into the client. See [Clients](/docs/clients) and
[Pairing](/docs/pairing).
## Appendix — build from source
If there's no RPM for your Fedora release and you don't want to build one, compile the host directly
(no clean updates / no packaged units — you wire those up by hand):
```sh
sudo dnf install gcc gcc-c++ make cmake clang clang-devel nasm git \
pipewire-devel wayland-devel wayland-protocols-devel libxkbcommon-devel opus-devel \
libdrm-devel mesa-libgbm-devel mesa-libEGL-devel mesa-libGLES-devel libva-devel \
ffmpeg-devel libei-devel
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
git clone https://git.unom.io/unom/punktfunk.git && cd punktfunk
cargo build --release -p punktfunk-host
```
Then write `~/.config/punktfunk/host.env` (as in `/usr/share/punktfunk/host.env.kde`, but the host
binary is `target/release/punktfunk-host`) and run it inside your desktop session — for a headless
KWin appliance see [KDE → Headless session](/docs/kde#headless-session).
+6 -7
View File
@@ -8,21 +8,20 @@ password. That password is generated — or, on Windows, chosen — when the con
it lives on the **host**. So if you can't get past the login screen, you recover or change it on the it lives on the **host**. So if you can't get past the login screen, you recover or change it on the
host machine itself, not from the browser. host machine itself, not from the browser.
New to the console? See [The Web Console](/docs/web-console) to enable it and arm pairing.
> This is **only** the web console login. It is **not** your client/device pairing — if a client > This is **only** the web console login. It is **not** your client/device pairing — if a client
> won't connect, that's [Pairing](/docs/pairing), not this password. > won't connect, that's [Pairing](/docs/pairing), not this password.
## Find your host ## Find your host
Jump to your host platform for exactly where the password lives and how to read or reset it: Find your host platform for exactly where the password lives, then read or reset it below:
| Host | Where the password lives | Section | | Host | Where the password lives | Section |
|------|--------------------------|---------| |------|--------------------------|---------|
| **Ubuntu — GNOME** | `~/.config/punktfunk/web-password` | [Console login password](/docs/ubuntu-gnome#console-login-password) | | **Linux packages (apt / RPM / Bazzite)** | `~/.config/punktfunk/web-password` | [Login password](/docs/web-console#login-password) |
| **Ubuntu — KDE Plasma** | `~/.config/punktfunk/web-password` | [Console login password](/docs/ubuntu-kde#console-login-password) | | **SteamOS (host)** | `~/.config/punktfunk/web.env` | [Login password](/docs/web-console#login-password) |
| **Fedora — KDE Plasma** | `~/.config/punktfunk/web-password` | [Console login password](/docs/fedora-kde#console-login-password) | | **Windows host** | `%ProgramData%\punktfunk\web-password` | [Login password](/docs/web-console#login-password) · [Windows Host](/docs/windows-host) |
| **Bazzite — gamescope** | `~/.config/punktfunk/web-password` | [Console login password](/docs/bazzite#console-login-password) |
| **SteamOS (host)** | `~/.config/punktfunk/web.env` | [Console login password](/docs/steamos-host#console-login-password) |
| **Windows host** | `%ProgramData%\punktfunk\web-password` | [Console login password](/docs/windows-host#console-login-password) |
## The short version ## The short version
+77
View File
@@ -0,0 +1,77 @@
---
title: Steam / gamescope
description: Configure a gamescope/Steam host — attach vs managed, session following, and limits.
---
gamescope is the compositor behind Steam **Gaming Mode** — the couch/handheld game UI on Bazzite,
SteamOS, or any distro running a gamescope session. The host **auto-detects** gamescope from your
live session, so you rarely need to set anything here. It also **follows a Gaming ↔ Desktop switch
mid-stream** — flip between Gaming Mode and the desktop with Steam's normal UI and the host
re-targets whatever's running without a reconnect.
This page covers the gamescope-specific choices. To get a host running on an appliance box, start
from the install guide for your OS: [Bazzite](/docs/bazzite) or [SteamOS (Host)](/docs/steamos-host).
> New here? Read [Security & Safe Use](/docs/security) first — a streaming host is remote control of
> the machine, so keep it on a trusted LAN or VPN and require pairing.
## Attach vs managed
There are two mutually-exclusive models for a gamescope box; pick one. The shipped default is
**attach**.
- **Attach** (`PUNKTFUNK_GAMESCOPE_ATTACH=1`, the default) — the **box** owns its gamescope session
and decides Gaming vs Desktop via the normal Steam UI. The host just attaches to whatever's live
and never tears it down, so switching Desktop ↔ Game is rock-solid and disconnecting leaves the box
where it was. The streamed game-mode resolution is the box's gamescope mode
(`SCREEN_WIDTH/HEIGHT` in `/etc/gamescope-session-plus/sessions.d/steam`), not the client's.
- **Managed** (`PUNKTFUNK_GAMESCOPE_MANAGED=1`, and remove the attach line) — the host tears the
box's gamescope down on connect and launches its **own** at the *client's* exact resolution and
refresh, restoring on idle. Client-mode-following, but it can't coexist with a box-owned game-mode
session, and there must be **no physical gaming session already running**.
## Session following
`PUNKTFUNK_SESSION_WATCH` follows a Gaming ↔ Desktop switch **mid-stream** — the host rebuilds the
backend in place, with no reconnect. It is **on by default** on Bazzite/SteamOS; set `0` to disable.
One host service covers both faces of the box: it streams Gaming Mode over gamescope and the desktop
over its own compositor, and re-targets whichever is live on each switch.
## Start the host
On an appliance box (Bazzite, SteamOS) the install guide already enables the host service for you. On
any other distro running a gamescope session, start it from your session — the default attach model
just latches onto whatever gamescope session is live:
```sh
systemctl --user enable --now punktfunk-host
```
Then bring up [The Web Console](/docs/web-console) to arm pairing.
## gamescope knobs
The gamescope-specific settings in `host.env`. Leave them unset to auto-detect; set one only to force
a model. See the full [Configuration reference](/docs/configuration) for every other knob.
| Setting | Values | Meaning |
|---|---|---|
| `PUNKTFUNK_GAMESCOPE_ATTACH` | `1` | **Attach** model: the box owns its gamescope session; the host captures whatever's live and never tears it down. Streamed resolution is the box's gamescope mode. The default. |
| `PUNKTFUNK_GAMESCOPE_MANAGED` | `1` | **Managed** model: the host tears the box's gamescope down on connect and launches its own at the client's exact mode, restoring on idle. Doesn't coexist with a box-owned game-mode session. |
| `PUNKTFUNK_GAMESCOPE_SESSION` | `steam` | The host owns a `gamescope-session-plus` (Steam) session at the client's mode — a headless appliance with no physical session running. |
| `PUNKTFUNK_GAMESCOPE_NODE` | `auto` · node id | Discover and capture a **running** gamescope's PipeWire node at a fixed mode. Do **not** combine with `SESSION`. |
| `PUNKTFUNK_GAMESCOPE_APP` | command | For an ad-hoc bare-gamescope session, the nested command to run (e.g. `vkcube`). |
| `PUNKTFUNK_SESSION_WATCH` | `1` · `0` | Follow a Gaming ↔ Desktop switch mid-stream (rebuild in place, no reconnect). On by default on Bazzite/SteamOS; set `0` to disable. |
## Known limits
These apply to the **Gaming Mode (gamescope)** path only; the desktop path is unaffected.
- **gamescope 3.16.22 or newer is required.** Older versions can deadlock during capture. Bazzite's
and SteamOS's current gamescope is fine; this only bites if you've pinned an old one.
- **The mouse cursor isn't included in the captured image** — a gamescope limitation for now.
- **HDR isn't supported on the gamescope path** — gamescope's capture output is 8-bit. SDR streams
normally.
To stream the KDE Plasma desktop of a Steam box instead, see [KDE Plasma](/docs/kde). To bring up the
web console and pair a client, see [The Web Console](/docs/web-console).
+96
View File
@@ -0,0 +1,96 @@
---
title: GNOME (Mutter)
description: Configure a punktfunk host for GNOME — host.env, the EGL/lock traps, and a headless session.
---
Configure a host running **GNOME**. The host drives GNOME's Mutter compositor to create a per-client
virtual display over D-Bus (`RecordVirtual`), zero-copy. This page assumes the host is already
installed — see [Ubuntu](/docs/ubuntu), [Fedora](/docs/fedora), or [Arch](/docs/arch).
> New here? Read [Security & Safe Use](/docs/security) first — a streaming host is remote control of
> the machine, so keep it on a trusted LAN or VPN and require pairing.
## host.env
Write `~/.config/punktfunk/host.env` with the GNOME settings. The host auto-detects the compositor
from your session, so the explicit `PUNKTFUNK_COMPOSITOR` is belt-and-braces:
```ini
# ~/.config/punktfunk/host.env
WAYLAND_DISPLAY=wayland-0
XDG_CURRENT_DESKTOP=GNOME
PUNKTFUNK_COMPOSITOR=mutter
PUNKTFUNK_VIDEO_SOURCE=virtual
PUNKTFUNK_ZEROCOPY=1
PUNKTFUNK_INPUT_BACKEND=libei
```
You must be on a **Wayland** session (not X11), and Mutter must be **≥ 48**. See the
[Configuration reference](/docs/configuration) for every option.
## The GL/EGL userspace
On NVIDIA, gnome-shell fails to start — or the host logs **"GPU … not supported by EGL"** — when the
NVIDIA GL/EGL userspace is missing. The base driver package doesn't always pull it in. Install your
distro's NVIDIA GL/EGL userspace package — on **Ubuntu/Debian** it's `libnvidia-gl-<version>` matching
your driver; on **Fedora/Arch** it ships with the RPM Fusion / repo driver — then confirm the glvnd
vendor file exists:
```sh
ls /usr/share/glvnd/egl_vendor.d/10_nvidia.json # must exist
```
Installing the driver itself is covered on your distro's install page
([Ubuntu](/docs/ubuntu), [Fedora](/docs/fedora), [Arch](/docs/arch)).
## Do not lock the session
A **locked** GNOME session blocks screen capture — the host fails with
**"Session creation inhibited"**. On an always-on or headless host there's no one to unlock it, so
disable the lock:
```sh
gsettings set org.gnome.desktop.screensaver lock-enabled false
gsettings set org.gnome.desktop.session idle-delay 0
```
## Start the host
With `host.env` in place, start the host from **inside your GNOME session**:
```sh
systemctl --user enable --now punktfunk-host
journalctl --user -u punktfunk-host -f # watch it come up and print its identity fingerprint
```
Then bring up [The Web Console](/docs/web-console) to arm pairing and connect a
[client](/docs/clients). For an always-on box, see the [headless session](#headless-session) below.
## Headless session
To run with no monitor and no login, keep a GNOME Wayland session up at all times and start the host
without a login. Have GDM auto-login your user:
```ini
# /etc/gdm3/custom.conf (Ubuntu) · /etc/gdm/custom.conf (Fedora)
[daemon]
AutomaticLoginEnable = true
AutomaticLogin = your-user
```
Disable the lock (see [above](#do-not-lock-the-session)), then enable the host user service and let it
linger past logout:
```sh
systemctl --user enable --now punktfunk-host
sudo loginctl enable-linger "$USER"
```
Reboot and the host comes up on the auto-login session. Full walkthrough:
[Running as a Service](/docs/running-as-a-service).
## Troubleshooting
More fixes — black screen, discovery, pairing — in [Troubleshooting](/docs/troubleshooting).
Once the host is up, bring the console up and pair — see [The Web Console](/docs/web-console).
+1 -1
View File
@@ -68,4 +68,4 @@ LAN.
## Multiple devices at once ## Multiple devices at once
A host can stream to several clients simultaneously — your laptop and your TV both viewing (and A host can stream to several clients simultaneously — your laptop and your TV both viewing (and
controlling) the desktop, each at its own resolution. See [Multiple devices](/docs/configuration#multiple-devices). controlling) the desktop, each at its own resolution. See [Multiple devices](/docs/configuration#multiple-devices-at-once).
+2 -2
View File
@@ -29,7 +29,7 @@ It's built for the things that make streaming feel native:
<Cards> <Cards>
<Card title="How It Works" href="/docs/how-it-works" description="The ideas behind punktfunk in a few minutes — virtual displays, the two protocols, pairing." /> <Card title="How It Works" href="/docs/how-it-works" description="The ideas behind punktfunk in a few minutes — virtual displays, the two protocols, pairing." />
<Card title="Quick Start" href="/docs/quickstart" description="From nothing to streaming: set up a host and connect your first client." /> <Card title="Quick Start" href="/docs/quickstart" description="From nothing to streaming: set up a host and connect your first client." />
<Card title="Host Setup" href="/docs/requirements" description="Install the host on Ubuntu (GNOME or KDE), Fedora (KDE), or Bazzite." /> <Card title="Host Setup" href="/docs/requirements" description="Install on Ubuntu, Fedora, Arch, Bazzite, SteamOS, or Windows." />
<Card title="Connect a Client" href="/docs/clients" description="Stream with the native app for your device — macOS, Linux, Windows, Android — or any Moonlight client." /> <Card title="Connect a Client" href="/docs/clients" description="Stream with the native app for your device — macOS, Linux, Windows, Android — or any Moonlight client." />
<Card title="API Reference" href="/api" description="Interactive OpenAPI reference for the host's management REST API — status, devices, pairing, library." /> <Card title="API Reference" href="/api" description="Interactive OpenAPI reference for the host's management REST API — status, devices, pairing, library." />
</Cards> </Cards>
@@ -37,7 +37,7 @@ It's built for the things that make streaming feel native:
## What you need ## What you need
- A **host** with a supported GPU — either a **Linux** machine running one of the - A **host** with a supported GPU — either a **Linux** machine running one of the
[supported setups](/docs/requirements) (**Ubuntu** GNOME or KDE, **Fedora** KDE, or **Bazzite**), or [supported setups](/docs/requirements) (**Ubuntu**, **Fedora**, **Arch**, or **Bazzite**), or
a **[Windows](/docs/windows-host) PC**. a **[Windows](/docs/windows-host) PC**.
- A **client device** to stream to — there are native apps for **macOS, iOS/iPadOS, tvOS, Linux, - A **client device** to stream to — there are native apps for **macOS, iOS/iPadOS, tvOS, Linux,
Windows, and Android**, plus any device that runs **Moonlight**. Windows, and Android**, plus any device that runs **Moonlight**.
+13 -4
View File
@@ -16,9 +16,9 @@ On **Windows**, the host ships as a signed installer instead — see [Windows](#
| Distro | Package manager | One-command happy path | Guide | | Distro | Package manager | One-command happy path | Guide |
|--------|-----------------|------------------------|-------| |--------|-----------------|------------------------|-------|
| **Ubuntu / Debian** | apt | `sudo apt install punktfunk-host` | [Ubuntu — GNOME](/docs/ubuntu-gnome) · [Ubuntu — KDE](/docs/ubuntu-kde) · [packaging/debian](https://git.unom.io/unom/punktfunk/src/branch/main/packaging/debian/README.md) | | **Ubuntu / Debian** | apt | `sudo apt install punktfunk-host` | [Ubuntu / Debian](/docs/ubuntu) · [packaging/debian](https://git.unom.io/unom/punktfunk/src/branch/main/packaging/debian/README.md) |
| **Bazzite / Fedora Atomic** | systemd-sysext | `sudo bash punktfunk-sysext.sh install` (no layering, no reboot) | [Bazzite](/docs/bazzite) · [packaging/bazzite](https://git.unom.io/unom/punktfunk/src/branch/main/packaging/bazzite/README.md) | | **Bazzite / Fedora Atomic** | systemd-sysext | `sudo bash punktfunk-sysext.sh install` (no layering, no reboot) | [Bazzite](/docs/bazzite) · [packaging/bazzite](https://git.unom.io/unom/punktfunk/src/branch/main/packaging/bazzite/README.md) |
| **Fedora (dnf)** | dnf / rpm-ostree | `dnf install punktfunk punktfunk-web` | [Fedora — KDE](/docs/fedora-kde) · [packaging/rpm](https://git.unom.io/unom/punktfunk/src/branch/main/packaging/rpm/README.md) | | **Fedora (dnf)** | dnf / rpm-ostree | `dnf install punktfunk punktfunk-web` | [Fedora](/docs/fedora) · [packaging/rpm](https://git.unom.io/unom/punktfunk/src/branch/main/packaging/rpm/README.md) |
| **Arch** | pacman | `pacman -Sy punktfunk-host` (binary repo) | [Arch Linux](/docs/arch) · [packaging/arch](https://git.unom.io/unom/punktfunk/src/branch/main/packaging/arch/README.md) | | **Arch** | pacman | `pacman -Sy punktfunk-host` (binary repo) | [Arch Linux](/docs/arch) · [packaging/arch](https://git.unom.io/unom/punktfunk/src/branch/main/packaging/arch/README.md) |
| **SteamOS (host)** | on-device script | `bash scripts/steamdeck/install.sh` | [SteamOS (Host)](/docs/steamos-host) | | **SteamOS (host)** | on-device script | `bash scripts/steamdeck/install.sh` | [SteamOS (Host)](/docs/steamos-host) |
@@ -79,13 +79,22 @@ fallback without one. More detail — including the CLI `punktfunk-host service
Bare `serve` is the secure native-only default (native `punktfunk/1` + the web console). On a Bare `serve` is the secure native-only default (native `punktfunk/1` + the web console). On a
trusted LAN, add `--gamestream` to also serve stock [Moonlight](/docs/moonlight) clients. trusted LAN, add `--gamestream` to also serve stock [Moonlight](/docs/moonlight) clients.
3. Enable the web console and read its login password, then open `http://<host-ip>:47992`: 3. Enable the web console:
```sh ```sh
systemctl --user enable --now punktfunk-web systemctl --user enable --now punktfunk-web
journalctl --user -u punktfunk-web-init | sed -n 's/.*password generated: //p'
``` ```
Then open `http://<host-ip>:47992`. Reading its [login password](/docs/web-console#login-password)
and [arming PIN pairing](/docs/web-console#arm-pairing) are covered in
[The Web Console](/docs/web-console).
### Configure your desktop
How the virtual display and input work depends on your desktop — see [KDE](/docs/kde),
[GNOME](/docs/gnome), [Steam / gamescope](/docs/gamescope), or [Sway](/docs/sway) for the
compositor-specific setup.
From there, follow the [Quick Start](/docs/quickstart) to pair your first client. To run the host From there, follow the [Quick Start](/docs/quickstart) to pair your first client. To run the host
automatically at boot, see [Running as a Service](/docs/running-as-a-service). automatically at boot, see [Running as a Service](/docs/running-as-a-service).
+113
View File
@@ -0,0 +1,113 @@
---
title: KDE Plasma (KWin)
description: Configure a punktfunk host for KDE — host.env, quirks, and a headless KWin session.
---
Configure a punktfunk host on **KDE Plasma**. The host uses KDE's KWin compositor to create a
per-client virtual display, captured zero-copy on NVIDIA. This page assumes the package is already
installed — see [Ubuntu](/docs/ubuntu), [Fedora](/docs/fedora), [Arch](/docs/arch), or the
[Bazzite](/docs/bazzite) appliance.
> New here? Read [Security & Safe Use](/docs/security) first — a streaming host is remote control of
> the machine, so keep it on a trusted LAN or VPN and require pairing.
## host.env
A KDE starter `~/.config/punktfunk/host.env`:
```ini
WAYLAND_DISPLAY=wayland-0
XDG_CURRENT_DESKTOP=KDE
PUNKTFUNK_COMPOSITOR=kwin
PUNKTFUNK_VIDEO_SOURCE=virtual
PUNKTFUNK_ZEROCOPY=1
PUNKTFUNK_INPUT_BACKEND=libei
```
The host auto-detects the running compositor on every connect, so most of this is optional — the
values above are just what it resolves to on a KWin session. See the
[Configuration reference](/docs/configuration) for every option.
## Use a Wayland session
KDE must run on **Wayland**, not X11 — pick the Wayland session from the picker on the login screen.
The virtual-display path is Wayland-only and will not come up under X11.
KWin must be **6.5.6 or newer** (virtual outputs land there). Check with:
```sh
kwin_wayland --version
```
## Streaming the interactive desktop
To stream a logged-in Plasma desktop (rather than a headless session, below), KWin has to hand the
host its restricted screencast protocol. The host package ships an `io.unom.Punktfunk.Host.desktop`
file whose `X-KDE-Wayland-Interfaces` grants exactly that on a normal interactive session
(least-privilege, the same mechanism krfb/krdp use). After a **fresh install, log out and back into
the Desktop session once** so KWin re-reads the grant.
A normal KDE login still lacks the RemoteDesktop grant that **input** injection needs — without it the
host pops an "Allow remote control?" dialog no headless box can answer. **Fedora and Bazzite** ship a
one-shot helper that seeds it (run once as the streaming user, no root):
```sh
bash /usr/share/punktfunk/bazzite/kde-desktop-setup.sh # Fedora / Bazzite
```
The `.deb` and Arch packages don't include that wrapper. Seed the grant by hand instead — copy the
shipped `kde-authorized` file into the portal store (the share dir is `/usr/share/punktfunk-host` on
Debian/Ubuntu, `/usr/share/punktfunk` on Arch), then log out and back in:
```sh
mkdir -p ~/.local/share/flatpak/db
cp /usr/share/punktfunk*/headless/kde-authorized ~/.local/share/flatpak/db/kde-authorized
```
A login-less appliance skips all of this — its headless session (below) needs none of these grants.
## Start the host
With `host.env` in place, start the host from **inside your Plasma session**:
```sh
systemctl --user enable --now punktfunk-host
journalctl --user -u punktfunk-host -f # watch it come up and print its identity fingerprint
```
Then bring up [The Web Console](/docs/web-console) to arm pairing and connect a
[client](/docs/clients). To start at boot — including fully headless — see the
[headless session](#headless-session) below or [Running as a Service](/docs/running-as-a-service).
## Persistent per-client scaling
KWin round-trips per-client display scale: it names each session's virtual output per client, so a
scale you set for one client (150 %, 125 %, …) is reapplied on that client's next connect. See
[Virtual displays](/docs/virtual-displays).
## Headless session
For a login-less appliance — a box that streams at boot with no graphical login — the host brings up a
**dedicated headless KWin session** rather than relying on an interactive one. It runs its own
`kwin --virtual` session (shipped as the `punktfunk-kde-session.service` unit) with permission checks
relaxed, so it needs none of the interactive grants above.
```sh
mkdir -p ~/.config/punktfunk
cp /usr/share/punktfunk/host.env.kde ~/.config/punktfunk/host.env # Debian/Ubuntu: /usr/share/punktfunk-host/host.env.kde
systemctl --user daemon-reload
systemctl --user enable --now punktfunk-kde-session punktfunk-host
sudo loginctl enable-linger "$USER"
```
The session unit brings up headless KWin; the host unit follows it and starts listening. See
[Running as a Service](/docs/running-as-a-service) for the full headless setup.
## Troubleshooting
- **KWin too old:** virtual outputs need KWin **≥ 6.5.6**. Check with `kwin_wayland --version`.
- **Black screen / no picture:** confirm you're on a Wayland session (not X11) and the NVIDIA GL
userspace is installed. More in [Troubleshooting](/docs/troubleshooting).
To bring the console up and pair, see [The Web Console](/docs/web-console).
+13 -9
View File
@@ -5,27 +5,31 @@
"how-it-works", "how-it-works",
"security", "security",
"quickstart", "quickstart",
"install", "---Install the host---",
"---Host Setup---",
"requirements", "requirements",
"ubuntu-gnome", "install",
"ubuntu-kde", "ubuntu",
"fedora-kde", "fedora",
"arch", "arch",
"bazzite", "bazzite",
"steamos-host", "steamos-host",
"windows-host", "windows-host",
"web-console",
"---Configure your desktop---",
"configuration",
"kde",
"gnome",
"gamescope",
"sway",
"running-as-a-service", "running-as-a-service",
"virtual-displays",
"host-cli",
"---Connecting---", "---Connecting---",
"clients", "clients",
"install-client", "install-client",
"steam-deck", "steam-deck",
"moonlight", "moonlight",
"pairing", "pairing",
"---Configuration---",
"configuration",
"virtual-displays",
"host-cli",
"---Troubleshooting---", "---Troubleshooting---",
"troubleshooting", "troubleshooting",
"stats", "stats",
+14 -10
View File
@@ -11,15 +11,19 @@ This is the shortest path to a working stream. Each step links to the details.
## 1. Set up the host ## 1. Set up the host
On your Linux gaming machine (NVIDIA, AMD, or Intel GPU), follow the guide for your system: On your gaming machine (NVIDIA, AMD, or Intel GPU), follow the install guide for your system:
- [Ubuntu — GNOME](/docs/ubuntu-gnome) - [Ubuntu / Debian](/docs/ubuntu)
- [Ubuntu — KDE Plasma](/docs/ubuntu-kde) - [Fedora](/docs/fedora)
- [Fedora — KDE Plasma](/docs/fedora-kde) - [Arch](/docs/arch)
- [Bazzite — gamescope / Steam](/docs/bazzite) - [Bazzite](/docs/bazzite)
- [SteamOS](/docs/steamos-host)
- [Windows host](/docs/windows-host)
Each one covers the GPU driver, the dependencies, and how to build and run the host. Check the Each one covers the GPU driver, the dependencies, and how to install and run the host. After
[Requirements](/docs/requirements) first if you're not sure your machine is a fit. installing, configure for your desktop ([KDE](/docs/kde) / [GNOME](/docs/gnome) /
[gamescope](/docs/gamescope) / [Sway](/docs/sway)). Check the [Requirements](/docs/requirements)
first if you're not sure your machine is a fit.
## 2. Start the host ## 2. Start the host
@@ -44,9 +48,9 @@ latency, or any Moonlight client:
the list of hosts found on your network. Select it, and when prompted, **pair**. the list of hosts found on your network. Select it, and when prompted, **pair**.
- **Anything with Moonlight:** add the host (it should be discovered automatically), then pair. - **Anything with Moonlight:** add the host (it should be discovered automatically), then pair.
To pair, the host needs to show a PIN. Arm pairing from the host's web console — the host displays a To pair, the host needs to show a PIN. [Arm pairing](/docs/web-console#arm-pairing) from the host's
4-digit PIN, you type it into the client, and they trust each other from then on. Pairing is required web console — the host displays a 4-digit PIN, you type it into the client, and they trust each other
by default. Full details: [Pairing & Trust](/docs/pairing). from then on. Pairing is required by default. Full details: [Pairing & Trust](/docs/pairing).
## 4. Stream ## 4. Stream
+28 -20
View File
@@ -6,19 +6,31 @@ description: What you need to run a punktfunk host — GPU, driver, desktop, and
## Supported setups ## Supported setups
A punktfunk host runs primarily on a Linux machine with a dedicated GPU — NVIDIA (NVENC) is the A punktfunk host runs primarily on a Linux machine with a dedicated GPU — NVIDIA (NVENC) is the
most-exercised path, and AMD/Intel GPUs work via VAAPI (a native most-exercised path, and AMD/Intel GPUs work via VAAPI. A native [Windows host](/docs/windows-host)
[Windows host](/docs/windows-host) is also available — see below). These are the Linux desktop is also available. Setup splits along two axes: you **install** the package per distro, then
environments it supports today, each with its own guide: **configure** the host — and learn its quirks — per desktop/compositor.
| Setup | Desktop / compositor | Guide | > New here? Read [Security & Safe Use](/docs/security) first — a streaming host is remote control of
|---|---|---| > the machine, so keep it on a trusted LAN or VPN and require pairing.
| **Ubuntu** (Desktop or Server) | GNOME (Mutter) | [Ubuntu — GNOME](/docs/ubuntu-gnome) |
| **Ubuntu** (Desktop or Server) | KDE Plasma (KWin) | [Ubuntu — KDE](/docs/ubuntu-kde) |
| **Fedora** | KDE Plasma (KWin) | [Fedora — KDE](/docs/fedora-kde) |
| **Bazzite** | gamescope (Steam) | [Bazzite](/docs/bazzite) |
Other wlroots compositors (Sway/Hyprland) also work but aren't a primary target. If your desktop isn't **Distros — install the package:**
listed, the host still needs one of these compositor backends to create a virtual display.
- [Ubuntu / Debian](/docs/ubuntu)
- [Fedora](/docs/fedora)
- [Arch](/docs/arch)
- [Bazzite](/docs/bazzite)
- [SteamOS](/docs/steamos-host)
**Desktops — configure and quirks:**
- [KDE Plasma (KWin)](/docs/kde)
- [GNOME (Mutter)](/docs/gnome)
- [Steam / gamescope](/docs/gamescope)
- [Sway / wlroots](/docs/sway)
Pick your distro to install, then your desktop to configure — the two are independent. Other
wlroots compositors (Hyprland) work but aren't a primary target; the host still needs one of these
compositor backends to create a virtual display.
> **Windows host:** punktfunk also runs as a native host on **Windows 11 22H2 or newer (x64)** — a > **Windows host:** punktfunk also runs as a native host on **Windows 11 22H2 or newer (x64)** — a
> signed installer that registers a service and bundles a virtual-display driver (whose driver- > signed installer that registers a service and bundles a virtual-display driver (whose driver-
@@ -32,8 +44,8 @@ listed, the host still needs one of these compositor backends to create a virtua
encodes the video in hardware. encodes the video in hardware.
- **NVIDIA driver 535 or newer** (550+ recommended). The driver must include the **GL/EGL userspace**, - **NVIDIA driver 535 or newer** (550+ recommended). The driver must include the **GL/EGL userspace**,
not just `nvidia-utils` — without it the compositor can't initialise the GPU and capture fails. Each not just `nvidia-utils` — without it the compositor can't initialise the GPU and capture fails. Each
setup guide installs the right package (e.g. `libnvidia-gl-<version>` on Ubuntu). install guide installs the right package (e.g. `libnvidia-gl-<version>` on Ubuntu).
- **`nvidia-drm modeset=1`** must be enabled (Wayland on NVIDIA needs it). The setup guides cover this. - **`nvidia-drm modeset=1`** must be enabled (Wayland on NVIDIA needs it). The install guides cover this.
- **AMD / Intel GPUs** encode via **VAAPI** instead (install `mesa-va-drivers` or - **AMD / Intel GPUs** encode via **VAAPI** instead (install `mesa-va-drivers` or
`intel-media-driver`; validated live on AMD RDNA3). The NVIDIA-specific notes above don't apply `intel-media-driver`; validated live on AMD RDNA3). The NVIDIA-specific notes above don't apply
there. On modern Intel (Gen12/Tiger Lake and newer, including Arc) the driver only offers the there. On modern Intel (Gen12/Tiger Lake and newer, including Arc) the driver only offers the
@@ -57,9 +69,9 @@ needs to be running for the user the host runs as. This can be:
Minimum compositor versions (newer is fine): Minimum compositor versions (newer is fine):
- **KWin ≥ 6.5.6** (KDE Plasma) — headless virtual outputs. - **KWin ≥ 6.5.6** ([KDE Plasma](/docs/kde)) — headless virtual outputs.
- **GNOME ≥ 48** (Mutter) — virtual-monitor screen-cast. - **GNOME ≥ 48** ([Mutter](/docs/gnome)) — virtual-monitor screen-cast.
- **gamescope ≥ 3.16.22** (Bazzite/Steam) — older versions deadlock during capture. - **gamescope ≥ 3.16.22** ([Bazzite/Steam](/docs/gamescope)) — older versions deadlock during capture.
## Network ## Network
@@ -70,10 +82,6 @@ Minimum compositor versions (newer is fine):
- For best results, a wired or fast Wi-Fi link. The host can run a built-in **speed test** to pick a - For best results, a wired or fast Wi-Fi link. The host can run a built-in **speed test** to pick a
bitrate for your link (see [Configuration](/docs/configuration)). bitrate for your link (see [Configuration](/docs/configuration)).
> **Before you set up a host, read [Security & Safe Use](/docs/security).** A streaming host is
> remote control of the machine — it's important to understand what that exposes, why to keep it on a
> trusted network, and how pairing protects you.
## A client ## A client
You also need something to stream *to* — see [Connect a Client](/docs/clients). There are native You also need something to stream *to* — see [Connect a Client](/docs/clients). There are native
+9 -38
View File
@@ -37,50 +37,21 @@ Start by making the host service start at boot even when nobody logs in:
sudo loginctl enable-linger "$USER" sudo loginctl enable-linger "$USER"
``` ```
Then bring up a session automatically, depending on your desktop: Then bring up a session automatically. How you do that is desktop-specific — auto-login, lock
disable, and the session unit differ per compositor, so each is documented on its own page:
### Headless GNOME - GNOME: [GNOME → Headless session](/docs/gnome#headless-session).
- KDE Plasma: [KDE → Headless session](/docs/kde#headless-session).
- Steam / gamescope: [gamescope](/docs/gamescope) — the host launches its own session per client, so
there's no separate session unit.
Have GDM auto-login your user, so a GNOME Wayland session is always running: Once a session comes up at boot, enable the host user service (section A) and reboot. The host comes up
on that session.
```ini
# /etc/gdm3/custom.conf (Ubuntu) · /etc/gdm/custom.conf (Fedora)
[daemon]
AutomaticLoginEnable = true
AutomaticLogin = your-user
```
Then **disable the screen lock** — a locked GNOME session blocks screen capture, and there's no one to
unlock a headless box:
```sh
gsettings set org.gnome.desktop.screensaver lock-enabled false
gsettings set org.gnome.desktop.session idle-delay 0
```
Enable the host user service (section A) and reboot. The host comes up on the auto-login session.
### Headless KDE
punktfunk ships a unit that brings up a headless KWin/Plasma session with no display manager, so the
host has a desktop to stream even with no monitor attached:
```sh
cp scripts/punktfunk-kde-session.service scripts/punktfunk-host.service ~/.config/systemd/user/
# host.env: PUNKTFUNK_COMPOSITOR=kwin, WAYLAND_DISPLAY=wayland-kde
systemctl --user daemon-reload
systemctl --user enable punktfunk-kde-session punktfunk-host
sudo loginctl enable-linger "$USER"
reboot
```
The session unit starts headless KWin; the host unit follows it and starts listening. (KWin only needs
to be up by the time a client connects, so the ordering is soft.)
### Headless Bazzite ### Headless Bazzite
On Bazzite, the host launches its own gamescope/Steam session per client, so you don't need a separate On Bazzite, the host launches its own gamescope/Steam session per client, so you don't need a separate
session unit — see [Bazzite](/docs/bazzite). session unit — see [Bazzite](/docs/bazzite) and [gamescope](/docs/gamescope).
## Windows ## Windows
+7 -15
View File
@@ -86,9 +86,8 @@ When it finishes it prints the web-console URL and how to pair.
By default the host **requires PIN pairing** (secure). Two ways to pair: By default the host **requires PIN pairing** (secure). Two ways to pair:
- **Web console** (printed at the end of step 2): open `http://<device-ip>:47992`, log in with the - **Web console** (printed at the end of step 2): open `http://<device-ip>:47992`,
generated password (in `~/.config/punktfunk/web.env`), go to **Devices → arm pairing**, and enter [arm pairing](/docs/web-console#arm-pairing), and enter the PIN on your client.
the PIN on your client.
- **From the client directly**: pick this host (it advertises over mDNS as `_punktfunk._udp`) and - **From the client directly**: pick this host (it advertises over mDNS as `_punktfunk._udp`) and
enter the PIN the host shows. enter the PIN the host shows.
@@ -96,17 +95,9 @@ On a trusted home LAN you can instead install with `--open` and skip pairing ent
### Console login password ### Console login password
The installer generates a random console login password and writes it to The installer generates a random console login password (printed at the end of step 2) and writes it
`~/.config/punktfunk/web.env` (as `PUNKTFUNK_UI_PASSWORD=…`); it's also printed at the end of the to `~/.config/punktfunk/web.env`. To read it back or set your own, see
install run (step 2). Read it back with: [The Web Console](/docs/web-console#login-password).
```sh
sed -n 's/^PUNKTFUNK_UI_PASSWORD=//p' ~/.config/punktfunk/web.env
```
To set your own password, edit that file and restart the console:
`systemctl --user restart punktfunk-web`. Forgot it? This is the recovery path linked from the
console login screen — see [Forgot your Password?](/docs/forgot-password).
## 4. Verify ## 4. Verify
@@ -118,7 +109,8 @@ journalctl --user -u punktfunk-host -f # watch a client connect
Connect from a [native client](/docs/clients), or from [Moonlight](/docs/moonlight) (unless you Connect from a [native client](/docs/clients), or from [Moonlight](/docs/moonlight) (unless you
installed with `--no-gamestream`). In Game Mode the host attaches to the running gamescope session and installed with `--no-gamestream`). In Game Mode the host attaches to the running gamescope session and
streams it at your client's resolution; in Desktop Mode it streams the KDE desktop. The host streams it at your client's resolution; in Desktop Mode it streams the KDE desktop. The host
auto-detects which session is live per connection. auto-detects which session is live per connection. See [Steam / gamescope](/docs/gamescope) for the
attach-vs-managed detail and known limits.
## Updating ## Updating
+68
View File
@@ -0,0 +1,68 @@
---
title: Sway / wlroots
description: Configure a punktfunk host on a wlroots compositor (Sway, Hyprland).
---
The wlroots family can host — but **Sway is the only validated path.** The host adds a per-client
headless output at the client's exact mode and captures it through the xdg-desktop-portal-wlr (xdpw)
ScreenCast portal, injecting input via the wlroots virtual pointer/keyboard protocols. Hyprland and
other wlroots compositors are best-effort (see [How it works](#how-it-works) for the caveat).
This is **not a primary target.** It works and is validated live on **sway 1.11** (zero-copy), but it
sees far less testing than the KDE and GNOME paths — expect rougher edges. If you have a choice,
[KDE](/docs/kde) or [GNOME](/docs/gnome) are the better-exercised desktops.
This page assumes the package is already installed — see [Arch](/docs/arch), [Ubuntu](/docs/ubuntu),
or [Fedora](/docs/fedora).
> New here? Read [Security & Safe Use](/docs/security) first — a streaming host is remote control of
> the machine, so keep it on a trusted LAN or VPN and require pairing.
## host.env
The host auto-detects a wlroots session, so you usually need nothing here. To force the backend, set
these in `~/.config/punktfunk/host.env`:
```ini
PUNKTFUNK_COMPOSITOR=wlroots # aliases: sway, hyprland
PUNKTFUNK_INPUT_BACKEND=wlr
PUNKTFUNK_VIDEO_SOURCE=virtual
PUNKTFUNK_ZEROCOPY=1 # GPU zero-copy capture→encode; auto-falls back to CPU
```
See [Configuration](/docs/configuration) for the full reference.
## How it works
- **Video** — the host adds a headless output at the client's exact mode with `swaymsg create_output`.
This uses Sway's IPC specifically; other wlroots compositors (Hyprland, …) don't expose an
equivalent, so virtual-output creation isn't wired up for them yet — Sway is the supported wlroots
path today.
- **Capture** — it captures that output through the **xdg-desktop-portal-wlr (xdpw)** ScreenCast
portal. The host writes a managed chooser config so the output pick is automatic — no interactive
picker dialog to answer.
- **Input** — mouse and keyboard are injected via the wlroots **virtual pointer** and **virtual
keyboard** protocols.
For how long the virtual output lives, and extend-vs-exclusive topology, see
[Virtual displays](/docs/virtual-displays).
## Requirements
- A running wlroots session (Sway, Hyprland, …).
- **xdg-desktop-portal-wlr (xdpw)** installed and running — the host captures through its ScreenCast
portal. Without it there is no video.
## Start the host
With the backend selected, start the host from **inside your Sway session**:
```sh
systemctl --user enable --now punktfunk-host
journalctl --user -u punktfunk-host -f
```
## Bring up the console and pair
Enable the web console, read its login password, and arm PIN pairing — see
[The Web Console](/docs/web-console). Then [connect a client](/docs/clients).
+9 -3
View File
@@ -71,10 +71,14 @@ The NVIDIA **GL/EGL userspace** is missing — the base driver package doesn't a
- **Ubuntu:** `sudo apt install libnvidia-gl-<version>` (matching your driver). - **Ubuntu:** `sudo apt install libnvidia-gl-<version>` (matching your driver).
- Confirm `/usr/share/glvnd/egl_vendor.d/10_nvidia.json` exists and `nvidia-drm modeset` is `Y`. - Confirm `/usr/share/glvnd/egl_vendor.d/10_nvidia.json` exists and `nvidia-drm modeset` is `Y`.
See [GNOME](/docs/gnome) for the GL/EGL userspace details.
## Black screen / no picture, but the client connects ## Black screen / no picture, but the client connects
- You must be on a **Wayland** session, not X11 (check the login-screen session picker). - You must be on a **Wayland** session, not X11 (check the login-screen session picker).
- KWin must be **≥ 6.5.6** (`kwin_wayland --version`); GNOME **≥ 48**; gamescope **≥ 3.16.22**. - KWin must be **≥ 6.5.6** (`kwin_wayland --version`); GNOME **≥ 48**; gamescope **≥ 3.16.22**. See
[KDE](/docs/kde) for the KWin/Wayland requirement and [gamescope](/docs/gamescope) for the
gamescope one.
- Confirm `PUNKTFUNK_COMPOSITOR` in [`host.env`](/docs/configuration) matches your desktop. - Confirm `PUNKTFUNK_COMPOSITOR` in [`host.env`](/docs/configuration) matches your desktop.
## Capture fails: "Session creation inhibited" (GNOME) ## Capture fails: "Session creation inhibited" (GNOME)
@@ -86,7 +90,8 @@ gsettings set org.gnome.desktop.screensaver lock-enabled false
gsettings set org.gnome.desktop.session idle-delay 0 gsettings set org.gnome.desktop.session idle-delay 0
``` ```
See [Running as a Service](/docs/running-as-a-service). See [GNOME → Headless session](/docs/gnome#headless-session) and
[Running as a Service](/docs/running-as-a-service).
## A controller is detected but does nothing (Bazzite) ## A controller is detected but does nothing (Bazzite)
@@ -96,7 +101,8 @@ The host user needs to be in the `input` group. On Bazzite:
ujust add-user-to-input-group ujust add-user-to-input-group
``` ```
Then log out and back in. On other distros this is `sudo usermod -aG input $USER` + re-login. Then log out and back in. On other distros this is `sudo usermod -aG input $USER` + re-login. See
[Bazzite](/docs/bazzite).
## Pairing is rejected / the client can't connect ## Pairing is rejected / the client can't connect
+133
View File
@@ -0,0 +1,133 @@
---
title: Ubuntu / Debian
description: Install the punktfunk host on Ubuntu or Debian with apt.
---
Install a punktfunk host on **Ubuntu** (Desktop or Server) or **Debian** from the apt registry. This
page covers the distro-level setup — GPU driver, package, gamepad access. It works with either GNOME
or KDE; how the host creates its virtual display and injects input is desktop-specific, so pick your
desktop on the [configure pages](#configure-your-desktop) afterward rather than here.
> New here? Read [Security & Safe Use](/docs/security) first — a streaming host is remote control of
> the machine, so keep it on a trusted LAN or VPN and require pairing.
## 1. GPU driver
On **NVIDIA**, install the recommended driver:
```sh
sudo ubuntu-drivers install # or: sudo apt install nvidia-driver-<version>
```
Then make sure the **GL/EGL userspace** is present — Wayland compositors on NVIDIA need it, and the
base driver package doesn't always pull it in. Install the `libnvidia-gl` package matching your
driver version:
```sh
sudo apt install libnvidia-gl-<version> # e.g. libnvidia-gl-550
```
Reboot, then confirm the driver and KMS modeset:
```sh
nvidia-smi
cat /sys/module/nvidia_drm/parameters/modeset # should print Y
```
If modeset is not `Y`:
```sh
echo 'options nvidia-drm modeset=1' | sudo tee /etc/modprobe.d/nvidia-drm.conf
sudo update-initramfs -u && sudo reboot
```
> **Secure Boot:** on a machine with Secure Boot **enabled**, the NVIDIA kernel module won't load
> until you enrol its signing key. If `nvidia-smi` reports it can't talk to the driver, run
> `sudo mokutil --import /var/lib/shim-signed/mok/MOK.der` (set a one-time password), reboot, and
> choose **Enrol MOK** at the blue screen. Or disable Secure Boot in firmware.
On **AMD/Intel** none of the NVIDIA steps apply. Encode runs through VAAPI on the Mesa stack —
`mesa-va-drivers` on AMD, `intel-media-driver` on Intel — which your desktop install already provides.
## 2. Install the host (apt)
`punktfunk-host` is published as a `.deb` to the public Gitea apt registry, so the box installs and
updates with plain `apt`. The registry is public — no auth needed, just trust its signing key:
```sh
sudo install -d -m 0755 /etc/apt/keyrings
curl -fsSL https://git.unom.io/api/packages/unom/debian/repository.key \
| sudo tee /etc/apt/keyrings/punktfunk.asc >/dev/null
echo "deb [signed-by=/etc/apt/keyrings/punktfunk.asc] https://git.unom.io/api/packages/unom/debian stable main" \
| sudo tee /etc/apt/sources.list.d/punktfunk.list
sudo apt update
sudo apt install punktfunk-host
```
`punktfunk-host` `Recommends` the browser console (`punktfunk-web`), so apt pulls it in by default.
The desktop *client* (`punktfunk-client`) is a separate package for the machine you stream *to* — not
installed on a host. The NVIDIA driver is **not** a dependency — you installed it out of band in
step 1. Later updates are just `sudo apt update && sudo apt upgrade`.
The `stable` component above is the stable channel. To track pre-release builds instead, see
[Release Channels](/docs/channels).
## 3. Grant gamepad access
Virtual gamepads inject through `/dev/uinput`, which is gated by the `input` group. Add yourself and
re-login so the new group membership takes effect:
```sh
sudo usermod -aG input "$USER" # re-login to apply
```
## Configure your desktop
How the host creates its virtual display and injects input depends on your desktop, not your distro.
Continue on the page for the desktop you run — it covers your `host.env`, any compositor quirks, and
starting the host:
- [KDE Plasma (KWin)](/docs/kde)
- [GNOME (Mutter)](/docs/gnome)
- [Steam / gamescope](/docs/gamescope)
- [Sway / wlroots](/docs/sway)
Then bring up [The Web Console](/docs/web-console) to arm pairing and connect your first
[client](/docs/clients). To run the host at boot — including fully **headless** — see
[Running as a Service](/docs/running-as-a-service).
## Appendix — build from source
If the apt registry doesn't have a build for your release, or you want to track `main` directly,
compile the host yourself (no clean updates / no packaged units — you wire those up by hand).
Install the build toolchain and runtime libraries:
```sh
sudo apt install build-essential pkg-config cmake clang libclang-dev nasm git curl \
pipewire pipewire-pulse wireplumber libpipewire-0.3-dev libspa-0.2-dev \
libwayland-dev wayland-protocols libxkbcommon-dev libopus-dev \
libdrm-dev libgbm-dev libegl-dev libgles-dev mesa-common-dev libva-dev \
ffmpeg libavcodec-dev libavformat-dev libavutil-dev libswscale-dev libavfilter-dev libavdevice-dev \
libnvidia-egl-wayland1 libnvidia-egl-gbm1 libei-dev
```
Install Rust if you don't have it, then build:
```sh
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
git clone https://git.unom.io/unom/punktfunk.git && cd punktfunk
cargo build --release -p punktfunk-host
```
The host binary lands at `target/release/punktfunk-host`. Configure your desktop as above, then run
it from inside your session:
```sh
cargo run --release -p punktfunk-host -- serve --gamestream
```
(The native plane is always on; `--gamestream` adds the Moonlight-compat surface — trusted LAN only.
Drop it for a secure native-only host.)
+73
View File
@@ -0,0 +1,73 @@
---
title: The Web Console
description: Enable the punktfunk browser console, read or change its login password, and arm PIN pairing.
---
The web console is the browser UI for a punktfunk host — live status, paired devices, and the PIN
pairing flow. It ships as the **`punktfunk-web`** systemd user unit on Linux and the **`PunktfunkWeb`**
task on Windows, and serves on **`http://<host-ip>:47992`**. The host's own management API stays
loopback-only behind it, so the console is the one surface you expose on the LAN.
> New here? Read [Security & Safe Use](/docs/security) first — a streaming host is remote control of
> the machine, so keep it on a trusted LAN or VPN and require pairing.
## Enable the console
- **Linux packages (apt / RPM / Bazzite):** `punktfunk-host` recommends `punktfunk-web`, so your
package manager pulls it in. Enable and start it as your desktop user, then open the URL:
```sh
systemctl --user enable --now punktfunk-web
# then browse to http://<host-ip>:47992
```
- **Windows host:** the installer sets up the console, its runtime, and the `PunktfunkWeb` task and
starts it at boot. There is nothing to enable — open `http://<this-PC>:47992`.
- **SteamOS host:** the install script builds and starts the console as a user service for you. It
prints the URL when it finishes.
## Login password
The console is password-protected. Where that password lives and how you change it depends on the
host platform.
**Linux packages (apt / RPM / Bazzite).** On first start `punktfunk-web-init` generates a random
password and saves it to `~/.config/punktfunk/web-password` (as `PUNKTFUNK_UI_PASSWORD=…`). Read it
back from the init service's journal or straight from the file:
```sh
journalctl --user -u punktfunk-web-init | sed -n 's/.*password generated: //p'
sed -n 's/^PUNKTFUNK_UI_PASSWORD=//p' ~/.config/punktfunk/web-password
```
To set your own, edit that file (`PUNKTFUNK_UI_PASSWORD=<your-password>`) and restart the console:
`systemctl --user restart punktfunk-web`.
**SteamOS host.** Same idea, but the install script writes the generated password to
`~/.config/punktfunk/web.env` and prints it at the end of the install run:
```sh
sed -n 's/^PUNKTFUNK_UI_PASSWORD=//p' ~/.config/punktfunk/web.env
```
Edit that file and `systemctl --user restart punktfunk-web` to change it.
**Windows host.** You choose the password during install — a secure random default is pre-filled and
shown again on the installer's final page. It's stored in `%ProgramData%\punktfunk\web-password` (as
`PUNKTFUNK_UI_PASSWORD=…`), readable only by Administrators and SYSTEM. To change it, edit the file
and restart the task in an **elevated** PowerShell:
```powershell
notepad "$env:ProgramData\punktfunk\web-password" # set PUNKTFUNK_UI_PASSWORD=<your-password>
schtasks /End /TN PunktfunkWeb; schtasks /Run /TN PunktfunkWeb
```
Forgot it? See [Forgot your Password?](/docs/forgot-password).
## Arm pairing
The host **requires PIN pairing** by default (secure on a LAN). To connect the first time, open the
console, log in, and go to **Devices → arm pairing**. The host displays a 4-digit PIN — enter it on
your [client](/docs/clients) to pair. See [Pairing & Trust](/docs/pairing) for the full trust model
and how to approve or remove devices later.
+9 -14
View File
@@ -59,29 +59,24 @@ Packaging internals live in
### Web console & pairing ### Web console & pairing
See [The Web Console](/docs/web-console) for the console + pairing model shared with the Linux host;
the Windows specifics follow.
The installer also sets up the **web management console** (status, paired devices, the PIN pairing The installer also sets up the **web management console** (status, paired devices, the PIN pairing
flow): it bundles the console plus its own runtime and runs it as the **`PunktfunkWeb`** task on flow): it bundles the console plus its own runtime and runs it as the **`PunktfunkWeb`** task on
**`http://<this-PC>:47992`**, starting at boot. **`http://<this-PC>:47992`**, starting at boot.
#### Console login password #### Console login password
During setup you choose the console **login password** — it's pre-filled with a secure random default You choose the console **login password** during setup — a secure random default is pre-filled and
and shown again on the installer's final page. It's stored in `%ProgramData%\punktfunk\web-password` shown on the installer's final page. It's stored in `%ProgramData%\punktfunk\web-password`, readable
(as `PUNKTFUNK_UI_PASSWORD=…`), readable only by Administrators and SYSTEM. only by Administrators and SYSTEM. To read or change it (with the `schtasks` restart), see
[The Web Console → Login password](/docs/web-console#login-password); forgot it entirely?
To change it, edit that file and restart the console task. In an **elevated** PowerShell:
```powershell
notepad "$env:ProgramData\punktfunk\web-password" # set PUNKTFUNK_UI_PASSWORD=<your-password>
schtasks /End /TN PunktfunkWeb; schtasks /Run /TN PunktfunkWeb
```
Forgot it? This is the recovery path linked from the console login screen — see
[Forgot your Password?](/docs/forgot-password). [Forgot your Password?](/docs/forgot-password).
The host **requires PIN pairing** by default (secure on a LAN). To connect the first time, open the The host **requires PIN pairing** by default (secure on a LAN). To connect the first time, open the
console from any browser on the LAN, log in, go to **Devices → arm pairing**, and enter the PIN on console from any browser on the LAN, log in, go to **Devices → [arm pairing](/docs/web-console#arm-pairing)**,
your [client](/docs/clients). The host's own management API stays loopback-only behind the console. and enter the PIN on your [client](/docs/clients). The host's own management API stays loopback-only behind the console.
### Configure ### Configure