T-HUB/infra/peertube-workers/WINDOWS.md
glass beadian aa5e262f3a Tactical Media Broadcast Hub — initial release
Self-hosted multi-platform broadcast newsroom for activist collectives:
publishing pipeline with group approval and DST-proof scheduling, TweetDeck-style
column wall with hostile-content-safe rendering, live control room with Auto
Director, bridged chat governance with polls and quorum, distributed sandboxed
transcode workers, encrypted content-addressed archive, monthly analytics.

MIT licensed. See README.md and docs/.
2026-10-10 11:56:42 +00:00

190 lines
12 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Windows native NVENC worker
Use Windows 10/11 x64 with an NVIDIA GPU and a working driver. WSL is the SSH
transport only: Node, FFmpeg, the shim, admission, and IPC all run as Windows
processes. The initial worker name is `worker-laptop-win`; root is `C:\pt-worker`.
The canonical instance is `https://tube.occupymedia.cc`; worker traffic uses
`http://TAILSCALE_IP:9000` inside encrypted Tailscale. Viewers use PeerTube.
No server configuration change is needed: remote VOD is already enabled.
## Prepare and enroll
Run the installer from this directory. Python 3.12+ and Windows Tailscale are
build/access prerequisites. Python is embedded in the frozen executables, so
services do not depend on the developer's Python installation. Pins are in
[win/dependencies.json](win/dependencies.json); the FFmpeg URL is a dated archive,
verified by SHA256. The two executables are built from reviewed Python source
using the versions in `win/build-requirements.txt`. Runner and IPC dependencies
use the existing runtime lockfile. Do not substitute a `.cmd` shim: Node's
shell-free spawn rejects it with EINVAL.
```powershell
# Elevated PowerShell: installs Node MSI silently plus isolated Node 22.
.\install-peertube-worker-windows.ps1 -Phase Prepare -Name WORKERNAME-win
# A filtered SSH/WSL token can prepare everything except the MSI:
.\install-peertube-worker-windows.ps1 -Phase Prepare -UserLevel -Name WORKERNAME-win
.\install-peertube-worker-windows.ps1 -Phase SelfTest
```
Both H.264 and HEVC must produce a real 5-second 1080p encode **and positive
NVIDIA encoder utilization**. GPU identity, UUID, driver, boot, device index,
exit codes, samples, and session statistics are recorded in `state\nvenc.json`.
No proof means no enrollment. The installer keeps admission PAUSED. A failed
init, absent telemetry signal, reboot, or driver mismatch closes admission.
Session-0 proof runs again when services are installed; enrollment-session
success alone does not prove service-context access.
Supply the **existing** registration token through stdin. Never pass it as a
PowerShell/Node argument, environment variable, transcript, or source file.
For SSH transport, pipe PostgreSQL's selected token output directly into the
Windows Node `bin\ipc-nvenc.cjs register` process. The version-controlled
`win/register-from-ssh.py --worker USER@HOST --name NAME` implements this using two subprocesses and pipe handles; it fetches
`runnerRegistrationToken.registrationToken`, database `peertube`, using the
PostgreSQL container's existing `POSTGRES_USER`. No token is printed or retained.
Before doing so, run `bin\enroll-server.cjs`: it requires concurrency 0 and drops
all upstream logs. After registration use `ipc-nvenc.cjs graceful-shutdown`, wait
for the listener to exit, and set TOML concurrency to 2. Alternatively use:
```powershell
# The calling process must give this process the secret on inherited stdin.
.\install-peertube-worker-windows.ps1 -Phase Enroll -RegistrationTokenStdin
```
The **registration secret** is never saved. The official runner necessarily
saves its separate issued **runner credential** in
`profile\Roaming\peertube-runner-nodejs\Config\default\config.toml`.
NTFS ACLs restrict this tree to the owner, SYSTEM, administrators, and LocalService.
Never print that TOML, arbitrary runner logs, database token columns, or HTTP
headers. Enrollment pending markers prohibit blind duplicate registrations.
## Services and operations
```powershell
# ServiceFiles prepares concrete WinSW XML/exe files without touching SCM.
.\install-peertube-worker-windows.ps1 -Phase ServiceFiles
# Elevated PowerShell; services initially PAUSED, session-0 proof first.
.\install-peertube-worker-windows.ps1 -Phase Services
C:\pt-worker\pt-worker-win.ps1 status
C:\pt-worker\pt-worker-win.ps1 network-test
C:\pt-worker\pt-worker-win.ps1 start
C:\pt-worker\pt-worker-win.ps1 drain
C:\pt-worker\pt-worker-win.ps1 restart
C:\pt-worker\pt-worker-win.ps1 self-test
```
WinSW 2.12.0 wraps `pt-runner` (Node supervisor) and `pt-admission` (frozen Python).
Both use the [WinSW 2.12 service-account and stop configuration](https://github.com/winsw/winsw/blob/v2.12.0/doc/xmlConfigFile.md), running as LocalService with automatic delayed startup, a 30-second service
restart delay, and limited rotated logs. The supervisor uses a further 15-second
runner restart delay. It retains only safe milestones and observer events;
unfiltered upstream logs are discarded because they can contain tokens.
A service stop asks the supervisor to drain via the official named-pipe IPC,
with an explicit one-hour SCM stop ceiling. For jobs that can exceed this ceiling,
use `pt-worker-win drain`, wait for `runner_running=false`, then stop services.
No admission loss forcibly kills an active encode.
State decisions use the Linux Meter/Admission semantics: AVAILABLE, BUSY,
DRAINING, NETWORK_DEGRADED, GPU_UNAVAILABLE, LOW_DISK, THERMAL_THROTTLED, OFFLINE,
PAUSED. Status preserves Linux field names (`status`, `disk_free_bytes`,
`registration_state`, `last_job_duration_seconds`, `last_job_realtime_factor`,
`util`, etc.) and adds `state`, NVENC capability flags, and fleet aliases. QSV
flags remain false; a successful NVENC test is never reported as QSV success.
The supervisor requires a fresh admission document (<30 seconds), an explicit
unpaused control document, and no GPU-refusal marker. Missing/stale admission
always triggers the official runner graceful-shutdown request.
AC policy uses `GetSystemPowerStatus`: battery or unknown AC drains. Thermal
zones are read through `root/wmi:MSAcpi_ThermalZoneTemperature` when supported;
unavailable CPU sensors remain null. NVIDIA temperature remains a real reading.
Defaults: 20 GiB disk reserve, 85 C thermal ceiling, 120 s thermal cooldown,
10 Mbps each direction, 1.25x bandwidth recovery margin, three good/two bad
samples, 900 s bandwidth expiry, no DERP admission. The existing Tailscale-only
server probe (`TAILSCALE_IP:9044`) uses bounded 8 MiB GET download and PUT upload
checks, EWMA, and runs while the runner is drained. GPU failure events remain
latched until a later real self-test. Boot/driver changes trigger new proof.
`powercfg /change standby-timeout-ac 0` is an elevated install step. The laptop
must remain on AC; lid-close/Modern Standby behavior still needs owner review.
## Adapter contract and tests
The pinned runner requests `libx264`. The executable accepts only reviewed
command shapes and rewrites them before executing FFmpeg: CUDA/NVDEC hardware
frames -> `scale_cuda` -> `h264_nvenc`, preset p4, preserving bitrate cap/GOP.
The original libx264 command is never executed. H.264, SDR HEVC, and VP9 sources
have reviewed hardware-decode routes; rotated, HDR, unsupported pixel formats,
unknown options, stream codec overrides, extra outputs, and unknown codecs fail
closed with exit 78. Audio-only and explicit stream-copy/remux jobs are permitted
without video encoding. Static audio-merge images use software image processing
and `hwupload_cuda`; video encoding remains NVENC. AV1 input is refused until a
reviewed decode route is tested; AV1 capability is not inferred from FFmpeg's
encoder list. A local diagnostic can set `PT_NVENC_TARGET=hevc_nvenc`; any other target is refused. Never change the PeerTube service target without a reviewed codec contract. HEVC encoding is proven by the gate but the PeerTube default output
remains H.264, matching the pinned runner/server contract.
```bash
python3 -m unittest discover -s infra/peertube-workers/win/tests -p test_nvenc.py -v
```
A running encode that fails, or lasts >=3 seconds without a readable positive
encoder signal, returns failure and latches GPU_UNAVAILABLE. Very short encodes
may finish within NVIDIA's utilization averaging window; their explicit NVENC
encoder and current boot/driver proof remain required. For a real E2E test record
positive encode telemetry, job UUID, server Pending/Processing/Completed states,
input/output codec and resolution, wall time, RTF, and playable result. Local
synthetic success is not a PeerTube E2E result.
Failure checks: drain -> runner gracefully exits; start/restart -> reconnect
milestone; create `state\gpu-unavailable` -> admission GPU_UNAVAILABLE and shim
exit 78; remove marker, drain, rerun self-test, then start. Do not unload the
owner's desktop GPU driver to simulate failure. Test reboot recovery and AC loss
only after services and the owner's physical AC/lid policy can be exercised.
## Deployment-specific elevation blocker / worker 2
The verified route is SSH into WSL using `~/.ssh/devserver`, then native
PowerShell/Node through `/mnt/c`. Interop works. The Windows token is medium
integrity with administrators marked deny-only. `sc create` fails with
OpenSCManager error 5; registering a Highest scheduled task returns access denied.
Enabling alternate-port Windows sshd needs the same unavailable elevation and
would not remove this blocker. No existing recovery task, UAC policy, driver, or
server setting was changed to bypass it. The owner must run the prepared Services
phase in an elevated Windows PowerShell. An interactive native process deployment
can be validated over the working route but is not a boot-persistent service.
Worker 2 changes only name, root (if wanted), GPU device index, and local network
access. Reuse this server probe and existing authorized token; give each worker a
unique runner name and isolated profile. Do not copy worker 1's credential TOML.
Require a fresh real hardware gate on that GPU and service context. Start with
concurrency 2; benchmark equivalent real workloads at 1–4 before increasing it.
The RTX 3090's stock session ceiling is not a two-job constraint; no driver patch
is deployed. Its measured limit is 350 W; an optional 200–250 W cap needs driver
support and throughput/thermal measurement before adopting it. No power limit or
driver was changed during deployment. Hardware throughput/session/codec claims
from research remain estimates until measured on the specific worker.
## Authorized E2E fixture
`win/e2e-peertube.mjs` is an explicit, privileged server test, never an installer
autostart step. Run it only for an authorized private upload, with other workers
drained if a specific worker must own the job. Supply a synthetic H.264 file as
`/tmp/pt-worker-e2e-source.mp4` inside the PeerTube container, then run the script
there through Node stdin with `NODE_DB_LOG=false` and `LOGGER_LEVEL=error`. It
requires the inspected PeerTube 7.3.0 model layout. It registers the installed
models without the initializer's SQL function/extension mutations, creates one
10-minute admin OAuth session through the installed token model, performs one
private upload through the HTTP API, records safe state metadata, checks private
HLS/media HTTP responses and full decoding, then revokes/removes that session.
It does not change the root password or runner registration token. Credentials
remain in process memory and the temporary normal OAuth database row; they never
appear in command arguments, report JSON, or source. Upstream ORM logging is
disabled before the token is created. The private test video remains available
for owner review; delete disposable server/container scratch files afterward.
First upload with the target worker drained to capture Pending, then start the
worker while the helper polls. Report JSON goes to `/tmp/pt-worker-e2e-result.json`
inside the container; it contains no credentials. This host's successful private
fixture is [Windows NVENC worker E2E](https://tube.occupymedia.cc/w/7d3EHVeikq3JZ29XqjKJyd),
video UUID `324566b4-3506-417d-9cca-cc2a3b7a14cc`. Jobs 1/2 completed on runner 1.
The cold WebVideo encode took 36.359 s with positive 100% NVIDIA encoder samples;
its warm HLS encode took 2.594 s. These are observed 5-second-fixture timings,
not a concurrency benchmark. The short HLS run sampled 0% in NVIDIA's averaging
window; its command was still explicitly NVENC, and the WebVideo job supplies
mandatory job-correlated GPU proof. Root OAuth sessions were verified back at 0.