Files
punktfunk/docs-site/content/docs/windows-host.md
T
enricobuehlerandClaude Fable 5 5926306a4c
windows-host / package (push) Failing after 22s
windows-host / canary-manifest (push) Skipped
windows-host / winget-source (push) Skipped
ci / docs-site (push) Successful in 1m47s
ci / web (push) Successful in 1m53s
ci / rust-arm64 (push) Successful in 1m58s
docker / builders (--build-arg FEDORA_VERSION=44, ci/fedora-rpm.Dockerfile, punktfunk-fedora44-rpm, -f44) (push) Successful in 11s
docker / builders (ci/android-ci.Dockerfile, punktfunk-android-ci) (push) Successful in 9s
docker / builders (ci/arch-ci.Dockerfile, punktfunk-arch-ci) (push) Successful in 7s
docker / builders (ci/fedora-rpm.Dockerfile, punktfunk-fedora-rpm) (push) Successful in 7s
docker / builders (ci/rust-ci-noble.Dockerfile, punktfunk-rust-ci-noble) (push) Successful in 8s
docker / builders (ci/rust-ci.Dockerfile, punktfunk-rust-ci) (push) Successful in 6s
docker / apps (., web/Dockerfile, punktfunk-web) (push) Successful in 58s
apple / swift (push) Successful in 4m45s
deb / build-publish-client-arm64 (push) Successful in 3m28s
docker / apps (docs-site, docs-site/Dockerfile, punktfunk-docs) (push) Successful in 1m27s
deb / build-publish (push) Successful in 5m26s
docker / builders-arm64cross (push) Successful in 6s
android / android (push) Successful in 6m22s
docker / deploy-docs (push) Successful in 38s
ci / rust (push) Successful in 7m10s
deb / build-publish-host (push) Successful in 5m27s
arch / build-publish (push) Successful in 8m42s
rpm / build-publish (44, fedora-44, punktfunk-fedora44-rpm) (push) Successful in 16m58s
rpm / build-publish (43, bazzite, punktfunk-fedora-rpm) (push) Successful in 17m16s
apple / screenshots (push) Successful in 20m19s
feat(windows): the web console becomes a supervised child of the host service
Three silent console outages in one week (0x1 / 0xFFFFFFFF / 0x41306),
each a different proximate cause of the same structural defect: the
console's lifecycle was owned by Task Scheduler — one best-effort start
per boot/logon/install, no retry on a plain non-zero exit, no watchdog —
while the product already shipped a real supervisor.

The service now supervises the console as a second child slot: plain
session-0 spawn (suspended → own no-breakaway kill-on-close job →
resume), started only once the host has written mgmt-token + cert.pem +
key.pem (the cert race dies by construction), secrets read from their
files at every respawn, bun's stdout finally captured in logs\web.log,
doubling backoff 0.5s→60s that never gives up. Session switches never
touch it; a service stop takes it down via the job.

The PunktfunkWeb task is retired: web setup slims to password + legacy
task delete + firewall, the 127-line web-run.cmd batch supervisor is
deleted, an [InstallDelete] entry reaps the stale copy, and service
install now sets SCM crash-recovery actions (restart 1s/5s/60s) since
the console rides on the service process. StopBunRuntimes stays for the
scripting runner + the one migrating upgrade.

Design: punktfunk-planning design/windows-web-console-lifecycle.md

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-31 20:16:19 +02:00

18 KiB

title, description
title description
Windows Host Run the Punktfunk streaming host on a Windows PC — a first-class, all-vendor, virtual-display host.

Set up a Punktfunk host on a Windows 11 PC (22H2 or newer) and stream its desktop or games to any Punktfunk client — or to Moonlight, once you turn on GameStream compatibility (see Configure). A signed installer registers a Windows service that streams at the client's exact resolution and refresh via Punktfunk's own virtual display — including HDR10 (10-bit BT.2020 PQ), which the host turns on for that display itself when a session negotiates it, whatever your desktop's own HDR mode is. The virtual display is created on the fly, so you need no second monitor and no dummy HDMI plug, and capture keeps working even on the secure desktop (UAC prompts, the lock screen).

New to this? Skim Requirements first.

Read Security & Safe Use before you set this up. The Windows host runs as a LocalSystem service (so it can capture the secure desktop and stream headless), which makes it a high-privilege component — keep it on a trusted network, never expose it to the internet, and prefer a dedicated or gaming PC over a machine that holds your most sensitive data.

This page is about the Windows host — streaming from a Windows PC. To stream to a Windows PC, see the Windows client.

