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>
|
||
|---|---|---|
| .. | ||
| static | ||
| docker-compose.yml | ||
| Dockerfile | ||
| README.md | ||
| seed-data.sh | ||
TrueNAS deploy — datarhei Core (M2, WebRTC-in-Core)
Host-networked Docker stack that runs the real root Core binary with
the M2 WebRTC egress subsystem wired in. This replaces the M1
webrtc-poc stack — WebRTC is now a first-class output alongside
RTMP/SRT/HLS.
What changed from M1
| M1 (webrtc-poc) | M2 (this stack) |
|---|---|
Standalone cmd/webrtc-poc binary |
Full Core with restream, HTTP API, storage |
| One hard-coded stream id | Every restream process can opt into WebRTC |
| Single UDP ingest, PT-split forwarding | Two UDP ports per process, per-track |
Plain /whep/:id on a side port |
/api/v3/whep/:id on the JWT-protected API |
| No auth | JWT (same creds as the rest of Core) |
Prereqs
- Docker on the TrueNAS host (TrueNAS SCALE includes it)
- LAN or public IP that clients can reach (set in
.envasPUBLIC_IP) - Admin credentials for Core's API
- FFmpeg is bundled in the image — no host install required
One-time setup
sudo mkdir -p /mnt/NVME/Docker/dragonfork-core
cd /mnt/NVME/Docker/dragonfork-core
# Pull the repo (or sync deploy files) onto the host. The compose
# build `context:` points at the repo root.
git clone https://forgejo.wilddragon.net/zgaetano/datarhei-dragonfork-core.git
cd datarhei-dragonfork-core/deploy/truenas/core
cat > .env <<EOF
PUBLIC_IP=10.0.0.25
CORE_HTTP_PORT=8080
API_AUTH_USERNAME=admin
API_AUTH_PASSWORD=$(openssl rand -base64 24)
API_AUTH_JWT_SECRET=$(openssl rand -base64 48)
LOG_LEVEL=info
EOF
mkdir -p config data
Run
docker compose up -d --build
docker compose logs -f
You should see Core come up logging all configured listeners, including a line from the WebRTC component confirming the subsystem is enabled.
Smoke-test via API
# Issue a JWT against the admin creds from .env:
TOKEN=$(curl -s -X POST -H 'Content-Type: application/json' \
-d '{"username":"admin","password":"<from .env>"}' \
http://10.0.0.25:8080/api/login | jq -r '.access_token')
# Probe the WHEP endpoint — should 404 for an unknown id.
curl -i -H "Authorization: Bearer $TOKEN" \
-X POST http://10.0.0.25:8080/api/v3/whep/nope
# → HTTP/1.1 404 Not Found
# Create a process with WebRTC enabled, send RTMP to its input, then
# subscribe the Pion whep-client to /api/v3/whep/<process-id>.
Cutting over from the M1 PoC
The M1 webrtc-poc stack is independent; it binds its own ports. You
can run both side-by-side during the cutover:
# Stop the M1 stack when you're ready to retire it:
cd /mnt/NVME/Docker/dragonfork-webrtc-poc
docker compose down
Teardown
docker compose down
Security notes
- The WHEP endpoint is mounted under
/api/v3, which is JWT-protected. That's the M2 posture — WHEP clients (browsers) need a token. M3 adds per-process signed-URL tokens so embeds don't require admin credentials. - The binary runs as root inside the container; if you need an unpriv
user, mount volumes owned by a fixed UID and add a
user:directive. This matches how the upstream datarhei/core image ships. - Put Caddy or nginx in front for TLS. The media itself is DTLS-SRTP-encrypted regardless.