The compose file's environment: block only forwarded the variables it
explicitly referenced — CORE_ADDRESS, CORE_API_AUTH_*, CORE_WEBRTC_*,
CORE_LOG_LEVEL. Everything else got the upstream Core defaults
regardless of what was in .env. So 'CORE_RTMP_ADDRESS=:1937' in .env
was silently ignored and Core kept binding 1935.
Hit on the live TrueNAS host where another datarhei/restreamer
container was already on 1935 with active stream state — couldn't
just stop it. Adding explicit env passthrough for the four common
collision points (RTMP, RTMPS, SRT, TLS) so an operator can remap
each individually without editing this file:
CORE_RTMP_ADDRESS=:1937
CORE_RTMP_ADDRESS_TLS=:1938
CORE_SRT_ADDRESS=:6002
CORE_TLS_ADDRESS=:8183
Defaults are unchanged — empty .env keeps :1935/:1936/:6000/:8181.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Layers Wild Dragon branding on top of upstream restreamer-ui v1.14.0
without forking the whole repo — keeps upstream UI updates flowing in
when we bump RESTREAMER_UI_REF.
Overlay (deploy/truenas/core/ui-overlay/):
public/index.html Wild Dragon title, theme color #0d0e12
public/manifest.json PWA name/short_name/colors
public/favicon.ico multi-res ICO (16/32/64) generated from
a 'WD' monogram in orange #ff6633 on dark
public/logo192.png Apple touch icon
public/logo512.png PWA install icon
src/misc/Logo/images/ rs-logo.svg (square mark, used in the
Header) and logo.svg (wordmark, used in
the Footer) — both Wild-Dragon-themed
src/misc/Logo/{index,rsLogo}.js
link the logos to forge.wilddragon.net
instead of datarhei.com
apply-overlay.sh runs in the Docker ui-builder stage just after the
upstream git clone and just before yarn install. Two phases:
1. rsync the overlay's public/ and src/ on top of the cloned
upstream tree
2. Targeted in-place patches for one-line UI strings (header
title, two welcome captions). Each patch is anchored to a
unique surrounding context and the script fails loudly if the
anchor isn't present — so a future upstream rename surfaces
immediately rather than silently shipping un-rebranded UI.
Image size: ~+50KB (the overlay assets), no measurable build-time
delta. PWA installs and OS bookmarks now show Wild Dragon. The
remaining 'Restreamer'/'datarhei' references in views/Welcome.js,
views/Login.js, views/Settings.js, etc. are deeper-page strings
that aren't worth a one-off overlay; they'll go away when we fork
the UI repo properly for the WebRTC tab milestone.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
The Restreamer UI bundle includes subdirectories (_player,
_playersite, static, locales) and the Dockerfile copies the whole
tree into /core/static. seed-data.sh on first boot was using flat
'cp -p' which errors on directories with 'omitting directory ...';
set -e then exits, the container restarts forever in a crash loop,
and Core never starts.
Fix: 'cp -Rp' so directories are copied as trees. The no-clobber
check on the top-level name still keeps operator-edited content
safe — if /core/data/_player exists we don't replace it, even if
its internals diverge from the bundled version.
Also defends against dotfiles via the second glob.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Replaces the placeholder Dragon Fork landing page at / with the real
React SPA — the same UI that ships in upstream's datarhei/restreamer
image. Operators get the full process management dashboard, log
viewer, restream config, and so on.
Implementation: a new Docker stage 'ui-builder' (node:21-alpine3.20)
clones datarhei/restreamer-ui at a pinned tag (v1.14.0), runs
'yarn install + yarn build' with PUBLIC_URL="./" so all asset
references are relative, and the runtime stage pulls /ui/build into
/core/static. The existing seed-data.sh script then copies it into
/core/data on first boot.
Stacking order in /core/static:
1. UI bundle from ui-builder — provides index.html, the SPA bundle
and assets, _player, _playersite, etc.
2. Dragon Fork deploy/static/* — currently only whep-player.html;
the placeholder index.html was removed so the UI's wins.
Pinned to v1.14.0 (the most recent tagged restreamer-ui release)
rather than 'main' for reproducible builds. Bumping the pin is a
one-line ARG override.
Image size: ~+25MB compressed (Restreamer UI bundle is ~3MB
gzipped, plus the build-stage layer overhead until pruned).
UI-side configuration: the SPA defaults to talking to the
same-origin /api endpoints, which is exactly what we want when
serving from Core. No '?address=' query string needed on the URL.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
A clean post-merge deploy showed an unintended UX wart: hitting
http://<host>:<port>/ in a browser returned 404 'File not found'
because Core's static-disk handler serves /core/data and we never
put anything there. Functionally fine — the API and Swagger are
reachable on /api and /api/swagger — but a confusing first
impression for a brand-new operator.
Fix is deploy-side, not code-side: ship a small landing page +
the existing test/whep-player.html as default content for the data
volume.
Pieces:
deploy/truenas/core/static/
index.html — Dragon Fork-branded landing page; links
to Swagger and the WHEP player; live
/api status panel.
whep-player.html — same self-contained Pion subscriber that
lives at test/whep-player.html.
deploy/truenas/core/seed-data.sh
First-boot script. Copies /core/static/* into /core/data/
only when the destination filename doesn't already exist —
operator-supplied content is never clobbered, so this is a
safe addition that respects upstream's contract that
/core/data is operator-owned.
deploy/truenas/core/Dockerfile
COPYs the static dir and seed script into the runtime image,
wraps the entrypoint as 'seed-data.sh && exec run.sh' (run.sh
itself is unchanged from upstream).
Image size impact: ~15KB.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Adds a dedicated deploy bundle under deploy/truenas/core/ so the
real root Core binary — with the M2 WebRTC subsystem wired in —
can replace the M1 webrtc-poc stack on the TrueNAS host.
- Dockerfile: two-stage build on golang:1.24-alpine3.20 + alpine:3.20
runtime. FFmpeg is bundled so restream processes have their
subprocess path ready. Copies the core binary from core/core
(Go places the output file inside the core/ package directory
because it can't overwrite a directory with a file) plus import
and ffmigrate from the repo root.
- docker-compose.yml: host-networked Core service, env-driven
config (CORE_ADDRESS, CORE_API_AUTH_*, CORE_WEBRTC_ENABLE,
CORE_WEBRTC_PUBLIC_IP), with config/ and data/ bind mounts.
- README.md: M1→M2 cutover notes, one-time setup, JWT smoke test
against /api/v3/whep/:id, and teardown.
Verified: make release + make import + make ffmigrate all
cross-compile cleanly for linux/amd64; go build ./... and
go test ./... pass on the branch.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- core/webrtc: NewSourceOn(streamID, host, port) allows binding the
RTP UDP socket on something other than 127.0.0.1, required when the
PoC runs in a container and must accept RTP from LAN publishers.
NewSource(streamID, port) stays as a convenience wrapper on
127.0.0.1 for existing tests and tight local tests.
- cmd/webrtc-poc: new -rtp-host flag (default 127.0.0.1 for safety).
- deploy/docker/Dockerfile: two-stage build, scratch runtime, ~14 MB.
- deploy/truenas/docker-compose.yml: host-networked stack template
driven by a .env file. Host networking is required for WebRTC ICE
to work without NAT rewriting per-candidate.
- deploy/truenas/README.md: operator runbook with port picking,
bring-up, verification curls, and security notes.