Requirements

  • Windows 11 22H2 (build 22621) or newer, x64. Windows 10 — including LTSC — and Windows 11 21H2 are not supported: the virtual-display driver needs the IddCx 1.10 driver framework, which first shipped in Windows 11 22H2. On older Windows the driver installs but can't start ("Punktfunk Virtual Display" shows Code 10 in Device Manager and streaming fails); the installer therefore refuses to run there. ARM64 is not built either (no ARM64 NVIDIA driver, and the virtual-display driver is x64-only).

  • A GPU for hardware encode — the host auto-detects the vendor:

    • NVIDIA → NVENC
    • AMD → AMF
    • Intel → QSV

    No discrete GPU? The host falls back to a software H.264 encoder (higher CPU use, lower quality — fine for light desktop use).

  • No gamepad prerequisite. The virtual gamepad drivers are bundled in the installer — there is nothing else to download. (Earlier builds needed ViGEmBus; it is no longer used.)

Install

Download the signed punktfunk-host-setup-<ver>.exe from the latest release and run it. The installer:

  • drops the host into C:\Program Files\punktfunk and registers + starts the PunktfunkHost service,
  • installs the bundled virtual-display driver (pf-vdisplay) so the host can create per-client displays,
  • installs the bundled virtual gamepad drivers (DualSense, DualShock 4, Xbox 360),
  • registers the bundled HDR Vulkan layer so Vulkan games can enable HDR over the virtual display,
  • installs VB-CABLE (VB-Audio, donationware) as the virtual microphone for client mic passthrough — a checkbox in the installer, ticked by default; clear it, or pass /MERGETASKS="!installaudiocable", if you don't want it,
  • adds a status icon to the notification area (see Status tray),
  • sets up the web management console (see below).

Prefer the CLI, or want the full service/firewall details? See Running as a Service → Windows. Packaging internals live in packaging/windows.

Install with winget

Punktfunk ships the same signed installer through its own winget source. Register the source once per machine, from an elevated terminal:

winget source add -n punktfunk https://winget.punktfunk.unom.io -t Microsoft.Rest
winget install unom.PunktfunkHost

Before it downloads anything, winget shows the package's agreements — the bundled VB-CABLE notice, and that Moonlight compatibility is off by default — and asks you to accept them.

winget install runs setup silently with the same defaults the wizard shows, so the console password is generated for you (see Unattended install). Add --interactive for the full wizard instead (the task checkboxes, the console-password page, the VB-CABLE notice). To change an individual installer task on the silent path, pass the whole switch line through --override — not --custom, which appends and would leave two /MERGETASKS on one command line:

winget install unom.PunktfunkHost --override "/VERYSILENT /SUPPRESSMSGBOXES /NORESTART /SP- /MERGETASKS=gamestream"

The source carries every stable release, so --version <x.y.z> installs a specific one instead of the newest; canary builds are not published there — use the setup .exe for those. Later updates are winget upgrade unom.PunktfunkHost and removal is winget uninstall unom.PunktfunkHost.

About the signatures

Punktfunk signs with its own certificates rather than a publicly trusted one, so Windows warns about an unknown publisher before setup runs. Accepting the prompt is enough. To silence it for good, the matching punktfunk-host-windows_<ver>.cer is published next to the installer and it is the same certificate for every release — the one-time import is in Install → Windows. This applies to the winget path too: winget downloads and runs that same installer.

The bundled drivers carry a second, separate self-signed certificate (CN=punktfunk-driver, SHA-1 thumbprint 4B8493E7CD565758D335F8F4F05C5A7261A13E02). The installer adds it to the machine's Trusted Root and Trusted Publishers stores so Windows will load the drivers; uninstalling removes every copy of it again.

Unattended install

punktfunk-host-setup-<ver>.exe /VERYSILENT /SUPPRESSMSGBOXES /NORESTART /SP-

Keep /SUPPRESSMSGBOXES: without it an unattended run can stop on a message box nobody can see.

A silent run takes the same defaults as the wizard, so add or drop individual options with Inno's /MERGETASKS — a bare name adds a task, a ! prefix removes one. /MERGETASKS="gamestream" turns on Moonlight compatibility; /MERGETASKS="!trayicon" skips the status icon. The task names are installdriver, installgamepad, installaudiocable, installhdrlayer, gamestream, allowpublicfw, startservice and trayicon.

Two things to know before you script it:

  • Setup aborts with a non-zero exit code if another Moonlight-compatible host — Sunshine, Apollo, Vibeshine, Vibepollo or LuminalShine — is installed and its service is set to start on its own. Stop and disable that service first. An installed but disabled host is not flagged.
  • There is no wizard, so the console password is generated for you. Read it afterwards from %ProgramData%\punktfunk\web-password.

