diff --git a/.gitea/workflows/installer-smoke.yml b/.gitea/workflows/installer-smoke.yml
index 2084b4b9..836b2079 100644
--- a/.gitea/workflows/installer-smoke.yml
+++ b/.gitea/workflows/installer-smoke.yml
@@ -39,12 +39,15 @@ jobs:
- family: debian-13
image: debian:trixie
prep: apt-get update -qq && apt-get install -y -qq --no-install-recommends ca-certificates curl git nodejs
+ rmweb: apt-get purge -y punktfunk-web
- family: fedora-44
image: fedora:44
prep: dnf install -y -q curl git nodejs
+ rmweb: dnf remove -y punktfunk-web
- family: arch
image: archlinux:base
prep: pacman -Sy --noconfirm --needed curl git nodejs && (pacman-key --init >/dev/null 2>&1 || true)
+ rmweb: pacman -Rns --noconfirm punktfunk-web
container:
image: ${{ matrix.image }}
steps:
@@ -59,8 +62,25 @@ jobs:
run: |
punktfunk-host --version
punktfunk-host detect-conflicts
+ # The console is the whole management surface — pairing, approving a device, every setting.
+ # A host without it can be installed and still be useless, so assert it by name: the binary
+ # the package puts on PATH and the user unit step 6 enables.
+ - name: The web console is installed too
+ run: |
+ command -v punktfunk-web-server
+ test -f /usr/lib/systemd/user/punktfunk-web.service
- name: Re-running is a no-op install
run: sh scripts/install.sh --yes --no-start | grep -q 'already installed'
+ # The reported Fedora failure, as a test: a box that has the host but lost (or never got)
+ # the console must get one back from a re-run. Before the per-package check, the installer
+ # saw punktfunk-host on PATH, declared itself done, and left the box without a console
+ # while still printing the console's URL.
+ - name: A host without a console gets one back on re-run
+ run: |
+ ${{ matrix.rmweb }}
+ ! command -v punktfunk-web-server
+ sh scripts/install.sh --yes --no-start
+ command -v punktfunk-web-server
- name: --uninstall takes the packages and the repo off again
run: |
sh scripts/install.sh --yes --uninstall
diff --git a/data/platforms.json b/data/platforms.json
index 59a2296e..31f385cb 100644
--- a/data/platforms.json
+++ b/data/platforms.json
@@ -81,7 +81,7 @@
"curl -fsSL https://git.unom.io/api/packages/unom/debian/repository.key | sudo tee /etc/apt/keyrings/punktfunk.asc >/dev/null",
"echo \"deb [signed-by=/etc/apt/keyrings/punktfunk.asc] https://git.unom.io/api/packages/unom/debian stable main\" | sudo tee /etc/apt/sources.list.d/punktfunk.list",
"sudo apt update",
- "sudo apt install punktfunk-host"
+ "sudo apt install punktfunk-host punktfunk-web punktfunk-scripting"
]
},
{
@@ -95,7 +95,7 @@
"curl -fsS https://git.unom.io/api/packages/unom/arch/repository.key | sudo pacman-key --add -",
"sudo pacman-key --lsign-key E0CA04465C99C936E0B0C6510A317015A34DDD69",
"grep -q '^\\[punktfunk\\]' /etc/pacman.conf || printf '\\n[punktfunk]\\nServer = https://git.unom.io/api/packages/unom/arch/$repo/$arch\\n' | sudo tee -a /etc/pacman.conf >/dev/null",
- "sudo pacman -Syu punktfunk-host"
+ "sudo pacman -Syu punktfunk-host punktfunk-web punktfunk-scripting"
]
},
{
diff --git a/docs-site/content/docs/arch.mdx b/docs-site/content/docs/arch.mdx
index c779eae8..449d8126 100644
--- a/docs-site/content/docs/arch.mdx
+++ b/docs-site/content/docs/arch.mdx
@@ -22,9 +22,9 @@ the partial upgrade that breaks Arch boxes:
-The browser console is **optional** on Arch, so name it yourself — same line, full upgrade:
-`sudo pacman -Syu punktfunk-web`. (Also in the repo: `punktfunk-gamescope` for HDR off gamescope,
-`punktfunk-scripting` for [plugins](/docs/plugins), `punktfunk-client` if this box is also a client.)
+The browser console and the plugin runner are *optional* packages on Arch — pacman never installs
+an optional dependency, so the line names them. (Also in the repo: `punktfunk-gamescope` for HDR off
+gamescope, `punktfunk-client` if this box is also a client.)
From then on a normal `sudo pacman -Syu` moves every Punktfunk package; restart the host afterwards
(`systemctl --user restart punktfunk-host`) — or let the [console do it](/docs/updating).
diff --git a/docs-site/content/docs/debian.mdx b/docs-site/content/docs/debian.mdx
index 91f47076..8cc2b7e0 100644
--- a/docs-site/content/docs/debian.mdx
+++ b/docs-site/content/docs/debian.mdx
@@ -28,7 +28,10 @@ package needs 2.39) — [build from source](/docs/build-from-source) there, or u
## 2. Install the host
The repo is public and signed — the `debian` in the URL is the package format, it's the same repo
-Ubuntu uses. The browser console, `punktfunk-web`, comes along automatically:
+Ubuntu uses. The line names the browser console (`punktfunk-web`) and the plugin runner
+(`punktfunk-scripting`) explicitly rather than leaning on apt to pull them in: they are only
+*recommended* by `punktfunk-host`, and a box with `APT::Install-Recommends "0"` would end up with
+a host you cannot pair with.
diff --git a/docs-site/content/docs/install.mdx b/docs-site/content/docs/install.mdx
index fea9bda9..a98cde0d 100644
--- a/docs-site/content/docs/install.mdx
+++ b/docs-site/content/docs/install.mdx
@@ -9,10 +9,10 @@ The **host** is the program on the PC you stream *from*. It installs from Punktf
repositories on Linux and from a signed installer on Windows — pick your system:
-
+
-
-
+
+
@@ -51,10 +51,13 @@ they show (CI fails if the two drift apart). Re-running is safe.
- **Already running Sunshine, Apollo or Vibeshine?** They can coexist, with one port moved — see
[Switching from Sunshine](/docs/switching-from-sunshine) before you install.
- **What gets installed.** `punktfunk-host` is the host; `punktfunk-web` is the browser console
- (pairing, status, library — apt and RPM pull it in automatically, on Arch you name it yourself,
- the Bazzite image contains it); `punktfunk-scripting` is the plugin runner that brings your
- game launchers into the [library](/docs/game-library) (started for you everywhere except Arch and
- source builds — `systemctl --user enable --now punktfunk-scripting` there).
+ (pairing, status, library); `punktfunk-scripting` is the plugin runner that brings your game
+ launchers into the [library](/docs/game-library) (started for you everywhere except Arch and
+ source builds — `systemctl --user enable --now punktfunk-scripting` there). Every install line
+ on these pages names all three. The host package only *recommends* the console, and a package
+ manager set to skip weak deps (`install_weak_deps=False`, `APT::Install-Recommends "0"`) would
+ otherwise leave you with a host and no way to pair with it. The Bazzite image contains all
+ three already.
- **Stable by default.** Every guide points at the **stable** channel, which moves on `vX.Y.Z`
releases. The latest `main` build is the **canary** channel — [Release Channels](/docs/channels).
- **Updating and removing** are one page each: [Updating the Host](/docs/updating) (the console
diff --git a/docs-site/content/docs/ubuntu.mdx b/docs-site/content/docs/ubuntu.mdx
index 92277e58..bd6b5a0f 100644
--- a/docs-site/content/docs/ubuntu.mdx
+++ b/docs-site/content/docs/ubuntu.mdx
@@ -26,8 +26,10 @@ For **Ubuntu 26.04 or newer**, Desktop or Server, GNOME or KDE.
## 2. Install the host
-The repo is public and signed; this adds it and installs the host (the browser console,
-`punktfunk-web`, comes along automatically):
+The repo is public and signed; this adds it and installs the host together with the browser
+console (`punktfunk-web`) and the plugin runner (`punktfunk-scripting`). They are named in the
+line rather than left to apt: `punktfunk-host` only *recommends* them, so a box with
+`APT::Install-Recommends "0"` would end up with a host you cannot pair with.
diff --git a/docs-site/content/docs/web-console.md b/docs-site/content/docs/web-console.md
index 3676c460..f5819d1d 100644
--- a/docs-site/content/docs/web-console.md
+++ b/docs-site/content/docs/web-console.md
@@ -36,23 +36,26 @@ In practice:
## Enable the console
-- **Linux packages (apt / RPM / Bazzite):** the host package (`punktfunk-host` on Ubuntu,
- `punktfunk` on Fedora/Bazzite) *recommends* `punktfunk-web`, so your package manager pulls the
- console in with the host (the Bazzite sysext image already contains it). Enable it as your
- desktop user:
+- **Linux packages (apt / RPM / Arch / Bazzite):** `punktfunk-web` is its own package, and the
+ install line on every distro page names it (the Bazzite sysext image already contains it).
+ Enable it as your desktop user:
```sh
systemctl --user enable --now punktfunk-web
# then browse to https://:47992
```
-- **Arch / CachyOS (pacman):** the console is an *optional* package and pacman never installs
- optional dependencies — install it from the same repo the host came from (see
- [Arch Linux](/docs/arch)), then enable it as above. Use a full `-Syu`, never a bare `pacman -S`,
- to avoid a partial upgrade:
+ **No console on a box that has the host?** That is the one way this goes wrong: the host package
+ only *recommends* the console on apt and RPM, and lists it as an *optional* dependency on Arch
+ (pacman never installs those). So a host put on by hand, or by a package manager configured to
+ skip weak dependencies (`install_weak_deps=False` in `/etc/dnf/dnf.conf`,
+ `APT::Install-Recommends "0"`), has no console. Install it from the same repo the host came
+ from — on Arch as a full `-Syu`, never a bare `pacman -S`, to avoid a partial upgrade:
```sh
- sudo pacman -Syu punktfunk-web
+ sudo dnf install punktfunk-web # Fedora
+ sudo apt install punktfunk-web # Debian / Ubuntu
+ sudo pacman -Syu punktfunk-web # Arch / CachyOS
systemctl --user enable --now punktfunk-web
```
diff --git a/docs-site/src/data/platforms.json b/docs-site/src/data/platforms.json
index 59a2296e..31f385cb 100644
--- a/docs-site/src/data/platforms.json
+++ b/docs-site/src/data/platforms.json
@@ -81,7 +81,7 @@
"curl -fsSL https://git.unom.io/api/packages/unom/debian/repository.key | sudo tee /etc/apt/keyrings/punktfunk.asc >/dev/null",
"echo \"deb [signed-by=/etc/apt/keyrings/punktfunk.asc] https://git.unom.io/api/packages/unom/debian stable main\" | sudo tee /etc/apt/sources.list.d/punktfunk.list",
"sudo apt update",
- "sudo apt install punktfunk-host"
+ "sudo apt install punktfunk-host punktfunk-web punktfunk-scripting"
]
},
{
@@ -95,7 +95,7 @@
"curl -fsS https://git.unom.io/api/packages/unom/arch/repository.key | sudo pacman-key --add -",
"sudo pacman-key --lsign-key E0CA04465C99C936E0B0C6510A317015A34DDD69",
"grep -q '^\\[punktfunk\\]' /etc/pacman.conf || printf '\\n[punktfunk]\\nServer = https://git.unom.io/api/packages/unom/arch/$repo/$arch\\n' | sudo tee -a /etc/pacman.conf >/dev/null",
- "sudo pacman -Syu punktfunk-host"
+ "sudo pacman -Syu punktfunk-host punktfunk-web punktfunk-scripting"
]
},
{
diff --git a/scripts/ci/check-docs-drift.sh b/scripts/ci/check-docs-drift.sh
index 4f4620c3..f5cbea5b 100755
--- a/scripts/ci/check-docs-drift.sh
+++ b/scripts/ci/check-docs-drift.sh
@@ -140,13 +140,13 @@ installer_case() { # name os-release-body expected-substring [extra args...]
fail=1 ;;
esac
}
-installer_case debian 'ID=debian\nVERSION_ID=13\n' 'sudo apt install -y punktfunk-host'
-installer_case ubuntu 'ID=ubuntu\nID_LIKE=debian\nVERSION_ID=26.04\n' 'sudo apt install -y punktfunk-host'
+installer_case debian 'ID=debian\nVERSION_ID=13\n' 'sudo apt install -y punktfunk-host punktfunk-web punktfunk-scripting'
+installer_case ubuntu 'ID=ubuntu\nID_LIKE=debian\nVERSION_ID=26.04\n' 'sudo apt install -y punktfunk-host punktfunk-web punktfunk-scripting'
installer_case mint22 'ID=linuxmint\nID_LIKE="ubuntu debian"\nVERSION_ID=22.1\n' 'cannot host'
-installer_case fedora 'ID=fedora\nVERSION_ID=44\n' 'sudo dnf install -y punktfunk'
+installer_case fedora 'ID=fedora\nVERSION_ID=44\n' 'sudo dnf install -y punktfunk punktfunk-web punktfunk-scripting'
installer_case fedora43 'ID=fedora\nVERSION_ID=43\n' '/rpm/bazzite'
-installer_case arch 'ID=arch\n' 'sudo pacman -Syu --noconfirm punktfunk-host'
-installer_case cachyos 'ID=cachyos\nID_LIKE="arch"\n' 'sudo pacman -Syu --noconfirm punktfunk-host'
+installer_case arch 'ID=arch\n' 'sudo pacman -Syu --noconfirm punktfunk-host punktfunk-web punktfunk-scripting'
+installer_case cachyos 'ID=cachyos\nID_LIKE="arch"\n' 'sudo pacman -Syu --noconfirm punktfunk-host punktfunk-web punktfunk-scripting'
installer_case bazzite 'ID=bazzite\nID_LIKE="fedora"\nVERSION_ID=43\n' 'punktfunk-sysext.sh install'
installer_case nixos 'ID=nixos\n' 'docs/nixos'
installer_case steamos 'ID=steamos\nID_LIKE=arch\n' 'docs/steamos-host'
diff --git a/scripts/install.sh b/scripts/install.sh
index 80de7d81..9019d826 100644
--- a/scripts/install.sh
+++ b/scripts/install.sh
@@ -236,10 +236,23 @@ fi
# ---------------------------------------------------------------------------- 1. install
# The snippets below are data/platforms.json's install lines, verbatim (stable channel); canary
# and the Fedora group are edited in. check-docs-drift.sh gate 6 keeps them identical.
-if command -v punktfunk-host >/dev/null 2>&1; then
- say "punktfunk-host is already installed ($(punktfunk-host --version 2>/dev/null | head -1)) — skipping the install, continuing with setup"
+#
+# The host, the console and the plugin runner are three separate packages on every family, so "is
+# the host there?" is the wrong question to skip the install on. A box that has the host but no
+# console — installed by hand, from an older docs line, or by a package manager told to drop weak
+# deps (dnf `install_weak_deps=False`, APT::Install-Recommends "0") — would never get one however
+# often this ran, and the console is where you pair, approve a device and change every setting.
+# Ask per binary instead: each family's line below names all three, and installing one that is
+# already there is a no-op.
+have() { command -v "$1" >/dev/null 2>&1; }
+MISSING=
+have punktfunk-host || MISSING="$MISSING host"
+have punktfunk-web-server || MISSING="$MISSING web-console"
+have punktfunk-scripting || MISSING="$MISSING plugin-runner"
+if [ -z "$MISSING" ]; then
+ say "host, web console and plugin runner are already installed ($(punktfunk-host --version 2>/dev/null | head -1)) — skipping the install, continuing with setup"
else
- say "Installing the host ($CHANNEL channel)"
+ say "Installing:$MISSING ($CHANNEL channel)"
case "$FAMILY" in
apt)
repo_line='echo "deb [signed-by=/etc/apt/keyrings/punktfunk.asc] https://git.unom.io/api/packages/unom/debian stable main" | sudo tee /etc/apt/sources.list.d/punktfunk.list'
@@ -248,7 +261,7 @@ else
run 'curl -fsSL https://git.unom.io/api/packages/unom/debian/repository.key | sudo tee /etc/apt/keyrings/punktfunk.asc >/dev/null'
run "$repo_line"
run 'sudo apt update'
- run 'sudo apt install punktfunk-host'
+ run 'sudo apt install punktfunk-host punktfunk-web punktfunk-scripting'
;;
pacman)
repo_line=$(cat <<'LINE'
@@ -260,10 +273,7 @@ LINE
run 'curl -fsS https://git.unom.io/api/packages/unom/arch/repository.key | sudo pacman-key --add -'
run 'sudo pacman-key --lsign-key E0CA04465C99C936E0B0C6510A317015A34DDD69'
run "$repo_line"
- run 'sudo pacman -Syu punktfunk-host'
- if ask "Install the web console and the plugin runner too (punktfunk-web, punktfunk-scripting — optional on Arch, recommended)?" y; then
- run 'sudo pacman -Syu punktfunk-web punktfunk-scripting'
- fi
+ run 'sudo pacman -Syu punktfunk-host punktfunk-web punktfunk-scripting'
;;
dnf)
group=$RPM_GROUP
@@ -294,8 +304,12 @@ CMD
esac
hash -r 2>/dev/null || true
if [ "$DRY" != 1 ]; then
- command -v punktfunk-host >/dev/null 2>&1 || die "the install finished but punktfunk-host isn't on PATH — open a new terminal and re-run, or see $DOCS_PAGE"
+ have punktfunk-host || die "the install finished but punktfunk-host isn't on PATH — open a new terminal and re-run, or see $DOCS_PAGE"
ok "punktfunk-host $(punktfunk-host --version 2>/dev/null | head -1) installed"
+ # Not fatal — the host still streams — but say it out loud here rather than let step 7
+ # hand out a console URL for something that is not on the box.
+ if have punktfunk-web-server; then ok "the web console (punktfunk-web) is installed"
+ else warn "the web console (punktfunk-web) did NOT get installed — pairing, approving a device and every setting live there. Install it by hand: $DOCS_PAGE"; fi
fi
fi
@@ -384,7 +398,11 @@ if [ "$START" = 1 ]; then
else
systemctl --user daemon-reload 2>/dev/null
units="punktfunk-host"
- systemctl --user list-unit-files punktfunk-web.service 2>/dev/null | grep -q '^punktfunk-web.service' && units="$units punktfunk-web"
+ if systemctl --user list-unit-files punktfunk-web.service 2>/dev/null | grep -q '^punktfunk-web.service'; then
+ units="$units punktfunk-web"
+ else
+ warn "no punktfunk-web.service on this box — the console is not installed, so nothing will answer on 47992 ($DOCS_PAGE)"
+ fi
# The plugin runner fills the game library; apt/dnf/sysext start it themselves, Arch doesn't.
if systemctl --user list-unit-files punktfunk-scripting.service 2>/dev/null | grep -q disabled; then units="$units punktfunk-scripting"; fi
run "systemctl --user enable --now $units"
@@ -421,11 +439,20 @@ if grep -qs 0x10de /sys/bus/pci/devices/*/vendor 2>/dev/null; then
fi
ip=$(hostname -I 2>/dev/null | awk '{print $1}')
[ -n "$ip" ] || ip=$(ip -4 route get 1.1.1.1 2>/dev/null | awk '{for(i=1;i<=NF;i++) if($i=="src") print $(i+1); exit}')
+# Step 1 is the console, so it must not be printed as fact when the console isn't installed —
+# that is what sent a Fedora user looking for a page nothing was serving. (--dry-run installs
+# nothing by definition, so it shows the normal text.)
+if have punktfunk-web-server || [ "$DRY" = 1 ]; then
+ step1="1. Open the web console: https://${ip:-}:47992 (the certificate is the host's own — continue past the warning)
+ password: sed -n 's/^PUNKTFUNK_UI_PASSWORD=//p' ~/.config/punktfunk/web-password"
+else
+ step1="1. Install the web console — it is NOT on this box, and pairing, approving a device and
+ every setting live there. The install line for your distro is on $DOCS_PAGE"
+fi
cat <}:47992 (the certificate is the host's own — continue past the warning)
- password: sed -n 's/^PUNKTFUNK_UI_PASSWORD=//p' ~/.config/punktfunk/web-password
+ $step1
2. Install a client on the device you stream to ($DOCS/install-client), connect, and click
Approve in the console — or Pair a device for a PIN ($DOCS/pairing).
3. Stream. Ctrl+Alt+Shift+Q hands mouse and keyboard back on desktop clients.