feat(web,host/windows): move the web console off :3000 to :47992

Port 3000 collides with half the dev-server ecosystem; 47992 sits next
to the mgmt API (47990) in the punktfunk port family. Updates the run
scripts, systemd/scheduled-task units, Dockerfile, Windows firewall
rule + installer, packaging, and every doc that referenced :3000.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
2026-07-02 18:17:42 +00:00
parent 0c17343a50
commit 7fbc7cf76f
31 changed files with 53 additions and 53 deletions
+1 -1
View File
@@ -44,7 +44,7 @@ cargo run -rp punktfunk-host -- serve # native-only (secure defa
cargo run -rp punktfunk-host -- serve --gamestream # + Moonlight compatibility cargo run -rp punktfunk-host -- serve --gamestream # + Moonlight compatibility
``` ```
Then pair from the web console (`https://<host-ip>:3000`) or the client app. Then pair from the web console (`https://<host-ip>:47992`) or the client app.
Most people should install a **package** rather than run from source — see Most people should install a **package** rather than run from source — see
[`packaging/`](../../packaging/README.md) (apt · rpm/COPR/bootc · Arch/sysext · Windows installer) and [`packaging/`](../../packaging/README.md) (apt · rpm/COPR/bootc · Arch/sysext · Windows installer) and
+9 -9
View File
@@ -338,7 +338,7 @@ fn web_setup(args: &[String]) -> Result<()> {
// 1. login password // 1. login password
set_web_password(&pw_path, pw_file.as_deref()); set_web_password(&pw_path, pw_file.as_deref());
// 2. (upgrade-safe) stop any running console so the new task binds :3000 + the files unlock // 2. (upgrade-safe) stop any running console so the new task binds :47992 + the files unlock
stop_web_console(); stop_web_console();
// 3. register the PunktfunkWeb scheduled task // 3. register the PunktfunkWeb scheduled task
let cmd = app_dir.join("web").join("web-run.cmd"); let cmd = app_dir.join("web").join("web-run.cmd");
@@ -346,7 +346,7 @@ fn web_setup(args: &[String]) -> Result<()> {
bail!("web launcher missing: {}", cmd.display()); bail!("web launcher missing: {}", cmd.display());
} }
register_web_task(&cmd)?; register_web_task(&cmd)?;
// 4. firewall: inbound TCP 3000. The console serves HTTPS (HTTP/1.1 over TLS) with the host's // 4. firewall: inbound TCP 47992. The console serves HTTPS (HTTP/1.1 over TLS) with the host's
// identity cert. (No UDP/HTTP-3: browsers won't use QUIC against a self-signed/no-SAN cert.) // identity cert. (No UDP/HTTP-3: browsers won't use QUIC against a self-signed/no-SAN cert.)
if !run_quiet( if !run_quiet(
"netsh", "netsh",
@@ -355,14 +355,14 @@ fn web_setup(args: &[String]) -> Result<()> {
"firewall", "firewall",
"add", "add",
"rule", "rule",
"name=punktfunk web console (TCP 3000)", "name=punktfunk web console (TCP 47992)",
"dir=in", "dir=in",
"action=allow", "action=allow",
"protocol=TCP", "protocol=TCP",
"localport=3000", "localport=47992",
], ],
) { ) {
eprintln!("warning: could not add the firewall rule for TCP 3000"); eprintln!("warning: could not add the firewall rule for TCP 47992");
} }
// 5. wait briefly for the host's mgmt token, then start (restart-on-failure picks it up otherwise) // 5. wait briefly for the host's mgmt token, then start (restart-on-failure picks it up otherwise)
for _ in 0..30 { for _ in 0..30 {
@@ -372,7 +372,7 @@ fn web_setup(args: &[String]) -> Result<()> {
std::thread::sleep(std::time::Duration::from_secs(1)); std::thread::sleep(std::time::Duration::from_secs(1));
} }
run_quiet("schtasks", &["/run", "/tn", WEB_TASK]); run_quiet("schtasks", &["/run", "/tn", WEB_TASK]);
println!("web console set up + started (https://<host-ip>:3000)"); println!("web console set up + started (https://<host-ip>:47992)");
Ok(()) Ok(())
} }
@@ -432,7 +432,7 @@ fn random_password() -> String {
.collect() .collect()
} }
/// Stop + reap a running console before re-registering (upgrade-safe): end the task AND kill the :3000 /// Stop + reap a running console before re-registering (upgrade-safe): end the task AND kill the :47992
/// listener owner (runtime-agnostic - a prior install may have run node vs the current bun). The listener /// listener owner (runtime-agnostic - a prior install may have run node vs the current bun). The listener
/// is identified by the wildcard foreign address (`0.0.0.0:0`/`[::]:0`), so the localized state word /// is identified by the wildcard foreign address (`0.0.0.0:0`/`[::]:0`), so the localized state word
/// ("LISTENING"/"ABHOEREN"/...) is never parsed. /// ("LISTENING"/"ABHOEREN"/...) is never parsed.
@@ -442,7 +442,7 @@ fn stop_web_console() {
let toks: Vec<&str> = line.split_whitespace().collect(); let toks: Vec<&str> = line.split_whitespace().collect();
if toks.len() >= 5 if toks.len() >= 5
&& toks[0].eq_ignore_ascii_case("tcp") && toks[0].eq_ignore_ascii_case("tcp")
&& toks[1].ends_with(":3000") && toks[1].ends_with(":47992")
&& (toks[2] == "0.0.0.0:0" || toks[2] == "[::]:0") && (toks[2] == "0.0.0.0:0" || toks[2] == "[::]:0")
{ {
let pid = toks[toks.len() - 1]; let pid = toks[toks.len() - 1];
@@ -460,7 +460,7 @@ fn register_web_task(cmd: &Path) -> Result<()> {
let xml = format!( let xml = format!(
"<?xml version=\"1.0\" encoding=\"UTF-16\"?>\n\ "<?xml version=\"1.0\" encoding=\"UTF-16\"?>\n\
<Task version=\"1.2\" xmlns=\"http://schemas.microsoft.com/windows/2004/02/mit/task\">\n\ <Task version=\"1.2\" xmlns=\"http://schemas.microsoft.com/windows/2004/02/mit/task\">\n\
<RegistrationInfo><Description>punktfunk web management console (Nitro SSR on bun, :3000)</Description></RegistrationInfo>\n\ <RegistrationInfo><Description>punktfunk web management console (Nitro SSR on bun, :47992)</Description></RegistrationInfo>\n\
<Triggers><BootTrigger><Enabled>true</Enabled></BootTrigger></Triggers>\n\ <Triggers><BootTrigger><Enabled>true</Enabled></BootTrigger></Triggers>\n\
<Principals><Principal id=\"Author\"><UserId>S-1-5-18</UserId><RunLevel>HighestAvailable</RunLevel></Principal></Principals>\n\ <Principals><Principal id=\"Author\"><UserId>S-1-5-18</UserId><RunLevel>HighestAvailable</RunLevel></Principal></Principals>\n\
<Settings>\n\ <Settings>\n\
+1 -1
View File
@@ -40,7 +40,7 @@ the GPU/compositor stack of the box it runs on). What is:
| Image | Source | Notes | | Image | Source | Notes |
|---|---|---| |---|---|---|
| `git.unom.io/unom/punktfunk-web` | `web/Dockerfile` (repo-root context — orval needs `api/openapi.json`) | Nitro `bun` bundle; `PORT` (3000) and `PUNKTFUNK_MGMT_URL` env at runtime | | `git.unom.io/unom/punktfunk-web` | `web/Dockerfile` (repo-root context — orval needs `api/openapi.json`) | Nitro `bun` bundle; `PORT` (47992) and `PUNKTFUNK_MGMT_URL` env at runtime |
| `git.unom.io/unom/punktfunk-docs` | `docs-site/Dockerfile` | This site; `PORT` (3000) | | `git.unom.io/unom/punktfunk-docs` | `docs-site/Dockerfile` | This site; `PORT` (3000) |
| `git.unom.io/unom/punktfunk-rust-ci` | `ci/rust-ci.Dockerfile` | Ubuntu 26.04 + FFmpeg 8/PipeWire/GL/GBM dev libs + a libcuda **link stub** (driver userspace, no kernel module) + pinned rustup — the container `ci.yml`'s Rust job runs in | | `git.unom.io/unom/punktfunk-rust-ci` | `ci/rust-ci.Dockerfile` | Ubuntu 26.04 + FFmpeg 8/PipeWire/GL/GBM dev libs + a libcuda **link stub** (driver userspace, no kernel module) + pinned rustup — the container `ci.yml`'s Rust job runs in |
+3 -3
View File
@@ -157,8 +157,8 @@ and stays. Each subcommand is best-effort (a hiccup warns, never aborts the inst
(pf-vdisplay) or `pnputil /add-driver` per-inf (gamepads - the host SwDeviceCreate's the devnodes). (pf-vdisplay) or `pnputil /add-driver` per-inf (gamepads - the host SwDeviceCreate's the devnodes).
A driver hiccup never aborts the install (the host degrades to a physical display). A driver hiccup never aborts the install (the host degrades to a physical display).
- **Web console (`web setup`):** write the ACL'd `web-password`, register the `PunktfunkWeb` task (boot, - **Web console (`web setup`):** write the ACL'd `web-password`, register the `PunktfunkWeb` task (boot,
SYSTEM, restart-on-failure -> `bun` on `:3000`, via a generated UTF-16 Task Scheduler XML), open TCP SYSTEM, restart-on-failure -> `bun` on `:47992`, via a generated UTF-16 Task Scheduler XML), open TCP
3000, start it. Upgrade-safe: stop + reap any old console (by the `:3000` listener owner, runtime- 47992, start it. Upgrade-safe: stop + reap any old console (by the `:47992` listener owner, runtime-
agnostic - identified by the wildcard foreign address, so the localized state word is never parsed) agnostic - identified by the wildcard foreign address, so the localized state word is never parsed)
before re-registering so the new one can bind. before re-registering so the new one can bind.
@@ -172,7 +172,7 @@ secrets, an ephemeral self-signed cert is generated and its `.cer` published nex
The console is a TanStack Start / Nitro SSR app (`web/`). `vite.config.ts` sets `noExternals: true`, so The console is a TanStack Start / Nitro SSR app (`web/`). `vite.config.ts` sets `noExternals: true`, so
`bun run build` emits a **self-contained `.output`** (~75 files, deps bundled + tree-shaken, no `bun run build` emits a **self-contained `.output`** (~75 files, deps bundled + tree-shaken, no
`node_modules`/`.npmrc`). The installer ships that `.output` + a portable `bun.exe`; the `PunktfunkWeb` `node_modules`/`.npmrc`). The installer ships that `.output` + a portable `bun.exe`; the `PunktfunkWeb`
task runs `bun .output/server/index.mjs` on `:3000`, auto-wired to the host's loopback mgmt API via task runs `bun .output/server/index.mjs` on `:47992`, auto-wired to the host's loopback mgmt API via
`web-run.cmd` (sources `%ProgramData%\punktfunk\mgmt-token` + `web-password`). No node, no node_modules `web-run.cmd` (sources `%ProgramData%\punktfunk\mgmt-token` + `web-password`). No node, no node_modules
forest. (`build-web.ps1` is the dev-box rebuild-and-restart helper.) forest. (`build-web.ps1` is the dev-box rebuild-and-restart helper.)
+1 -1
View File
@@ -129,7 +129,7 @@ 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, # Web console (pairing + status) — enable it and read the auto-generated login password,
# then open http://<host-ip>:3000: # then open http://<host-ip>:47992:
systemctl --user enable --now punktfunk-web systemctl --user enable --now punktfunk-web
journalctl --user -u punktfunk-web-init | sed -n 's/.*password generated: //p' journalctl --user -u punktfunk-web-init | sed -n 's/.*password generated: //p'
``` ```
+1 -1
View File
@@ -114,7 +114,7 @@ mDNS. It requires **PIN pairing** by default (secure on a LAN); pair once from y
### Web console ### Web console
The console (status, paired devices, arm pairing) ships as `punktfunk-web` — enable it, then open The console (status, paired devices, arm pairing) ships as `punktfunk-web` — enable it, then open
`http://<host-ip>:3000`: `http://<host-ip>:47992`:
```sh ```sh
systemctl --user enable --now punktfunk-web systemctl --user enable --now punktfunk-web
+1 -1
View File
@@ -73,7 +73,7 @@ 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>:3000`: 3. Enable the web console and read its login password, then open `http://<host-ip>:47992`:
```sh ```sh
systemctl --user enable --now punktfunk-web systemctl --user enable --now punktfunk-web
+1 -1
View File
@@ -83,7 +83,7 @@ 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>:3000`, log in with the - **Web console** (printed at the end of step 2): open `http://<device-ip>:47992`, log in with the
generated password (in `~/.config/punktfunk/web.env`), go to **Devices → arm pairing**, and enter generated password (in `~/.config/punktfunk/web.env`), go to **Devices → 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
+1 -1
View File
@@ -103,7 +103,7 @@ The console (status, paired devices, arm pairing) ships as `punktfunk-web`:
```sh ```sh
systemctl --user enable --now punktfunk-web systemctl --user enable --now punktfunk-web
# read the auto-generated login password, then open http://<host-ip>:3000 # read the auto-generated login password, then open http://<host-ip>:47992
journalctl --user -u punktfunk-web-init | sed -n 's/.*password generated: //p' journalctl --user -u punktfunk-web-init | sed -n 's/.*password generated: //p'
``` ```
+1 -1
View File
@@ -76,7 +76,7 @@ your [client](/docs/clients).
```sh ```sh
systemctl --user enable --now punktfunk-web systemctl --user enable --now punktfunk-web
# read the auto-generated login password, then open http://<host-ip>:3000 # read the auto-generated login password, then open http://<host-ip>:47992
journalctl --user -u punktfunk-web-init | sed -n 's/.*password generated: //p' journalctl --user -u punktfunk-web-init | sed -n 's/.*password generated: //p'
``` ```
+1 -1
View File
@@ -52,7 +52,7 @@ Packaging internals live in
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>:3000`**, starting at boot. **`http://<this-PC>:47992`**, starting at boot.
#### Console login password #### Console login password
+2 -2
View File
@@ -101,11 +101,11 @@ systemctl --user enable --now punktfunk-host
# Management web console (pairing + status) — pulled in by default (the host RPM Recommends it; # Management web console (pairing + status) — pulled in by default (the host RPM Recommends it;
# `--no-install-recommends` / headless-only boxes can skip it). Enable it and read the login password: # `--no-install-recommends` / headless-only boxes can skip it). Enable it and read the login password:
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 https://<host-ip>:3000 journalctl --user -u punktfunk-web-init | sed -n 's/.*password generated: //p' # then open https://<host-ip>:47992
``` ```
Pair a stock Moonlight client (mDNS-discovered), or connect the native punktfunk/1 client — via the Pair a stock Moonlight client (mDNS-discovered), or connect the native punktfunk/1 client — via the
web console at `https://<host-ip>:3000` or directly. web console at `https://<host-ip>:47992` or directly.
> ⚠️ **COPR caveat:** COPR's mock chroot has no `bun`, so a COPR build produces only > ⚠️ **COPR caveat:** COPR's mock chroot has no `bun`, so a COPR build produces only
> `punktfunk` + `punktfunk-client` — **not** `punktfunk-web`. For the console on a COPR/bootc host, > `punktfunk` + `punktfunk-client` — **not** `punktfunk-web`. For the console on a COPR/bootc host,
+1 -1
View File
@@ -42,7 +42,7 @@ cp /usr/share/punktfunk/host.env.bazzite ~/.config/punktfunk/host.env # gamesc
systemctl --user enable --now punktfunk-host systemctl --user enable --now punktfunk-host
# Web console (if you installed the punktfunk-web package): enable it + read the login password. # Web console (if you installed the punktfunk-web package): enable it + read the login password.
systemctl --user enable --now punktfunk-web systemctl --user enable --now punktfunk-web
journalctl --user -u punktfunk-web-init | sed -n 's/.*password generated: //p' # open https://<host-ip>:3000 journalctl --user -u punktfunk-web-init | sed -n 's/.*password generated: //p' # open https://<host-ip>:47992
``` ```
NVENC/EGL come from the NVIDIA driver: `sudo pacman -S --needed nvidia-utils`. Arch's stock NVENC/EGL come from the NVIDIA driver: `sudo pacman -S --needed nvidia-utils`. Arch's stock
`ffmpeg` already has NVENC built in — no RPM-Fusion-style swap needed (unlike Fedora). `ffmpeg` already has NVENC built in — no RPM-Fusion-style swap needed (unlike Fedora).
+1 -1
View File
@@ -223,7 +223,7 @@ systemctl --user enable --now punktfunk-host
# Management web console (pairing + status), if you installed punktfunk-web (it ships in the Gitea # Management web console (pairing + status), if you installed punktfunk-web (it ships in the Gitea
# RPM registry / bootc image — COPR can't build it; see ../rpm/README.md). Read the login password: # RPM registry / bootc image — COPR can't build it; see ../rpm/README.md). Read the login password:
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 https://<host-ip>:3000 journalctl --user -u punktfunk-web-init | sed -n 's/.*password generated: //p' # then open https://<host-ip>:47992
``` ```
Check health and logs: Check health and logs:
+1 -1
View File
@@ -45,7 +45,7 @@ sudo usermod -aG input "$USER" # virtual gamepads (re-login to take eff
mkdir -p ~/.config/punktfunk mkdir -p ~/.config/punktfunk
cp /usr/share/punktfunk-host/host.env.example ~/.config/punktfunk/host.env # then edit cp /usr/share/punktfunk-host/host.env.example ~/.config/punktfunk/host.env # then edit
systemctl --user enable --now punktfunk-host systemctl --user enable --now punktfunk-host
# Web console — enable it and read the auto-generated login password (then open https://<host-ip>:3000): # Web console — enable it and read the auto-generated login password (then open https://<host-ip>:47992):
systemctl --user enable --now punktfunk-web systemctl --user enable --now punktfunk-web
journalctl --user -u punktfunk-web-init | sed -n 's/.*password generated: //p' journalctl --user -u punktfunk-web-init | sed -n 's/.*password generated: //p'
``` ```
+2 -2
View File
@@ -111,7 +111,7 @@ Homepage: https://git.unom.io/unom/punktfunk
Description: punktfunk management web console (Nitro SSR on bun + React) Description: punktfunk management web console (Nitro SSR on bun + React)
The browser console for a punktfunk streaming host: status, paired devices, and the The browser console for a punktfunk streaming host: status, paired devices, and the
SPAKE2 PIN pairing flow every client needs. Runs as a systemd --user service on port SPAKE2 PIN pairing flow every client needs. Runs as a systemd --user service on port
3000 over HTTPS (HTTP/1.1 over TLS, with the host's own identity cert), login-gated (a 47992 over HTTPS (HTTP/1.1 over TLS, with the host's own identity cert), login-gated (a
password generated on first start), proxying the host's loopback HTTPS management API password generated on first start), proxying the host's loopback HTTPS management API
with a bearer token injected server-side (never sent to the browser). Bundles its own with a bearer token injected server-side (never sent to the browser). Bundles its own
bun runtime (no system nodejs/bun dependency). bun runtime (no system nodejs/bun dependency).
@@ -130,7 +130,7 @@ if [ "$1" = "configure" ]; then
echo "A login password is generated on first start — read it with:" echo "A login password is generated on first start — read it with:"
echo " journalctl --user -u punktfunk-web-init | sed -n 's/.*password generated: //p'" echo " journalctl --user -u punktfunk-web-init | sed -n 's/.*password generated: //p'"
echo " (or: sed -n 's/^PUNKTFUNK_UI_PASSWORD=//p' ~/.config/punktfunk/web-password)" echo " (or: sed -n 's/^PUNKTFUNK_UI_PASSWORD=//p' ~/.config/punktfunk/web-password)"
echo "Then open https://<host-ip>:3000 (self-signed host cert — trust it once)" echo "Then open https://<host-ip>:47992 (self-signed host cert — trust it once)"
fi fi
exit 0 exit 0
EOF EOF
+1 -1
View File
@@ -84,7 +84,7 @@ ujust add-user-to-input-group # virtual gamepads need /dev/uinput (re-
mkdir -p ~/.config/punktfunk mkdir -p ~/.config/punktfunk
cp /usr/share/punktfunk/host.env.bazzite ~/.config/punktfunk/host.env # gamescope defaults cp /usr/share/punktfunk/host.env.bazzite ~/.config/punktfunk/host.env # gamescope defaults
systemctl --user enable --now punktfunk-host systemctl --user enable --now punktfunk-host
# Web console — enable it and read the auto-generated login password (then open http://<host-ip>:3000): # Web console — enable it and read the auto-generated login password (then open http://<host-ip>:47992):
systemctl --user enable --now punktfunk-web systemctl --user enable --now punktfunk-web
journalctl --user -u punktfunk-web-init | sed -n 's/.*password generated: //p' journalctl --user -u punktfunk-web-init | sed -n 's/.*password generated: //p'
``` ```
+2 -2
View File
@@ -45,7 +45,7 @@ parse breakage that silently failed installs on non-English boxes.
password (pre-filled with a secure random default, shown again on the final page; kept on upgrade), password (pre-filled with a secure random default, shown again on the final page; kept on upgrade),
then `punktfunk-host.exe web setup` writes the ACL'd `%ProgramData%\punktfunk\web-password`, registers the then `punktfunk-host.exe web setup` writes the ACL'd `%ProgramData%\punktfunk\web-password`, registers the
**`PunktfunkWeb`** scheduled task (boot, SYSTEM, restart-on-failure → `web-run.cmd``bun` on **`PunktfunkWeb`** scheduled task (boot, SYSTEM, restart-on-failure → `web-run.cmd``bun` on
`:3000`), opens TCP 3000, and starts it. It proxies the host's loopback mgmt API with the host's `:47992`), opens TCP 47992, and starts it. It proxies the host's loopback mgmt API with the host's
own `%ProgramData%\punktfunk\mgmt-token`. own `%ProgramData%\punktfunk\mgmt-token`.
- **GameStream (Moonlight) compatibility is a wizard task** (checked by default): the choice is passed - **GameStream (Moonlight) compatibility is a wizard task** (checked by default): the choice is passed
to `service install --gamestream=on|off`, which writes `PUNKTFUNK_HOST_CMD=serve --gamestream` (or to `service install --gamestream=on|off`, which writes `PUNKTFUNK_HOST_CMD=serve --gamestream` (or
@@ -108,7 +108,7 @@ fresh install uses the generated random console password — read it from
| `install-vbcable.ps1` | On-target: seed VB-Audio's cert into `TrustedPublisher`, silently install the bundled VB-CABLE (`-i -h`). Run by the installer's *Install VB-CABLE virtual audio* task; idempotent + always exits 0 (non-fatal). | | `install-vbcable.ps1` | On-target: seed VB-Audio's cert into `TrustedPublisher`, silently install the bundled VB-CABLE (`-i -h`). Run by the installer's *Install VB-CABLE virtual audio* task; idempotent + always exits 0 (non-fatal). |
| `clear-force-integrity.ps1` | Clear the `/INTEGRITYCHECK` PE bit so a self-signed driver loads (reused by every driver build). | | `clear-force-integrity.ps1` | Clear the `/INTEGRITYCHECK` PE bit so a self-signed driver loads (reused by every driver build). |
| `stage-pf-vdisplay.ps1` | Stage the just-built pf-vdisplay bundle + fetch/verify the **pinned** nefcon release. | | `stage-pf-vdisplay.ps1` | Stage the just-built pf-vdisplay bundle + fetch/verify the **pinned** nefcon release. |
| `../../scripts/windows/web-run.cmd` | The `PunktfunkWeb` task action: loads the mgmt token + login password env, runs the bundled `bun` on the Nitro server (`:3000`). | | `../../scripts/windows/web-run.cmd` | The `PunktfunkWeb` task action: loads the mgmt token + login password env, runs the bundled `bun` on the Nitro server (`:47992`). |
| `drivers/` | The all-Rust IddCx **driver source** workspace: the `pf-vdisplay` crate on `wdk-sys` / windows-drivers-rs + the owned `pf-driver-proto` ABI + `wdk-iddcx` / `wdk-probe`, plus `deploy-dev.ps1` (build/sign/install for dev). | | `drivers/` | The all-Rust IddCx **driver source** workspace: the `pf-vdisplay` crate on `wdk-sys` / windows-drivers-rs + the owned `pf-driver-proto` ABI + `wdk-iddcx` / `wdk-probe`, plus `deploy-dev.ps1` (build/sign/install for dev). |
| `reset-pf-vdisplay.ps1` | **Dev:** recover a wedged driver — stop host → reap ghost monitor nodes → reload the adapter → start host (no reboot). See *Dev iteration* below. | | `reset-pf-vdisplay.ps1` | **Dev:** recover a wedged driver — stop host → reap ghost monitor nodes → reload the adapter → start host (no reboot). See *Dev iteration* below. |
| `redeploy-pf-vdisplay.ps1` | **Dev:** one-shot redeploy — (optional) build → stop host → `deploy-dev.ps1 -Install` → reload adapter → start host. | | `redeploy-pf-vdisplay.ps1` | **Dev:** one-shot redeploy — (optional) build → stop host → `deploy-dev.ps1 -Install` → reload adapter → start host. |
+2 -2
View File
@@ -1,4 +1,4 @@
# punktfunk management web console — systemd USER unit (Nitro SSR on bun, port 3000, HTTPS). # punktfunk management web console — systemd USER unit (Nitro SSR on bun, port 47992, HTTPS).
# #
# Installed by the punktfunk-web .deb to /usr/lib/systemd/user/. AUTO-WIRED — no env editing: # Installed by the punktfunk-web .deb to /usr/lib/systemd/user/. AUTO-WIRED — no env editing:
# it sources the host's mgmt token + the generated login password, serves HTTPS (HTTP/1.1 over TLS) # it sources the host's mgmt token + the generated login password, serves HTTPS (HTTP/1.1 over TLS)
@@ -21,7 +21,7 @@ EnvironmentFile=%h/.config/punktfunk/mgmt-token
EnvironmentFile=-%h/.config/punktfunk/web-password EnvironmentFile=-%h/.config/punktfunk/web-password
Environment=PUNKTFUNK_MGMT_URL=https://127.0.0.1:47990 Environment=PUNKTFUNK_MGMT_URL=https://127.0.0.1:47990
Environment=NODE_TLS_REJECT_UNAUTHORIZED=0 Environment=NODE_TLS_REJECT_UNAUTHORIZED=0
Environment=PORT=3000 Environment=PORT=47992
Environment=HOST=0.0.0.0 Environment=HOST=0.0.0.0
# Serve HTTPS (HTTP/1.1 over TLS) with the host's own identity cert; mark the # Serve HTTPS (HTTP/1.1 over TLS) with the host's own identity cert; mark the
# session cookie Secure. The host's `serve` writes these PEMs; if absent at start the unit fails and # session cookie Secure. The host's `serve` writes these PEMs; if absent at start the unit fails and
+1 -1
View File
@@ -47,7 +47,7 @@ Note: unlike a bare `serve` (native-only by default), the Deck install enables `
default so stock Moonlight clients work out of the box; `--no-gamestream` turns that surface off. default so stock Moonlight clients work out of the box; `--no-gamestream` turns that surface off.
Env overrides: `PUNKTFUNK_SRC` (source dir, default `~/punktfunk`), `PUNKTFUNK_BOX` (container name, Env overrides: `PUNKTFUNK_SRC` (source dir, default `~/punktfunk`), `PUNKTFUNK_BOX` (container name,
default `pf2`), `PUNKTFUNK_MGMT_PORT` (47990), `PUNKTFUNK_WEB_PORT` (3000). default `pf2`), `PUNKTFUNK_MGMT_PORT` (47990), `PUNKTFUNK_WEB_PORT` (47992).
## What gets installed ## What gets installed
+1 -1
View File
@@ -29,7 +29,7 @@ SRC="${PUNKTFUNK_SRC:-$HOME/punktfunk}"
BOX="${PUNKTFUNK_BOX:-pf2}" BOX="${PUNKTFUNK_BOX:-pf2}"
BOX_IMAGE="${PUNKTFUNK_BOX_IMAGE:-docker.io/library/debian:trixie}" BOX_IMAGE="${PUNKTFUNK_BOX_IMAGE:-docker.io/library/debian:trixie}"
MGMT_PORT="${PUNKTFUNK_MGMT_PORT:-47990}" MGMT_PORT="${PUNKTFUNK_MGMT_PORT:-47990}"
WEB_PORT="${PUNKTFUNK_WEB_PORT:-3000}" WEB_PORT="${PUNKTFUNK_WEB_PORT:-47992}"
OPEN=0 OPEN=0
WITH_WEB=1 WITH_WEB=1
GAMESTREAM=1 # Moonlight/GameStream compat on by default; --no-gamestream for a secure native-only host GAMESTREAM=1 # Moonlight/GameStream compat on by default; --no-gamestream for a secure native-only host
+1 -1
View File
@@ -15,5 +15,5 @@ if [ ! -s "$PWFILE" ]; then
(umask 077; printf 'PUNKTFUNK_UI_PASSWORD=%s\n' "$PW" > "$PWFILE") (umask 077; printf 'PUNKTFUNK_UI_PASSWORD=%s\n' "$PW" > "$PWFILE")
chmod 600 "$PWFILE" 2>/dev/null || true chmod 600 "$PWFILE" 2>/dev/null || true
echo "punktfunk web console login password generated: $PW" echo "punktfunk web console login password generated: $PW"
echo "(stored in $PWFILE — open http://<host-ip>:3000 and log in)" echo "(stored in $PWFILE — open http://<host-ip>:47992 and log in)"
fi fi
+2 -2
View File
@@ -38,9 +38,9 @@ On an **installed** host (the `setup.exe`) the console is set up automatically
The installer bundles the built (self-contained, no-`node_modules`) `.output` server + a portable The installer bundles the built (self-contained, no-`node_modules`) `.output` server + a portable
bun and runs `punktfunk-host.exe web setup`, which registers the **`PunktfunkWeb`** scheduled task bun and runs `punktfunk-host.exe web setup`, which registers the **`PunktfunkWeb`** scheduled task
(at boot, as SYSTEM, restart-on-failure) running `{app}\web\web-run.cmd` (at boot, as SYSTEM, restart-on-failure) running `{app}\web\web-run.cmd`
`bun …\.output\server\index.mjs` on `:3000`, opens inbound TCP 3000, and writes the login password to `bun …\.output\server\index.mjs` on `:47992`, opens inbound TCP 47992, and writes the login password to
`%ProgramData%\punktfunk\web-password` (ACL'd to Administrators + SYSTEM). The mgmt bearer token it `%ProgramData%\punktfunk\web-password` (ACL'd to Administrators + SYSTEM). The mgmt bearer token it
proxies with is the host's own `%ProgramData%\punktfunk\mgmt-token`. Browse `http://<host-ip>:3000` proxies with is the host's own `%ProgramData%\punktfunk\mgmt-token`. Browse `http://<host-ip>:47992`
and log in with the password the installer shows on its final page. To change it, edit and log in with the password the installer shows on its final page. To change it, edit
`web-password` and re-run the task: `schtasks /run /tn PunktfunkWeb`. `web-password` and re-run the task: `schtasks /run /tn PunktfunkWeb`.
+2 -2
View File
@@ -5,7 +5,7 @@
bun is both the build tool AND the runtime: vite.config's Nitro noExternals bundles every dep bun is both the build tool AND the runtime: vite.config's Nitro noExternals bundles every dep
into the self-contained .output (no node_modules, nothing for bun to fail to resolve), so the into the self-contained .output (no node_modules, nothing for bun to fail to resolve), so the
PunktfunkWeb task runs web\web-run.cmd -> bun .output\server\index.mjs on :3000. PunktfunkWeb task runs web\web-run.cmd -> bun .output\server\index.mjs on :47992.
#> #>
$ErrorActionPreference = 'Stop' $ErrorActionPreference = 'Stop'
$repo = Split-Path (Split-Path $PSScriptRoot) $repo = Split-Path (Split-Path $PSScriptRoot)
@@ -30,6 +30,6 @@ Start-Sleep 2
& schtasks /run /tn $task | Out-Null & schtasks /run /tn $task | Out-Null
Start-Sleep 5 Start-Sleep 5
try { try {
$r = Invoke-WebRequest 'http://127.0.0.1:3000/login' -UseBasicParsing -TimeoutSec 10 $r = Invoke-WebRequest 'http://127.0.0.1:47992/login' -UseBasicParsing -TimeoutSec 10
Write-Host "DONE - web /login -> HTTP $($r.StatusCode)" Write-Host "DONE - web /login -> HTTP $($r.StatusCode)"
} catch { Write-Warning "web restarted but /login check failed: $($_.Exception.Message)" } } catch { Write-Warning "web restarted but /login check failed: $($_.Exception.Message)" }
+1 -1
View File
@@ -34,7 +34,7 @@ for /f "usebackq tokens=1* delims==" %%A in ("%TOKENFILE%") do set "%%A=%%B"
if exist "%PWFILE%" for /f "usebackq tokens=1* delims==" %%A in ("%PWFILE%") do set "%%A=%%B" if exist "%PWFILE%" for /f "usebackq tokens=1* delims==" %%A in ("%PWFILE%") do set "%%A=%%B"
rem Fixed deployment wiring (the Windows analogue of scripts/punktfunk-web.service). rem Fixed deployment wiring (the Windows analogue of scripts/punktfunk-web.service).
set "PORT=3000" set "PORT=47992"
set "HOST=0.0.0.0" set "HOST=0.0.0.0"
set "PUNKTFUNK_MGMT_URL=https://127.0.0.1:47990" set "PUNKTFUNK_MGMT_URL=https://127.0.0.1:47990"
set "NODE_TLS_REJECT_UNAUTHORIZED=0" set "NODE_TLS_REJECT_UNAUTHORIZED=0"
+1 -1
View File
@@ -40,5 +40,5 @@ PUNKTFUNK_UI_TLS_KEY=/home/you/.config/punktfunk/key.pem
PUNKTFUNK_UI_SECURE=1 PUNKTFUNK_UI_SECURE=1
# The Bun server binds these (standard Nitro env): # The Bun server binds these (standard Nitro env):
# PORT=3000 # PORT=47992
# HOST=0.0.0.0 # HOST=0.0.0.0
+3 -3
View File
@@ -4,7 +4,7 @@
# #
# docker build -f web/Dockerfile -t punktfunk-web . # docker build -f web/Dockerfile -t punktfunk-web .
# #
# Runtime: PORT (default 3000) and PUNKTFUNK_MGMT_URL (upstream management API the Nitro # Runtime: PORT (default 47992) and PUNKTFUNK_MGMT_URL (upstream management API the Nitro
# server proxies /api to; see web/server/routes). # server proxies /api to; see web/server/routes).
FROM oven/bun:1 AS build FROM oven/bun:1 AS build
WORKDIR /repo/web WORKDIR /repo/web
@@ -24,6 +24,6 @@ FROM oven/bun:1-slim
WORKDIR /app WORKDIR /app
COPY --from=build /repo/web/.output ./.output COPY --from=build /repo/web/.output ./.output
USER bun USER bun
ENV PORT=3000 ENV PORT=47992
EXPOSE 3000 EXPOSE 47992
CMD ["bun", "run", ".output/server/index.mjs"] CMD ["bun", "run", ".output/server/index.mjs"]
+3 -3
View File
@@ -18,7 +18,7 @@ The `@unom` registry mapping lives in [`.npmrc`](.npmrc); the auth token comes f
```sh ```sh
# from web/ — Bun is the toolchain (https://bun.sh) # from web/ — Bun is the toolchain (https://bun.sh)
bun install # runs `prepare` → codegen (orval + paraglide) bun install # runs `prepare` → codegen (orval + paraglide)
bun run dev # http://localhost:3000 bun run dev # http://localhost:47992
# The dev server proxies /api → https://127.0.0.1:47990 (the host's mgmt API; it serves HTTPS # The dev server proxies /api → https://127.0.0.1:47990 (the host's mgmt API; it serves HTTPS
# with the host's self-signed identity cert — the dev proxy uses `secure: false`). # with the host's self-signed identity cert — the dev proxy uses `secure: false`).
@@ -50,7 +50,7 @@ LAN console.)
```sh ```sh
bun run build # → .output/ (Nitro `bun` preset + our Bun.serve TLS entry) bun run build # → .output/ (Nitro `bun` preset + our Bun.serve TLS entry)
PORT=3000 HOST=0.0.0.0 \ PORT=47992 HOST=0.0.0.0 \
PUNKTFUNK_UI_PASSWORD=PUNKTFUNK_MGMT_TOKEN=\ PUNKTFUNK_UI_PASSWORD=PUNKTFUNK_MGMT_TOKEN=\
PUNKTFUNK_MGMT_URL=https://127.0.0.1:47990 NODE_TLS_REJECT_UNAUTHORIZED=0 \ PUNKTFUNK_MGMT_URL=https://127.0.0.1:47990 NODE_TLS_REJECT_UNAUTHORIZED=0 \
PUNKTFUNK_UI_TLS_CERT=~/.config/punktfunk/cert.pem \ PUNKTFUNK_UI_TLS_CERT=~/.config/punktfunk/cert.pem \
@@ -63,7 +63,7 @@ bun run lint # tsc --noEmit
``` ```
The built **Nitro bun server** SSR-renders the app and is the only thing exposed on the LAN. The built **Nitro bun server** SSR-renders the app and is the only thing exposed on the LAN.
Run it on the same box as the host; it serves the console over HTTPS on `:3000` (or `$PORT`). Run it on the same box as the host; it serves the console over HTTPS on `:47992` (or `$PORT`).
## Auth (backend-for-frontend) ## Auth (backend-for-frontend)
+1 -1
View File
@@ -7,7 +7,7 @@
"prepare": "bun run codegen", "prepare": "bun run codegen",
"codegen": "orval --config orval.config.ts && paraglide-js compile --project ./project.inlang --outdir ./src/paraglide", "codegen": "orval --config orval.config.ts && paraglide-js compile --project ./project.inlang --outdir ./src/paraglide",
"predev": "orval --config orval.config.ts", "predev": "orval --config orval.config.ts",
"dev": "vite dev --port 3000", "dev": "vite dev --port 47992",
"prebuild": "orval --config orval.config.ts", "prebuild": "orval --config orval.config.ts",
"build": "vite build", "build": "vite build",
"start": "bun run .output/server/index.mjs", "start": "bun run .output/server/index.mjs",
+2 -2
View File
@@ -3,7 +3,7 @@ rem punktfunk web console launcher - DEV layout (in-repo tree). The PunktfunkWeb
rem (boot trigger, SYSTEM, restart-on-failure) runs this at startup. It sources the host's mgmt bearer rem (boot trigger, SYSTEM, restart-on-failure) runs this at startup. It sources the host's mgmt bearer
rem token + the console login password from %ProgramData%\punktfunk\, points the /api proxy at the rem token + the console login password from %ProgramData%\punktfunk\, points the /api proxy at the
rem host's loopback HTTPS mgmt API, and serves the self-contained (no-node_modules) Nitro console over rem host's loopback HTTPS mgmt API, and serves the self-contained (no-node_modules) Nitro console over
rem HTTPS (HTTP/1.1 over TLS) on :3000 with the host's identity cert. %~dp0 = <repo>\web\ . rem HTTPS (HTTP/1.1 over TLS) on :47992 with the host's identity cert. %~dp0 = <repo>\web\ .
rem rem
rem DEV vs the installed launcher (scripts\windows\web-run.cmd): the dev host service runs from rem DEV vs the installed launcher (scripts\windows\web-run.cmd): the dev host service runs from
rem target\release (not the installed {app} tree), so this runs the in-repo web\.output. The console rem target\release (not the installed {app} tree), so this runs the in-repo web\.output. The console
@@ -35,7 +35,7 @@ for /f "usebackq tokens=1* delims==" %%A in ("%TOKENFILE%") do set "%%A=%%B"
if exist "%PWFILE%" for /f "usebackq tokens=1* delims==" %%A in ("%PWFILE%") do set "%%A=%%B" if exist "%PWFILE%" for /f "usebackq tokens=1* delims==" %%A in ("%PWFILE%") do set "%%A=%%B"
rem Fixed deployment wiring (the Windows analogue of scripts/punktfunk-web.service). rem Fixed deployment wiring (the Windows analogue of scripts/punktfunk-web.service).
set "PORT=3000" set "PORT=47992"
set "HOST=0.0.0.0" set "HOST=0.0.0.0"
set "PUNKTFUNK_MGMT_URL=https://127.0.0.1:47990" set "PUNKTFUNK_MGMT_URL=https://127.0.0.1:47990"
set "NODE_TLS_REJECT_UNAUTHORIZED=0" set "NODE_TLS_REJECT_UNAUTHORIZED=0"
+2 -2
View File
@@ -3,7 +3,7 @@
# On a `apt install punktfunk-web` install you DO NOT edit anything: the systemd --user units wire # On a `apt install punktfunk-web` install you DO NOT edit anything: the systemd --user units wire
# everything automatically — # everything automatically —
# punktfunk-web.service sets PUNKTFUNK_MGMT_URL=https://127.0.0.1:47990, NODE_TLS_REJECT_UNAUTHORIZED=0, # punktfunk-web.service sets PUNKTFUNK_MGMT_URL=https://127.0.0.1:47990, NODE_TLS_REJECT_UNAUTHORIZED=0,
# PORT=3000, HOST=0.0.0.0, the PUNKTFUNK_UI_TLS_* cert paths + PUNKTFUNK_UI_SECURE=1, and sources: # PORT=47992, HOST=0.0.0.0, the PUNKTFUNK_UI_TLS_* cert paths + PUNKTFUNK_UI_SECURE=1, and sources:
# ~/.config/punktfunk/mgmt-token (written by the host's `serve` — the shared bearer token) # ~/.config/punktfunk/mgmt-token (written by the host's `serve` — the shared bearer token)
# ~/.config/punktfunk/web-password (written by punktfunk-web-init — the console login password) # ~/.config/punktfunk/web-password (written by punktfunk-web-init — the console login password)
# ~/.config/punktfunk/{cert,key}.pem (the host identity — the console serves HTTPS with it) # ~/.config/punktfunk/{cert,key}.pem (the host identity — the console serves HTTPS with it)
@@ -14,7 +14,7 @@
# (its only outbound TLS hop is that loopback connection). # (its only outbound TLS hop is that loopback connection).
PUNKTFUNK_MGMT_URL=https://127.0.0.1:47990 PUNKTFUNK_MGMT_URL=https://127.0.0.1:47990
NODE_TLS_REJECT_UNAUTHORIZED=0 NODE_TLS_REJECT_UNAUTHORIZED=0
PORT=3000 PORT=47992
HOST=0.0.0.0 HOST=0.0.0.0
# Serve the console over HTTPS (HTTP/1.1 over TLS) with the host's own identity cert. BOTH paths # Serve the console over HTTPS (HTTP/1.1 over TLS) with the host's own identity cert. BOTH paths