Web console & pairing

See The 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 flow): it bundles the console plus its own runtime, and the PunktfunkHost service runs it on https://<this-PC>:47992 — started with the service and restarted automatically if it stops.

Console login password

You choose the console login password during setup — a secure random default is pre-filled and shown on the installer's final page. It's stored in %ProgramData%\punktfunk\web-password, readable only by Administrators and SYSTEM. To read or change it (with the service restart), see The Web Console → Login password; forgot it entirely? Forgot your Password?.

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, open Pairing in the sidebar and click Pair a device (arm pairing), and enter the PIN on your client. The host's own management API keeps every admin action loopback-only; off-loopback it serves only read-only status and game-library browsing to paired clients.

Status tray

The installer also adds a status icon to the notification area — the installer task Show the Punktfunk status icon in the notification area at sign-in, ticked by default (skip it with /MERGETASKS="!trayicon"). It shows at a glance whether the host is stopped, starting, running, degraded or failed, and its menu opens the web console and the logs folder and starts, stops or restarts the service without a terminal — each of those service actions raises its own UAC prompt. Every user who signs in to this PC gets one.

The installer starts the icon straight away when you run the wizard; a silent install (winget, /VERYSILENT) does not, so there it first appears at the next sign-in. Any upgrade closes the running trays to replace the executable — the wizard puts the icon back, and an update you start from the web console relaunches it itself, but after a silent upgrade it stays away until you sign in again. If it is missing while the host is otherwise fine, start one without signing out:

punktfunk-host tray start

punktfunk-host tray status reports whether one is running and where the executable is; punktfunk-host tray stop closes it.

Configure

The service reads %ProgramData%\punktfunk\host.env. The defaults work out of the box; common knobs:

  • PUNKTFUNK_ENCODER=autoauto picks NVENC/AMF/QSV by GPU vendor. Force one with nvenc, amf, qsv, or sw (software). On a multi-GPU box the web console's GPU preference wins: a forced backend whose vendor doesn't match the selected GPU is ignored (the host logs a warning) — remove the stale line rather than fighting it.

  • PUNKTFUNK_HOST_CMD — what the service runs. A fresh install from the setup .exe writes serve: the secure native-only host, Punktfunk clients only. Moonlight/GameStream compatibility is opt-in — tick Enable GameStream (Moonlight) compatibility in the installer (unattended: /MERGETASKS=gamestream), or turn it on afterwards from an elevated prompt:

    punktfunk-host service install --gamestream=on
    punktfunk-host service restart
    

    That writes PUNKTFUNK_HOST_CMD=serve --gamestream (native punktfunk/1 plus the GameStream/Moonlight-compat planes); --gamestream=off puts it back to serve. GameStream pairs over plain HTTP and uses weaker legacy encryption — trusted LAN only. An upgrade never changes your choice, and a hand-edited PUNKTFUNK_HOST_CMD is left alone.

Edit the file, then punktfunk-host service restart (it stops, waits for the service to actually reach Stopped, and starts again); punktfunk-host service status shows the current state. See the Configuration reference for every option.

Logs

The host writes to %ProgramData%\punktfunk\logs\service.log for the service supervisor and host.log for the streaming host itself. Each is rotated to .old at the next start once it passes 10 MB, one generation kept. The web console's Logs tab shows the same stream live. For more detail, set RUST_LOG=debug in host.env and restart the service.

Updating

The web console's Host page shows an Updates card with an Update now button — see Updating the Host. You can also run winget upgrade unom.PunktfunkHost, or simply run the newer punktfunk-host-setup-<ver>.exe over the old install. All three upgrade in place and keep your config, pairings and console password. If an update you started from the console leaves the host crash-looping, the service rolls itself back to the cached previous installer and records why in the Updates card.

Uninstalling

Open Settings → Apps → Installed apps → Punktfunk Host → Uninstall, or run winget uninstall unom.PunktfunkHost. Either way the uninstaller:

  • closes the status icon,
  • stops and removes the PunktfunkHost service and its firewall rules,
  • removes the pf-vdisplay and virtual-gamepad drivers — the device nodes and their driver-store packages — together with the CN=punktfunk-driver certificate it had added,
  • removes the PunktfunkScripting scheduled task (and the legacy PunktfunkWeb task older versions used for the console) and the console firewall rule,
  • unregisters the HDR Vulkan layer,
  • takes C:\Program Files\punktfunk back off the machine PATH.

