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>
7.6 KiB
title, description
| title | description |
|---|---|
| Host CLI | 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.
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.
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
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.
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.
By default the host requires pairing — see Pairing & Trust. 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.
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 (in the console, or as
PUNKTFUNK_CAPTURE_MONITOR).
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.
Environment
Most behaviour (compositor, video source, input backend, zero-copy) is set in
host.env, not on the command line. When running as a
service, the unit loads host.env for you.