datarhei-dragonfork-core/deploy/truenas/core
Zac Gaetano 75afcbc0d1
Some checks failed
ci / vet + build (push) Successful in 9m50s
ci / race tests (push) Failing after 6m30s
ci / WebRTC smoke (5-viewer fanout) (push) Successful in 9m47s
ci / WebRTC latency p95 gate (push) Successful in 10m2s
deploy(compose): pass RTMP/SRT/TLS port overrides through from .env
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>
2026-05-03 13:30:02 +00:00
..
static deploy: bundle the official Datarhei Restreamer UI 2026-05-03 12:58:51 +00:00
ui-overlay feat(ui): Wild Dragon reskin overlay on the Restreamer UI 2026-05-03 13:14:41 +00:00
docker-compose.yml deploy(compose): pass RTMP/SRT/TLS port overrides through from .env 2026-05-03 13:30:02 +00:00
Dockerfile feat(ui): Wild Dragon reskin overlay on the Restreamer UI 2026-05-03 13:14:41 +00:00
README.md deploy(truenas): Core image + compose for M2 WebRTC rollout 2026-04-17 14:59:49 -04:00
seed-data.sh fix(deploy): make seed-data.sh recursive for directory entries 2026-05-03 13:01:51 +00:00

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 .env as PUBLIC_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.