Three things are left behind on purpose: %ProgramData%\punktfunk (host.env, the host certificate and key, the management token, the console password, your paired devices and the logs — keeping it is what makes a reinstall pick up where you left off), VB-CABLE unless you cleared its checkbox, and the publisher certificate if you imported one by hand. Uninstalling → Windows host shows how to clear each one, and has the same walkthrough for the other platforms.

How it works

The host installs a LocalSystem SCM service that runs from Session 0 and launches a worker into the interactive session (CreateProcessAsUserW). That lets it capture the secure desktop (UAC prompts, the lock screen) and keep streaming across reboots with nobody logged in — the same model Sunshine and Apollo use. Service registration, firewall rules, and the supervisor all live in punktfunk-host service install; the installer just lays the exe down and calls it elevated.

So a healthy Windows host shows two punktfunk-host.exe processes in Task Manager — the Session 0 supervisor and the worker it launched into your session. That is normal. Ending the worker only makes the supervisor start a new one; stop the host with punktfunk-host service stop or from the status icon's menu.

Running as SYSTEM is what makes headless, log-in-optional streaming work — and it's why the host is a high-privilege component worth being deliberate about. Punktfunk mitigates this with user-mode drivers — the virtual display, the virtual gamepads and the virtual pointer are all UMDF, none of ours is kernel-mode (the optional third-party VB-CABLE mic driver is the one exception) — sealed internal channels between the host and its drivers, and Administrators/SYSTEM-only permissions on its secrets. See Security & Safe Use for the full picture, including why we recommend not hosting on your most sensitive machine.

One core, Windows backends

Most of Punktfunk is platform-agnostic. punktfunk-core (protocol, FEC, crypto, session, transport, the C ABI), the QUIC control plane, the GameStream wire logic, the management API, and the per-frame pipeline orchestration are all shared with the Linux host. The Windows host is a set of #[cfg(windows)] backends behind the same traits the Linux host uses:

Subsystem Linux backend Windows backend
Capture xdg ScreenCast portal → PipeWire (dmabuf) IDD direct-push — the pf-vdisplay driver copies finished frames into a host-owned shared GPU texture ring that the host consumes in-process (no Desktop Duplication, no Windows.Graphics.Capture); FP16/10-bit when the session negotiated HDR
Virtual display KWin / Mutter / Sway / gamescope pf-vdisplay signed IDD — create a WxH@Hz monitor per session, capture it, tear it down
Encode NVENC (CUDA) / VAAPI (AMD·Intel) / Vulkan Video / software, plus PyroWave NVENC (NVIDIA) · AMF (AMD) · QSV (Intel) · software H.264 — H.264, HEVC (Main10 / BT.2020 PQ for HDR) and AV1 where the GPU supports it, plus PyroWave
Input — mouse/keyboard libei / wlr protocols SendInput (Win32 VK + absolute mouse)
Input — gamepads uinput Xbox 360 + UHID DualSense/DS4 UMDF virtual pads — DualSense, DualShock 4, Xbox 360 (XUSB) + rumble
Audio capture PipeWire sink-monitor WASAPI loopback
Virtual mic PipeWire Audio/Source VB-CABLE virtual device (optional), captured via WASAPI

The virtual display is pf-vdisplay, Punktfunk's own all-Rust Indirect Display Driver (IDD). The host creates a shared GPU texture ring and the driver pushes finished frames straight into it — a real virtual display at the client's exact WxH@Hz, with no physical monitor and no dummy plug, captured in-process from Session 0 so the secure desktop streams too. There is no Desktop Duplication or Windows.Graphics.Capture path: IDD direct-push is the only capture path. The signed driver is bundled and staged by the installer and is required — without it the host can't create a session (there is no monitor-capture fallback).

HDR

A Windows host is the easiest place to get HDR: for a session that negotiated 10-bit it turns advanced colour on for the virtual display it just created, so you never touch "Use HDR" in Windows Settings. Vulkan games additionally need the bundled layer this installer registers. HDR → Windows has the whole chain, the layer's switches, the one case where the label can outrun the picture, and what to check when a stream comes out SDR.

Notes & limits

  • AMD / Intel encode is newer. The NVENC path is the most exercised; AMF (AMD) and QSV (Intel) are built and tested in CI but less battle-tested on real hardware. Software H.264 is the GPU-less fallback.
  • x64-only. No ARM64 build — no ARM64 NVIDIA driver, and the virtual-display driver is x64-only.
  • Newer than the Linux host. The Linux host is the most battle-tested path; the Windows host is more recent, with the virtual-mic and AMD/Intel encode backends the youngest pieces.

Trouble? See Troubleshooting and Pairing.