Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ Source for [OpenRTMP.org](https://openrtmp.org), the public website for the Open
OpenRTMP includes:

- [`librtmp2`](https://github.com/OpenRTMP/librtmp2) — Rust RTMP/RTMPS and Enhanced RTMP protocol library with a C-compatible FFI
- [`librtmp2-server`](https://github.com/OpenRTMP/librtmp2-server) — self-hosted RTMP/RTMPS server with SQLite, stream keys, REST API, and statistics
- [`librtmp2-server-panel`](https://github.com/OpenRTMP/librtmp2-server-panel) — web UI for stream lifecycle and live monitoring
- [`librtmp2-server`](https://github.com/OpenRTMP/librtmp2-server) — self-hosted RTMP/RTMPS server with SQLite, stream keys, REST API, statistics, and optional HA clustering
- [`librtmp2-server-panel`](https://github.com/OpenRTMP/librtmp2-server-panel) — web UI for stream lifecycle, live monitoring, and cluster-aware operations

All projects are active alpha software. The website intentionally avoids hard-coded release numbers where a package registry or GitHub release page can remain the source of truth.

Expand Down
46 changes: 42 additions & 4 deletions docs/index.php
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<?php
$page = 'docs';
$pageTitle = 'Documentation — OpenRTMP';
$pageDescription = 'Getting started with librtmp2, librtmp2-server, and librtmp2-server-panel: Cargo builds, host callbacks, Docker deployment, REST API, and the web panel.';
$pageDescription = 'Getting started with librtmp2, librtmp2-server, and librtmp2-server-panel: Cargo builds, host callbacks, Docker deployment, REST API, optional HA clustering, and the web panel.';
include __DIR__ . '/../includes/header.php';
?>

Expand All @@ -23,6 +23,7 @@
<li><a href="#callbacks">Host Callbacks</a></li>
<li><a href="#layers">Module Reference</a></li>
<li><a href="#server">librtmp2-server</a></li>
<li><a href="#cluster">HA clustering</a></li>
<li><a href="#panel">librtmp2-server-panel</a></li>
<li><a href="#docker">Docker Deployment</a></li>
<li><a href="#abi">API &amp; Versioning</a></li>
Expand Down Expand Up @@ -139,10 +140,11 @@
<tr><td>REST API</td><td>stream CRUD on <code>/api/v1/streams</code> with Bearer token auth (axum, port <code>8080</code>)</td></tr>
<tr><td>Stats endpoints</td><td><code>/stats?key=&lt;stats_key&gt;</code> (JSON) and <code>/stats-nginx?key=&lt;stats_key&gt;</code> (nginx-rtmp-compatible XML)</td></tr>
<tr><td>Frame relay</td><td>forwards publisher frames to all matching players, GOP-aware</td></tr>
<tr><td>HA clustering</td><td>optional multi-node mode (<code>CLUSTER_ENABLED</code>, off by default) with OpenRaft state replication and a media mesh &mdash; see <a href="#cluster">HA clustering</a></td></tr>
</tbody>
</table>
</div>
<p>Build and run natively:</p>
<p>Build and run natively (standalone):</p>
<pre><code>git clone https://github.com/OpenRTMP/librtmp2-server.git
cd librtmp2-server
cargo build --release
Expand All @@ -155,6 +157,37 @@
-H "Content-Type: application/json" \
-d '{"id":"mystream","name":"My Live Stream","app":"live"}'</code></pre>

<h2 id="cluster">HA clustering</h2>
<p>From server <code>0.2.0</code>, <code>librtmp2-server</code> can run as a multi-node cluster. Clustering is <strong>off by default</strong>; standalone behavior is unchanged when <code>CLUSTER_ENABLED=false</code>. Published Docker images build with the <code>cluster</code> Cargo feature; runtime still defaults to standalone.</p>
<p>Architecture in short:</p>
<div class="table-wrap">
<table>
<thead><tr><th>Plane</th><th>Default port</th><th>Role</th></tr></thead>
<tbody>
<tr><td>Control</td><td><code>1940</code></td><td>OpenRaft RPC, join/admin, heartbeats, StatsProxy</td></tr>
<tr><td>Media</td><td><code>1941</code></td><td>Inter-node frame relay, subscribe, init-cache</td></tr>
<tr><td>RTMP / HTTP</td><td><code>1935</code> / <code>8080</code></td><td>Client publish/play and admin API (unchanged)</td></tr>
</tbody>
</table>
</div>
<ul>
<li>One SQLite DB per node; durable stream/viewer/token/ownership mutations go through Raft.</li>
<li>No central media proxy and no mandatory Postgres/Redis for the cluster plane.</li>
<li>Publisher ownership uses epoch fencing; players on non-owner nodes receive media via the mesh.</li>
<li>Shared-secret peer auth; optional mTLS for control and media.</li>
</ul>
<p>Minimal bootstrap (first voter):</p>
<pre><code>CLUSTER_ENABLED=true
CLUSTER_NODE_ID=1
CLUSTER_BOOTSTRAP=true
CLUSTER_SECRET=&lt;long-random-secret&gt;
CLUSTER_ADVERTISE_ADDR=10.0.0.1:1940
CLUSTER_MEDIA_ADVERTISE_ADDR=10.0.0.1:1941</code></pre>
<p>Additional nodes join with an empty database and <code>CLUSTER_JOIN=&lt;existing-control-addr&gt;</code>, then promote learners to voters via <code>POST /api/v1/cluster/nodes/{id}/promote</code>.</p>
<p>Authenticated cluster APIs include <code>GET /api/v1/cluster</code>, <code>/nodes</code>, <code>/streams</code>, plus drain/resume/promote/remove. Full configuration, limitations, and operator notes live in the server repo's <a href="https://github.com/OpenRTMP/librtmp2-server/blob/main/docs/clustering.md" target="_blank" rel="noopener"><code>docs/clustering.md</code></a> and the site guide <a href="/guides/rtmp-server-ha-clustering/">Run an HA RTMP cluster</a>.</p>
<p>Native builds that need clustering must compile with the feature:</p>
<pre><code>cargo build --release --features cluster</code></pre>

<h2 id="panel">librtmp2-server-panel</h2>
<p><a href="https://github.com/OpenRTMP/librtmp2-server-panel" target="_blank" rel="noopener">librtmp2-server-panel</a> is a Flask web UI that talks to the server's REST API. It does not implement RTMP itself &mdash; it manages streams, copies URLs, and polls live stats.</p>
<div class="table-wrap">
Expand All @@ -164,11 +197,13 @@
<tr><td>Stream management</td><td>create and delete streams via <code>/api/v1/streams</code></td></tr>
<tr><td>One-click copy</td><td>publish URL, stream key, play URL, and stats URL</td></tr>
<tr><td>Live stats</td><td>bitrate, resolution, codec, uptime, RTT polled from <code>/stats?key=...</code></td></tr>
<tr><td>Cluster UI</td><td>when health reports <code>cluster.enabled=true</code>: quorum overview, node drain/resume/remove, stream owner/epoch placement</td></tr>
<tr><td>Login gate</td><td>optional admin login (<code>REQUIRE_LOGIN=True</code> by default)</td></tr>
<tr><td>Security</td><td>CSRF protection, rate limiting (Redis-backed in Docker), encrypted key display</td></tr>
</tbody>
</table>
</div>
<p>The panel does not participate in Raft. Point it at any healthy synchronized node; durable admin writes are forwarded inside the cluster. Standalone servers hide the Cluster navigation automatically.</p>
<p>Key environment variables (see <code>.env.example</code> in the panel repo):</p>
<div class="table-wrap">
<table>
Expand Down Expand Up @@ -198,7 +233,7 @@
ghcr.io/openrtmp/librtmp2-server:latest

docker logs librtmp2-server # copy API token from first-start output</code></pre>
<p>Available tags: <code>latest</code>, <code>beta</code>, <code>alpha</code>, and pinned versions (e.g. <code>0.1.4</code>).</p>
<p>Available tags: <code>latest</code>, <code>beta</code>, <code>alpha</code>, and pinned versions (e.g. <code>0.2.0</code>).</p>

<h3>Panel only (<code>docker run</code>)</h3>
<p>Image: <code>ghcr.io/openrtmp/librtmp2-server-panel</code>. Connect to an existing server on the same Docker network (container name <code>librtmp2-server</code>):</p>
Expand Down Expand Up @@ -263,17 +298,20 @@
<tbody>
<tr><td><code>1935</code></td><td>RTMP ingest / playback (<code>RTMP_BIND</code>)</td></tr>
<tr><td><code>1936</code></td><td>RTMPS ingest / playback (<code>RTMPS_BIND</code>) &mdash; only when <code>TLS_ENABLED=true</code>; not exposed in the default compose file (uncomment <code>1936:1936</code> there)</td></tr>
<tr><td><code>1940</code></td><td>Cluster control plane (<code>CLUSTER_BIND</code>) &mdash; only when <code>CLUSTER_ENABLED=true</code></td></tr>
<tr><td><code>1941</code></td><td>Cluster media mesh (<code>CLUSTER_MEDIA_BIND</code>) &mdash; only when clustering is enabled</td></tr>
Comment on lines +301 to +302

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Correct the default Docker port description.

The default deployment is standalone and does not map cluster ports. Present 1940 and 1941 as explicit peer-only HA networking that operators add when clustering is enabled.

  • docs/index.php#L301-L302: move these ports out of the “Ports exposed by default” list, or change the table heading and state that operators must explicitly map them for clustered nodes.
  • guides/self-hosted-rtmp-server-docker/index.php#L53-L53: replace “The stack exposes” behavior with conditional HA network guidance.
📍 Affects 2 files
  • docs/index.php#L301-L302 (this comment)
  • guides/self-hosted-rtmp-server-docker/index.php#L53-L53
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/index.php` around lines 301 - 302, Update docs/index.php lines 301-302
to identify ports 1940 and 1941 as peer-only HA networking that operators must
explicitly map when clustering is enabled, rather than ports exposed by default.
Update guides/self-hosted-rtmp-server-docker/index.php line 53 to replace the
unconditional “The stack exposes” wording with conditional guidance for
clustered deployments.

<tr><td><code>8080</code></td><td>HTTP API, stats, health check (<code>HTTP_BIND</code>)</td></tr>
<tr><td><code>8000</code></td><td>Web panel</td></tr>
</tbody>
</table>
</div>
<p>To enable RTMPS alongside plaintext RTMP, set <code>LRTMP2_TLS_ENABLED=true</code> (or <code>TLS_ENABLED=true</code> in <code>.env</code>), mount cert/key files, expose port <code>1936</code>, and set <code>RTMPS_BIND=0.0.0.0:1936</code> as in <code>librtmp2-server/docker-compose.yml</code>. The panel shows <code>rtmps://</code> URLs only when <code>GET /api/v1/health</code> reports <code>rtmps_enabled: true</code> (and uses <code>LRTMP2_RTMPS_PORT</code>, default <code>1936</code>).</p>
<p>For a multi-node cluster, expose <code>1940</code> and <code>1941</code> between peers, set the <code>CLUSTER_*</code> variables described under <a href="#cluster">HA clustering</a>, and keep each node on its own SQLite volume. See the <a href="/guides/rtmp-server-ha-clustering/">clustering guide</a> for bootstrap and join steps.</p>

<h2 id="abi">API &amp; Versioning</h2>
<p>Only the public <code>librtmp2</code> crate interface is the intended stable API surface. Everything under <code>src/**/*</code> that is not <code>pub</code> may change freely between releases.</p>
<p><code>librtmp2</code> follows SemVer but remains on <code>0.x</code> while in alpha. Semantic-versioning guarantees begin at <code>1.0.0</code>. Pin a crates.io version (currently <code>0.3.1</code>) if you depend on a specific API shape.</p>
<p><code>librtmp2-server</code> (currently <code>0.1.4</code>) and <code>librtmp2-server-panel</code> are also alpha &mdash; REST API shapes, environment variable names, and Docker images may evolve.</p>
<p><code>librtmp2-server</code> (currently <code>0.2.0</code>) and <code>librtmp2-server-panel</code> (currently <code>0.2.0</code>) are also alpha &mdash; REST API shapes, environment variable names, and Docker images may evolve. Prefer GitHub releases and image tags over hard-coding versions from this page.</p>

</div>
</div>
Expand Down
6 changes: 4 additions & 2 deletions download/index.php
Original file line number Diff line number Diff line change
Expand Up @@ -66,9 +66,11 @@
<pre><code>git clone https://github.com/OpenRTMP/librtmp2-server.git
cd librtmp2-server
cargo build --release
# Optional HA clustering:
# cargo build --release --features cluster
cp .env.example .env
LRTMP2_DB=./server.db ./target/release/librtmp2-server</code></pre>
<p>The API token is generated on first startup unless supplied as the real <code>LRTMP2_API_TOKEN</code> process environment variable.</p>
<p>The API token is generated on first startup unless supplied as the real <code>LRTMP2_API_TOKEN</code> process environment variable. Docker images already include the <code>cluster</code> feature; runtime clustering stays off until you set <code>CLUSTER_ENABLED=true</code>. See the <a href="/guides/rtmp-server-ha-clustering/">HA clustering guide</a>.</p>
</div>

<div class="download-card download-card--wide" id="docker-stack">
Expand Down Expand Up @@ -126,7 +128,7 @@

<div class="cta" style="margin-top: 48px;">
<h2>Not sure which component you need?</h2>
<p>The homepage separates the library and operator paths, while the guides cover Docker, OBS, RTMPS, and Enhanced RTMP.</p>
<p>The homepage separates the library and operator paths, while the guides cover Docker, OBS, RTMPS, HA clustering, and Enhanced RTMP.</p>
<div class="hero-actions" style="margin-bottom:0;">
<a href="/#paths" class="btn btn-primary">Choose a path</a>
<a href="/guides/" class="btn btn-ghost">Browse guides</a>
Expand Down
11 changes: 9 additions & 2 deletions guides/index.php
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<?php
$page = 'guides';
$pageTitle = 'OpenRTMP Guides — Docker, OBS, RTMPS, NOALBS, and Enhanced RTMP';
$pageDescription = 'Practical OpenRTMP guides for self-hosting an RTMP server, publishing from OBS, enabling RTMPS, connecting NOALBS statistics, and understanding Enhanced RTMP codecs.';
$pageTitle = 'OpenRTMP Guides — Docker, OBS, RTMPS, Clustering, NOALBS, and Enhanced RTMP';
$pageDescription = 'Practical OpenRTMP guides for self-hosting an RTMP server, publishing from OBS, enabling RTMPS, HA clustering, connecting NOALBS statistics, and understanding Enhanced RTMP codecs.';
$canonicalPath = '/guides/';
include __DIR__ . '/../includes/header.php';
?>
Expand Down Expand Up @@ -30,6 +30,13 @@
<a href="/guides/rtmps-server-obs/" class="text-link">Read the RTMPS guide &rarr;</a>
</article>

<article class="card guide-card">
<span class="guide-tag">HA &middot; Clustering &middot; OpenRaft</span>
<h2><a href="/guides/rtmp-server-ha-clustering/">Run an HA RTMP server cluster</a></h2>
<p>Enable optional multi-node clustering, bootstrap and join voters, expose control/media ports, and operate nodes from the API or panel — with current alpha limits stated up front.</p>
<a href="/guides/rtmp-server-ha-clustering/" class="text-link">Read the clustering guide &rarr;</a>
</article>

<article class="card guide-card">
<span class="guide-tag">E-RTMP &middot; HEVC &middot; AV1 &middot; Opus</span>
<h2><a href="/guides/enhanced-rtmp-hevc-av1-opus/">Enhanced RTMP codecs explained</a></h2>
Expand Down
4 changes: 3 additions & 1 deletion guides/openrtmp-vs-nginx-rtmp/index.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
<section class="content-section" style="padding-top: 0;">
<div class="container article-layout">
<article class="prose">
<div class="callout"><strong>Summary:</strong> choose nginx-rtmp for established nginx workflows and built-in module features. Choose OpenRTMP for a Rust-first protocol stack, a small API-driven server, separate stream keys, JSON statistics, and an embeddable library — while accepting its alpha status and narrower feature set.</div>
<div class="callout"><strong>Summary:</strong> choose nginx-rtmp for established nginx workflows and built-in module features. Choose OpenRTMP for a Rust-first protocol stack, a small API-driven server, separate stream keys, JSON statistics, optional HA clustering, and an embeddable library — while accepting its alpha status and narrower media feature set.</div>

<h2 id="overview">High-level comparison</h2>
<table class="comparison-table">
Expand All @@ -38,6 +38,7 @@
<tr><td>Statistics</td><td>JSON plus nginx-compatible XML</td><td>Classic XML statistics endpoint with XSL presentation</td></tr>
<tr><td>Embeddable library</td><td>Rust crate and C-compatible FFI</td><td>No equivalent standalone protocol crate</td></tr>
<tr><td>HLS, recording, exec, push</td><td>Not built into the current server</td><td>Common nginx-rtmp module features</td></tr>
<tr><td>Multi-node HA</td><td>Optional OpenRaft + media mesh clustering (alpha, off by default)</td><td>Usually external load balancers, shared storage, or custom push topology</td></tr>
<tr><td>Modern RTMP work</td><td>Explicit focus on RTMPS and Enhanced RTMP building blocks</td><td>Primarily traditional RTMP module workflows</td></tr>
</tbody>
</table>
Expand All @@ -49,6 +50,7 @@
<li>You want separate publish, playback, and monitoring credentials.</li>
<li>You need JSON statistics but also want compatibility with tools that expect nginx-style XML.</li>
<li>You want to contribute to Enhanced RTMP, RTMPS, interoperability, or parser safety work.</li>
<li>You want optional multi-node HA with replicated stream state (evaluate carefully; still alpha).</li>
<li>You accept alpha software and can test the exact publishing/playback workflow.</li>
</ul>

Expand Down
Loading