The console grew a "Streamed screen" card and the host grew a PUNKTFUNK_CAPTURE_MONITOR knob and a list-monitors command, and the docs knew about none of it — a control with no explanation anywhere. virtual-displays.md gets the feature section: what it is for, that the monitor is never touched, that its resolution wins and a client scales, that a bad name is a hard error rather than a different screen, and that there is no chooser dialog on any of the four backends (which is what makes it work unattended). Plus the three troubleshooting entries the shape of the feature predicts: settings that do nothing while mirroring, a console card the env var has locked, and a pin that names no head. host-cli.md documents list-monitors and mirror-test; configuration.md gets the knob, including that it outranks the console on purpose; running-as-a-service.md gets the desktop-session drop-in and states that the host needs nothing exported to find its session. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
130 lines
7.6 KiB
Markdown
130 lines
7.6 KiB
Markdown
---
|
|
title: Host CLI
|
|
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`
|
|
|
|
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
|
|
```
|
|
|
|
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), so enable it **only on a trusted LAN**. The
|
|
native plane is immune to those issues.
|
|
|
|
```sh
|
|
punktfunk-host serve --gamestream
|
|
```
|
|
|
|
| Flag | Meaning |
|
|
|---|---|
|
|
| `--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 `0.0.0.0:47990` — all interfaces, so paired clients can browse the game library over mTLS; pass `127.0.0.1:47990` to keep it loopback-only). |
|
|
| `--mgmt-token <TOKEN>` | Override the bearer token for the management API. |
|
|
| `--no-mdns` | Skip the mDNS adverts (native + GameStream) — for networks/containers where multicast doesn't work. Clients connect via a manually added host instead. Same as `PUNKTFUNK_MDNS=0`. |
|
|
| `--data-port <PORT>` | Pin the per-session video data plane to this fixed UDP port and stream direct (no hole-punch) — open exactly that port in the host firewall. Same as `PUNKTFUNK_DATA_PORT`; default is a random port + hole-punch. |
|
|
|
|
These are the only flags `serve` accepts.
|
|
|
|
The management API is **always HTTPS**. It binds all interfaces by default so a **paired client** can
|
|
fetch the game library over its mTLS certificate — but off loopback that certificate reaches only the
|
|
read-only status + library endpoints. The **admin surface** (arming pairing, removing devices, session
|
|
control, library edits) authenticates with a **bearer token** and is honored **from loopback only**, so
|
|
it is never LAN-exposed even under the default wide bind. If you don't pass `--mgmt-token`, a token is
|
|
auto-generated and persisted to `~/.config/punktfunk/mgmt-token` (the bundled web console reads the same
|
|
file); `--mgmt-token` only overrides it. Pass `--mgmt-bind 127.0.0.1:47990` to keep 47990 loopback-only.
|
|
Every endpoint is documented in the interactive [**API Reference**](/api).
|
|
|
|
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). `punktfunk1-host` (below) requires pairing by default too; its `--allow-tofu` flag is the
|
|
test-host equivalent of `--open`.
|
|
|
|
## `punktfunk1-host`
|
|
|
|
A standalone native-only host, mainly for testing the `punktfunk/1` path without the GameStream server
|
|
or web console.
|
|
|
|
```sh
|
|
punktfunk-host punktfunk1-host --source virtual
|
|
```
|
|
|
|
| Flag | Meaning |
|
|
|---|---|
|
|
| `--port <N>` | QUIC listen port (default `9777`). |
|
|
| `--source synthetic` · `virtual` | `virtual` uses a real virtual display + NVENC; `synthetic` emits test frames. |
|
|
| `--seconds <N>` / `--frames <N>` | Bound each session by wall-clock seconds or frame count. |
|
|
| `--max-concurrent <N>` | Stream at most N sessions at once (default 4); overflow waits in the queue. |
|
|
| `--max-sessions <N>` | Exit after N sessions (0 = serve forever). |
|
|
| `--allow-tofu` | Also accept **unpaired** clients (trust-on-first-use) and advertise pairing as optional. Pairing is required by default; trusted LANs only. (`--allow-pairing`/`--require-pairing` are the old names for the default behaviour and are accepted as no-ops.) |
|
|
| `--pairing-pin <PIN>` | Use a fixed pairing PIN instead of a fresh random one per ceremony. For test harnesses/CI only — a guessable PIN defeats the ceremony's rate limit. |
|
|
| `--data-port <PORT>` | Pin the video data plane to this fixed UDP port and stream direct (no hole-punch). Same as `PUNKTFUNK_DATA_PORT`. |
|
|
| `--idle-timeout-ms <MS>` | Disconnect-detection latency — the QUIC control-connection idle timeout (default 8000). |
|
|
| `--no-mdns` | Skip the `_punktfunk._udp` advert; clients use `--connect HOST:PORT`. Same as `PUNKTFUNK_MDNS=0`. |
|
|
|
|
`--max-concurrent` and `--allow-tofu` are **`punktfunk1-host`-only** — `serve` does not accept them.
|
|
On `serve` you arm pairing from the web console instead (`--open` is its serve-any-device switch),
|
|
and concurrency is fixed at the built-in default (4 sessions) rather than settable from the command
|
|
line.
|
|
|
|
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`. Where multicast doesn't work (some
|
|
Docker/VLAN setups), pass `--no-mdns` (or set `PUNKTFUNK_MDNS=0`) and add the host in the client by
|
|
address instead.
|
|
|
|
## `list-monitors`
|
|
|
|
`punktfunk-host list-monitors` prints the **physical** monitors this host's compositor has, by
|
|
connector name — which is how you name one for [Streamed
|
|
screen](/docs/virtual-displays#stream-a-real-monitor-instead) (in the console, or as
|
|
`PUNKTFUNK_CAPTURE_MONITOR`).
|
|
|
|
```sh
|
|
punktfunk-host list-monitors
|
|
```
|
|
|
|
```
|
|
Kwin:
|
|
HDMI-A-1 1920x1080@60 at +0,+0 scale 1 Dell U2412M [primary]
|
|
DP-2 2560x1440@144 at +1920,+0 scale 1 ACME 27 [PINNED]
|
|
```
|
|
|
|
Tags flag what's worth knowing before you pick: `primary`, `disabled` (nothing to stream), `punktfunk
|
|
virtual display` (one of ours, not a real head), and `PINNED` for the one currently selected. Linux
|
|
only — it reads the live compositor, so run it in (or with the environment of) the session you want
|
|
to stream.
|
|
|
|
`punktfunk-host mirror-test --monitor <CONNECTOR> [--seconds N] [--cpu]` then proves the whole path —
|
|
mirror, capture, frames — with no client involved. It reports the first frame, the frame count and
|
|
the negotiated size. Screen recording is damage-driven, so move the mouse on the host while it runs;
|
|
an idle desktop legitimately yields almost nothing.
|
|
|
|
## `detect-conflicts`
|
|
|
|
`punktfunk-host detect-conflicts` reports other Moonlight-compatible hosts (Sunshine, Apollo, and
|
|
forks) installed or running on this machine. Running one alongside Punktfunk is **unsupported** —
|
|
they fight over the same ports and virtual-display driver. Prints what it found and exits **1** if
|
|
any conflict exists, **0** if clean (so installers and scripts can gate on it). The host also runs
|
|
this check at `serve` startup and surfaces it in the logs, tray, and — on Windows — the installer.
|
|
See [Troubleshooting → another streaming host is installed](/docs/troubleshooting#another-streaming-host-sunshine-apollo--is-installed).
|
|
|
|
## Environment
|
|
|
|
Most behaviour (compositor, video source, input backend, zero-copy) is set in
|
|
[`host.env`](/docs/configuration), not on the command line. When running as a
|
|
[service](/docs/running-as-a-service), the unit loads `host.env` for you.
|