feat(host): GameStream/Moonlight compat is now opt-in (--gamestream) — secure native-only by default
apple / swift (push) Successful in 55s
windows-host / package (push) Successful in 2m31s
android / android (push) Successful in 4m40s
ci / rust (push) Successful in 4m43s
ci / web (push) Successful in 30s
ci / docs-site (push) Successful in 34s
deb / build-publish (push) Successful in 2m9s
decky / build-publish (push) Successful in 11s
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 14s
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
docker / build-push (docs-site, docs-site/Dockerfile, punktfunk-docs) (push) Successful in 21s
ci / bench (push) Successful in 4m44s
docker / deploy-docs (push) Successful in 19s
rpm / build-publish (fedora-44, punktfunk-fedora44-rpm) (push) Successful in 8m6s
rpm / build-publish (bazzite, punktfunk-fedora-rpm) (push) Successful in 8m19s
apple / swift (push) Successful in 55s
windows-host / package (push) Successful in 2m31s
android / android (push) Successful in 4m40s
ci / rust (push) Successful in 4m43s
ci / web (push) Successful in 30s
ci / docs-site (push) Successful in 34s
deb / build-publish (push) Successful in 2m9s
decky / build-publish (push) Successful in 11s
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 14s
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
docker / build-push (docs-site, docs-site/Dockerfile, punktfunk-docs) (push) Successful in 21s
ci / bench (push) Successful in 4m44s
docker / deploy-docs (push) Successful in 19s
rpm / build-publish (fedora-44, punktfunk-fedora44-rpm) (push) Successful in 8m6s
rpm / build-publish (bazzite, punktfunk-fedora-rpm) (push) Successful in 8m19s
Follows the security audit (#5/#9): the GameStream-compat plane carries inherent on-path weaknesses that can't be fixed on the wire without breaking stock Moonlight — its pairing runs over plain HTTP (#9, MITM-able during the pairing window) and its legacy control encryption can reuse GCM nonces (#5, a passive eavesdropper can recover/forge input). The native punktfunk/1 plane (SPAKE2 PIN pairing + per-direction AEAD nonces) has neither. So flip the default to secure-by-default: - `serve` → native punktfunk/1 plane + management API ONLY (no GameStream surface). - `serve --gamestream` → ALSO the GameStream/Moonlight-compat planes (nvhttp pairing, RTSP, ENet control, _nvstream mDNS). Opt-in, logged with a trusted-LAN caveat. `--moonlight` is an alias. - The native plane is now ALWAYS on in `serve` (`--native` is a kept-for-compat no-op); the unified GameStream+native host is `serve --gamestream`. `gamestream::serve` gates the GameStream spawns (nvhttp/rtsp/control/mdns) on the flag; the native plane + mgmt + native-pairing handle always run. To avoid silently regressing validated Moonlight deployments, the explicit deployment configs PRESERVE Moonlight via `--gamestream` (each documents dropping it for a secure native-only host): the Linux systemd unit, the Steam Deck installer, and the Windows service default (DEFAULT_HOST_CMD). The bare `serve` default (new/manual use) is secure. Docs swept to match (host-cli, moonlight, quickstart, install, packaging READMEs, CLAUDE.md, README, …): Moonlight setup now instructs `--gamestream`; native/console refs use bare `serve`. OpenAPI regenerated (a stale "run `serve --native`" string). fmt + clippy clean; 94 host tests green. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -43,12 +43,12 @@ The client requests a bitrate; the host encodes to it. To find a good value for
|
||||
|
||||
## Multiple devices at once
|
||||
|
||||
Today the native `punktfunk/1` host (`serve --native`) streams **one session at a time** — additional
|
||||
Today the native `punktfunk/1` host (`serve`) streams **one session at a time** — additional
|
||||
clients wait in the accept queue until the active session ends. Each session gets its own virtual
|
||||
display at the client's exact resolution; concurrent native sessions are on the roadmap.
|
||||
|
||||
(`punktfunk1-host`, the standalone test host, has a `--max-concurrent N` knob, default 4, bounded by your
|
||||
GPU's encoder — see the [Host CLI](/docs/host-cli) reference — but `serve --native` does **not** take
|
||||
GPU's encoder — see the [Host CLI](/docs/host-cli) reference — but `serve` does **not** take
|
||||
that flag.)
|
||||
|
||||
## Codec and FEC
|
||||
|
||||
@@ -116,7 +116,7 @@ mDNS. It requires **PIN pairing** by default (secure on a LAN); pair once from y
|
||||
From any [client](/docs/clients) — `punktfunk-client --discover` finds the host on the LAN. On
|
||||
first connect, complete the PIN pairing — **arm it from the host's web console / mgmt API**, which
|
||||
makes the host display a 4-digit PIN to type into the client. (Pairing is required by default; pass
|
||||
`serve --native --open` only if you deliberately want to disable the requirement.) See
|
||||
`serve --open` only if you deliberately want to disable the requirement.) See
|
||||
[Clients](/docs/clients) and [Running as a Service](/docs/running-as-a-service).
|
||||
|
||||
## Appendix — build from source
|
||||
|
||||
@@ -6,18 +6,30 @@ description: The punktfunk-host commands and the flags you'll actually use.
|
||||
The host is one binary, `punktfunk-host`. Most of the time you'll run a single command; the rest reads
|
||||
its settings from [`host.env`](/docs/configuration).
|
||||
|
||||
## `serve --native`
|
||||
## `serve`
|
||||
|
||||
The normal way to run a host. Starts the unified host: the GameStream server (for Moonlight) **and**
|
||||
the native `punktfunk/1` server, plus the management API/web console — all in one process.
|
||||
The normal way to run a host. By default `serve` starts the **secure native host**: the native
|
||||
`punktfunk/1` server (QUIC, SPAKE2 PIN pairing, per-direction AEAD) plus the management API/web
|
||||
console — all in one process. The native plane is **always on**; there is no flag to turn it off.
|
||||
|
||||
```sh
|
||||
punktfunk-host serve --native
|
||||
punktfunk-host serve
|
||||
```
|
||||
|
||||
Add `--gamestream` (alias `--moonlight`) to **also** run the GameStream/Moonlight-compatible planes
|
||||
(nvhttp pairing, RTSP, ENet control, `_nvstream` mDNS) — required for stock [Moonlight](/docs/moonlight)
|
||||
clients. This is **opt-in** because GameStream carries inherent on-path weaknesses (pairing over plain
|
||||
HTTP; its legacy control encryption can reuse GCM nonces — security-review #5/#9), so enable it **only
|
||||
on a trusted LAN**. The native plane is immune to those issues.
|
||||
|
||||
```sh
|
||||
punktfunk-host serve --gamestream
|
||||
```
|
||||
|
||||
| Flag | Meaning |
|
||||
|---|---|
|
||||
| `--native` | Also run the native `punktfunk/1` server (recommended; enables the native clients and discovery). |
|
||||
| `--gamestream` / `--moonlight` | Also run the GameStream/Moonlight-compat planes (for stock Moonlight clients). Opt-in, trusted-LAN only — see above. |
|
||||
| `--native` | No-op. The native `punktfunk/1` server always runs in `serve`; kept only for backward compatibility. |
|
||||
| `--native-port <PORT>` | Native QUIC port (default `9777`). |
|
||||
| `--open` | Don't require pairing — serve any device on the network. Off by default; only for trusted single-user setups. |
|
||||
| `--mgmt-bind <IP:PORT>` | Management API address (default loopback `127.0.0.1:47990`). |
|
||||
@@ -29,7 +41,7 @@ The management API is **always HTTPS with bearer-token auth**. If you don't pass
|
||||
is auto-generated and persisted to `~/.config/punktfunk/mgmt-token`; `--mgmt-token` only overrides it. A
|
||||
token is **required** when you bind the API off loopback with `--mgmt-bind`.
|
||||
|
||||
By default the host **requires pairing** — see [Pairing & Trust](/docs/pairing). On `serve --native` you
|
||||
By default the host **requires pairing** — see [Pairing & Trust](/docs/pairing). On `serve` you
|
||||
**arm pairing from the web console** (or mgmt API); the host then displays a 4-digit PIN. Pass `--open` to
|
||||
turn off the mandatory-pairing default and serve any device on the network (trusted single-user setups
|
||||
only). The pairing flags below are `punktfunk1-host`-only and do **not** apply to `serve`.
|
||||
@@ -54,10 +66,10 @@ punktfunk-host punktfunk1-host --source virtual
|
||||
| `--require-pairing` | Only serve paired devices (implies `--allow-pairing`). |
|
||||
|
||||
`--max-concurrent`, `--allow-pairing`, and `--require-pairing` are **`punktfunk1-host`-only** — `serve` does not
|
||||
accept them. On `serve --native` you arm pairing from the web console instead, and concurrency is not
|
||||
accept them. On `serve` you arm pairing from the web console instead, and concurrency is not
|
||||
yet capped from the command line.
|
||||
|
||||
Both `serve --native` and `punktfunk1-host` advertise the host on the network so clients can discover it. List
|
||||
Both `serve` and `punktfunk1-host` advertise the host on the network so clients can discover it. List
|
||||
hosts from another machine with `punktfunk-probe --discover`.
|
||||
|
||||
## Environment
|
||||
|
||||
@@ -15,7 +15,7 @@ On **Windows** (NVIDIA), the host ships as a signed installer instead — see [W
|
||||
| **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) |
|
||||
| **Fedora / Bazzite** | rpm-ostree | `rpm-ostree install punktfunk punktfunk-web` | [Fedora — KDE](/docs/fedora-kde) · [Bazzite](/docs/bazzite) · [packaging/rpm](https://git.unom.io/unom/punktfunk/src/branch/main/packaging/rpm/README.md) |
|
||||
| **Arch** | PKGBUILD | `makepkg -si` | [packaging/arch](https://git.unom.io/unom/punktfunk/src/branch/main/packaging/arch/README.md) |
|
||||
| **Steam Deck (host)** | on-device script | `bash scripts/steamdeck/install.sh` | [Steam Deck (Host)](/docs/steam-deck-host) |
|
||||
| **SteamOS (host)** | on-device script | `bash scripts/steamdeck/install.sh` | [SteamOS (Host)](/docs/steamos-host) |
|
||||
|
||||
Each registry is public — no auth, you just trust the repo's signing key. Adding the repo is a
|
||||
one-time step covered in the linked guide; after that, normal `apt upgrade` / `rpm-ostree upgrade`
|
||||
@@ -62,9 +62,12 @@ You need an NVIDIA GPU + driver (the host is NVENC-only on Windows). More detail
|
||||
2. Start the host inside your desktop session:
|
||||
|
||||
```sh
|
||||
punktfunk-host serve --native
|
||||
punktfunk-host serve
|
||||
```
|
||||
|
||||
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.
|
||||
|
||||
3. Enable the web console and read its login password, then open `http://<host-ip>:3000`:
|
||||
|
||||
```sh
|
||||
|
||||
@@ -11,10 +11,20 @@ a browser, a smart TV, or any device without a native client.
|
||||
> discovery/pairing — including **Windows** and **Android** (phone and Android TV). See
|
||||
> [Clients](/docs/clients) before reaching for Moonlight.
|
||||
|
||||
## 1. Make sure the host is running
|
||||
## 1. Make sure the host is running with GameStream enabled
|
||||
|
||||
On the host machine, `serve --native` (or your [service](/docs/running-as-a-service)) should be up.
|
||||
The host advertises itself on the network, so Moonlight usually finds it on its own.
|
||||
Moonlight needs the GameStream planes, which are **opt-in**. Run the host with `--gamestream`:
|
||||
|
||||
```sh
|
||||
punktfunk-host serve --gamestream
|
||||
```
|
||||
|
||||
(Bare `serve` is the secure native-only default and stock Moonlight clients can't connect to it; the
|
||||
native plane is always on, and `--gamestream` adds the Moonlight-compat surface.) GameStream pairs over
|
||||
plain HTTP and its legacy control encryption is weaker than the native plane's, so only enable it on a
|
||||
**trusted LAN**. If you run the host as a [service](/docs/running-as-a-service), make sure its
|
||||
`ExecStart` includes `--gamestream`. The host advertises itself on the network, so Moonlight usually
|
||||
finds it on its own.
|
||||
|
||||
## 2. Add the host in Moonlight
|
||||
|
||||
|
||||
@@ -40,13 +40,13 @@ PIN ceremony before it can stream. It's the right path for the *first* device (b
|
||||
admitted anything) or when you're at the client and the console isn't handy.
|
||||
|
||||
Pairing has to be **armed** on the host before a client can pair (so a random device can't pair
|
||||
itself). On the production host (`serve --native`), this is done from the **web console**: open the
|
||||
itself). On the production host (`serve`), this is done from the **web console**: open the
|
||||
host's management console, click to arm pairing, and the host displays a 4-digit PIN along with the
|
||||
list of paired devices. This works on a headless host over the network — there is no command-line flag
|
||||
to arm pairing on `serve`.
|
||||
|
||||
(The standalone headless test host, `punktfunk1-host`, takes `--allow-pairing`/`--require-pairing` on its
|
||||
command line instead; the production `serve --native` host arms pairing from the console.)
|
||||
command line instead; the production `serve` host arms pairing from the console.)
|
||||
|
||||
Then, on the client:
|
||||
|
||||
@@ -61,7 +61,7 @@ the right setting on a shared network: a device has to complete the PIN ceremony
|
||||
connect.
|
||||
|
||||
If you're on a fully trusted single-user network and want to skip pairing, run the host open with
|
||||
`serve --native --open` (or `punktfunk1-host --allow-tofu` for the standalone host) — it then advertises
|
||||
`serve --open` (or `punktfunk1-host --allow-tofu` for the standalone host) — it then advertises
|
||||
`pair=optional` and accepts unpaired clients. Requiring pairing is strongly recommended.
|
||||
|
||||
## Trust-on-first-use (host opt-in)
|
||||
|
||||
@@ -22,9 +22,11 @@ Each one covers the NVIDIA driver, the dependencies, and how to build and run th
|
||||
From a terminal **inside your desktop session** (so the host can reach your compositor):
|
||||
|
||||
```sh
|
||||
punktfunk-host serve --native
|
||||
punktfunk-host serve
|
||||
```
|
||||
|
||||
This is the secure native-only default — the native `punktfunk/1` plane plus the web console. To also
|
||||
serve stock Moonlight clients, add `--gamestream` (trusted-LAN only; see [Moonlight](/docs/moonlight)).
|
||||
The host starts listening and prints its identity fingerprint. It advertises itself on your local
|
||||
network, so clients can find it by name. Leave it running. (To start it automatically at boot, see
|
||||
[Running as a Service](/docs/running-as-a-service).)
|
||||
|
||||
@@ -29,9 +29,10 @@ see [Status & Progress](/docs/status).
|
||||
|
||||
## ✅ Shipped
|
||||
|
||||
- **The host, two ways.** A GameStream host any [Moonlight](/docs/moonlight) client can use, and the
|
||||
lower-latency native [`punktfunk/1`](/docs/how-it-works) protocol (QUIC control + UDP data with
|
||||
GF(2¹⁶) Leopard FEC + AES-GCM). Both run from one process.
|
||||
- **The host, two ways.** The lower-latency native [`punktfunk/1`](/docs/how-it-works) protocol (QUIC
|
||||
control + UDP data with GF(2¹⁶) Leopard FEC + AES-GCM) — the secure default — and, opt-in via
|
||||
`serve --gamestream`, a GameStream host any [Moonlight](/docs/moonlight) client can use. Both run
|
||||
from one process.
|
||||
- **Native-resolution virtual displays** on Linux across KWin, GNOME/Mutter, gamescope, and
|
||||
Sway/wlroots, with a fully zero-copy GPU path to NVENC (stable 240 fps at 5120×1440).
|
||||
- **A native Windows host** (NVIDIA, x64) — a signed installer with secure-desktop capture and a
|
||||
|
||||
@@ -3,9 +3,14 @@ title: Running as a Service
|
||||
description: Start the host at boot — for a desktop you log into, or a fully headless always-on machine.
|
||||
---
|
||||
|
||||
Running `serve --native` in a terminal is fine for trying punktfunk out. To make a machine an
|
||||
Running `serve` in a terminal is fine for trying punktfunk out. To make a machine an
|
||||
always-available host, run it as a service. There are two cases.
|
||||
|
||||
> The bundled unit `scripts/punktfunk-host.service` runs `serve --gamestream`, so it serves both the
|
||||
> native `punktfunk/1` plane and stock [Moonlight](/docs/moonlight) clients. For a **secure native-only
|
||||
> host** (no GameStream — its pairing runs over plain HTTP and its legacy encryption is weaker;
|
||||
> security-review #5/#9), drop `--gamestream` from the unit's `ExecStart` and use bare `serve`.
|
||||
|
||||
## A. A desktop you log into
|
||||
|
||||
If you sit at the machine (or it auto-logs-in to a desktop), run the host as a **systemd user
|
||||
|
||||
@@ -70,7 +70,7 @@ Then log out and back in. On other distros this is `sudo usermod -aG input $USER
|
||||
manually.
|
||||
- Prefer a **wired** connection or 5 GHz Wi-Fi between host and client.
|
||||
- Streaming to **many devices at once** shares the GPU encoder. The production host
|
||||
(`serve --native`) handles one native session at a time, with extra clients queued; heavy load is
|
||||
(`serve`) handles one native session at a time, with extra clients queued; heavy load is
|
||||
usually bitrate-bound, so lower the bitrate first.
|
||||
|
||||
## Still stuck?
|
||||
|
||||
@@ -148,5 +148,8 @@ The host binary lands at `target/release/punktfunk-host`. Write `~/.config/punkt
|
||||
step 3, then run it inside your GNOME session:
|
||||
|
||||
```sh
|
||||
cargo run --release -p punktfunk-host -- serve --native
|
||||
cargo run --release -p punktfunk-host -- serve --gamestream
|
||||
```
|
||||
|
||||
(The native plane is always on; `--gamestream` adds the Moonlight-compat surface this guide's
|
||||
GameStream ports refer to — trusted LAN only. Drop it for a secure native-only host.)
|
||||
|
||||
@@ -104,5 +104,8 @@ cargo build --release -p punktfunk-host
|
||||
Write `~/.config/punktfunk/host.env` as in step 3, then run it inside your Plasma session:
|
||||
|
||||
```sh
|
||||
cargo run --release -p punktfunk-host -- serve --native
|
||||
cargo run --release -p punktfunk-host -- serve --gamestream
|
||||
```
|
||||
|
||||
(The native plane is always on; `--gamestream` adds the Moonlight-compat surface this guide's
|
||||
GameStream ports refer to — trusted LAN only. Drop it for a secure native-only host.)
|
||||
|
||||
Reference in New Issue
Block a user