From dffee1ddc8433c92c31a2f4d52882f35af076507 Mon Sep 17 00:00:00 2001 From: AlexanderWagnerDev Date: Sun, 9 Aug 2026 19:22:11 +0200 Subject: [PATCH] docs: document optional HA clustering Server/panel 0.2.0 cluster mode was missing from the site. Co-authored-by: Cursor --- README.md | 4 +- docs/index.php | 46 ++++++- download/index.php | 6 +- guides/index.php | 11 +- guides/openrtmp-vs-nginx-rtmp/index.php | 4 +- guides/rtmp-server-ha-clustering/index.php | 129 ++++++++++++++++++ .../self-hosted-rtmp-server-docker/index.php | 3 + index.php | 19 ++- sitemap.xml | 18 ++- 9 files changed, 217 insertions(+), 23 deletions(-) create mode 100644 guides/rtmp-server-ha-clustering/index.php diff --git a/README.md b/README.md index e16f69e..8e188db 100644 --- a/README.md +++ b/README.md @@ -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. diff --git a/docs/index.php b/docs/index.php index 35942cd..b454d3f 100644 --- a/docs/index.php +++ b/docs/index.php @@ -1,7 +1,7 @@ @@ -23,6 +23,7 @@
  • Host Callbacks
  • Module Reference
  • librtmp2-server
  • +
  • HA clustering
  • librtmp2-server-panel
  • Docker Deployment
  • API & Versioning
  • @@ -139,10 +140,11 @@ REST APIstream CRUD on /api/v1/streams with Bearer token auth (axum, port 8080) Stats endpoints/stats?key=<stats_key> (JSON) and /stats-nginx?key=<stats_key> (nginx-rtmp-compatible XML) Frame relayforwards publisher frames to all matching players, GOP-aware + HA clusteringoptional multi-node mode (CLUSTER_ENABLED, off by default) with OpenRaft state replication and a media mesh — see HA clustering -

    Build and run natively:

    +

    Build and run natively (standalone):

    git clone https://github.com/OpenRTMP/librtmp2-server.git
     cd librtmp2-server
     cargo build --release
    @@ -155,6 +157,37 @@
       -H "Content-Type: application/json" \
       -d '{"id":"mystream","name":"My Live Stream","app":"live"}'
    +

    HA clustering

    +

    From server 0.2.0, librtmp2-server can run as a multi-node cluster. Clustering is off by default; standalone behavior is unchanged when CLUSTER_ENABLED=false. Published Docker images build with the cluster Cargo feature; runtime still defaults to standalone.

    +

    Architecture in short:

    +
    + + + + + + + +
    PlaneDefault portRole
    Control1940OpenRaft RPC, join/admin, heartbeats, StatsProxy
    Media1941Inter-node frame relay, subscribe, init-cache
    RTMP / HTTP1935 / 8080Client publish/play and admin API (unchanged)
    +
    + +

    Minimal bootstrap (first voter):

    +
    CLUSTER_ENABLED=true
    +CLUSTER_NODE_ID=1
    +CLUSTER_BOOTSTRAP=true
    +CLUSTER_SECRET=<long-random-secret>
    +CLUSTER_ADVERTISE_ADDR=10.0.0.1:1940
    +CLUSTER_MEDIA_ADVERTISE_ADDR=10.0.0.1:1941
    +

    Additional nodes join with an empty database and CLUSTER_JOIN=<existing-control-addr>, then promote learners to voters via POST /api/v1/cluster/nodes/{id}/promote.

    +

    Authenticated cluster APIs include GET /api/v1/cluster, /nodes, /streams, plus drain/resume/promote/remove. Full configuration, limitations, and operator notes live in the server repo's docs/clustering.md and the site guide Run an HA RTMP cluster.

    +

    Native builds that need clustering must compile with the feature:

    +
    cargo build --release --features cluster
    +

    librtmp2-server-panel

    librtmp2-server-panel is a Flask web UI that talks to the server's REST API. It does not implement RTMP itself — it manages streams, copies URLs, and polls live stats.

    @@ -164,11 +197,13 @@ Stream managementcreate and delete streams via /api/v1/streams One-click copypublish URL, stream key, play URL, and stats URL Live statsbitrate, resolution, codec, uptime, RTT polled from /stats?key=... + Cluster UIwhen health reports cluster.enabled=true: quorum overview, node drain/resume/remove, stream owner/epoch placement Login gateoptional admin login (REQUIRE_LOGIN=True by default) SecurityCSRF protection, rate limiting (Redis-backed in Docker), encrypted key display
    +

    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.

    Key environment variables (see .env.example in the panel repo):

    @@ -198,7 +233,7 @@ ghcr.io/openrtmp/librtmp2-server:latest docker logs librtmp2-server # copy API token from first-start output -

    Available tags: latest, beta, alpha, and pinned versions (e.g. 0.1.4).

    +

    Available tags: latest, beta, alpha, and pinned versions (e.g. 0.2.0).

    Panel only (docker run)

    Image: ghcr.io/openrtmp/librtmp2-server-panel. Connect to an existing server on the same Docker network (container name librtmp2-server):

    @@ -263,17 +298,20 @@ + +
    1935RTMP ingest / playback (RTMP_BIND)
    1936RTMPS ingest / playback (RTMPS_BIND) — only when TLS_ENABLED=true; not exposed in the default compose file (uncomment 1936:1936 there)
    1940Cluster control plane (CLUSTER_BIND) — only when CLUSTER_ENABLED=true
    1941Cluster media mesh (CLUSTER_MEDIA_BIND) — only when clustering is enabled
    8080HTTP API, stats, health check (HTTP_BIND)
    8000Web panel

    To enable RTMPS alongside plaintext RTMP, set LRTMP2_TLS_ENABLED=true (or TLS_ENABLED=true in .env), mount cert/key files, expose port 1936, and set RTMPS_BIND=0.0.0.0:1936 as in librtmp2-server/docker-compose.yml. The panel shows rtmps:// URLs only when GET /api/v1/health reports rtmps_enabled: true (and uses LRTMP2_RTMPS_PORT, default 1936).

    +

    For a multi-node cluster, expose 1940 and 1941 between peers, set the CLUSTER_* variables described under HA clustering, and keep each node on its own SQLite volume. See the clustering guide for bootstrap and join steps.

    API & Versioning

    Only the public librtmp2 crate interface is the intended stable API surface. Everything under src/**/* that is not pub may change freely between releases.

    librtmp2 follows SemVer but remains on 0.x while in alpha. Semantic-versioning guarantees begin at 1.0.0. Pin a crates.io version (currently 0.3.1) if you depend on a specific API shape.

    -

    librtmp2-server (currently 0.1.4) and librtmp2-server-panel are also alpha — REST API shapes, environment variable names, and Docker images may evolve.

    +

    librtmp2-server (currently 0.2.0) and librtmp2-server-panel (currently 0.2.0) are also alpha — REST API shapes, environment variable names, and Docker images may evolve. Prefer GitHub releases and image tags over hard-coding versions from this page.

    diff --git a/download/index.php b/download/index.php index 4851e77..f3165d0 100644 --- a/download/index.php +++ b/download/index.php @@ -66,9 +66,11 @@
    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
    -

    The API token is generated on first startup unless supplied as the real LRTMP2_API_TOKEN process environment variable.

    +

    The API token is generated on first startup unless supplied as the real LRTMP2_API_TOKEN process environment variable. Docker images already include the cluster feature; runtime clustering stays off until you set CLUSTER_ENABLED=true. See the HA clustering guide.

    @@ -126,7 +128,7 @@

    Not sure which component you need?

    -

    The homepage separates the library and operator paths, while the guides cover Docker, OBS, RTMPS, and Enhanced RTMP.

    +

    The homepage separates the library and operator paths, while the guides cover Docker, OBS, RTMPS, HA clustering, and Enhanced RTMP.

    Choose a path Browse guides diff --git a/guides/index.php b/guides/index.php index 12e194d..4f2cac7 100644 --- a/guides/index.php +++ b/guides/index.php @@ -1,7 +1,7 @@ @@ -30,6 +30,13 @@ Read the RTMPS guide → + +
    E-RTMP · HEVC · AV1 · Opus

    Enhanced RTMP codecs explained

    diff --git a/guides/openrtmp-vs-nginx-rtmp/index.php b/guides/openrtmp-vs-nginx-rtmp/index.php index 5c29839..d9135be 100644 --- a/guides/openrtmp-vs-nginx-rtmp/index.php +++ b/guides/openrtmp-vs-nginx-rtmp/index.php @@ -25,7 +25,7 @@
    -
    Summary: 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.
    +
    Summary: 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.

    High-level comparison

    @@ -38,6 +38,7 @@ +
    StatisticsJSON plus nginx-compatible XMLClassic XML statistics endpoint with XSL presentation
    Embeddable libraryRust crate and C-compatible FFINo equivalent standalone protocol crate
    HLS, recording, exec, pushNot built into the current serverCommon nginx-rtmp module features
    Multi-node HAOptional OpenRaft + media mesh clustering (alpha, off by default)Usually external load balancers, shared storage, or custom push topology
    Modern RTMP workExplicit focus on RTMPS and Enhanced RTMP building blocksPrimarily traditional RTMP module workflows
    @@ -49,6 +50,7 @@
  • You want separate publish, playback, and monitoring credentials.
  • You need JSON statistics but also want compatibility with tools that expect nginx-style XML.
  • You want to contribute to Enhanced RTMP, RTMPS, interoperability, or parser safety work.
  • +
  • You want optional multi-node HA with replicated stream state (evaluate carefully; still alpha).
  • You accept alpha software and can test the exact publishing/playback workflow.
  • diff --git a/guides/rtmp-server-ha-clustering/index.php b/guides/rtmp-server-ha-clustering/index.php new file mode 100644 index 0000000..a78eea2 --- /dev/null +++ b/guides/rtmp-server-ha-clustering/index.php @@ -0,0 +1,129 @@ + 'https://schema.org', + '@type' => 'TechArticle', + 'headline' => 'Run an HA RTMP server cluster', + 'description' => $pageDescription, + 'author' => ['@type' => 'Organization', 'name' => 'OpenRTMP'], + 'mainEntityOfPage' => 'https://openrtmp.org/guides/rtmp-server-ha-clustering/' +]; +include __DIR__ . '/../../includes/header.php'; +?> + +
    +
    + HA · Clustering · OpenRaft +

    Run an HA RTMP server cluster

    +

    Optional multi-node mode replicates durable stream state with OpenRaft and relays live media between peers over a media mesh. Standalone single-node operation remains the default.

    +
    + +
    +
    +
    +
    Alpha feature: clustering landed in server and panel 0.2.0. Test failover, publisher reconnect, and firewall paths thoroughly. Invalid cluster configuration fails startup hard — there is no silent fallback to standalone.
    + +

    What clustering provides

    +

    With CLUSTER_ENABLED=true, each node keeps its own SQLite file while durable mutations (streams, viewers, tokens, ownership) go through Raft. Live frames leave the publisher owner over the media mesh so players can attach to other healthy nodes.

    +
      +
    • Replicated stream registry without a central media proxy or mandatory Postgres/Redis
    • +
    • Publisher ownership with epoch fencing and quorum-aware failure detection
    • +
    • Load-based drain/resume admission on nodes
    • +
    • Shared-secret peer authentication, with optional mTLS for control and media
    • +
    +

    Published Docker images already compile with --features cluster. Native builds need the Cargo feature explicitly. Runtime still defaults to CLUSTER_ENABLED=false.

    + +

    Planes and ports

    + + + + + + + + +
    PlaneDefaultPurpose
    Control1940/tcpRaft, join/admin, heartbeats, StatsProxy
    Media1941/tcpFrame relay, subscribe, init-cache
    RTMP1935/tcpPublisher and player connections (unchanged)
    HTTP API8080/tcpAdmin REST API and health
    +

    Expose 1940 and 1941 between cluster peers. Keep the admin API restricted; RTMP exposure follows the same rules as a standalone deploy.

    + +

    1. Bootstrap the first voter

    +

    Start the first node with a shared secret (at least 16 characters) and advertise addresses peers can dial:

    +
    CLUSTER_ENABLED=true
    +CLUSTER_NODE_ID=1
    +CLUSTER_BOOTSTRAP=true
    +CLUSTER_SECRET=<long-random-secret>
    +CLUSTER_BIND=0.0.0.0:1940
    +CLUSTER_MEDIA_BIND=0.0.0.0:1941
    +CLUSTER_ADVERTISE_ADDR=10.0.0.1:1940
    +CLUSTER_MEDIA_ADVERTISE_ADDR=10.0.0.1:1941
    +

    Existing standalone streams, viewers, and the API token are seeded into Raft on first bootstrap. Docker mappings for a clustered node typically add:

    +
    ports:
    +  - "1935:1935"
    +  - "8080:8080"
    +  - "1940:1940"
    +  - "1941:1941"
    + +

    2. Join additional nodes

    +

    Each joiner needs an empty database (no prior streams or raft_* state) and the same secret:

    +
    CLUSTER_ENABLED=true
    +CLUSTER_NODE_ID=2
    +CLUSTER_JOIN=10.0.0.1:1940
    +CLUSTER_SECRET=<same-secret>
    +LRTMP2_DB=/data/node2.db
    +

    Joined nodes start as learners. After catch-up, promote to voter:

    +
    curl -X POST http://10.0.0.1:8080/api/v1/cluster/nodes/2/promote \
    +  -H "Authorization: Bearer <api-token>"
    +

    Do not copy a live SQLite file from another node and join — that creates conflicting Raft state. To reseed, delete the node's DB files and join again.

    + +

    3. Operate from the API or panel

    +

    Useful authenticated endpoints:

    + + + + + + + + + + +
    MethodPathPurpose
    GET/api/v1/clusterLeader, term, quorum, load
    GET/api/v1/cluster/nodesPeer list and health states
    GET/api/v1/cluster/streamsOwner, epoch, mesh subscriptions
    POST.../nodes/{id}/drainMark node DRAINING
    POST.../nodes/{id}/resumeMark node READY
    DELETE.../nodes/{id}Remove voter (releases its owners)
    +

    When health reports cluster.enabled=true, the web panel shows a Cluster page with quorum status, node actions (drain/resume/remove), and per-stream owner/epoch placement. Point the panel at any healthy synchronized node — it does not participate in Raft.

    + +

    Current limitations

    +
      +
    • After owner failure, publishers must reconnect to a public RTMP endpoint; automatic publisher migration is not implied.
    • +
    • Peers that join mid-stream need init-cache / stream_init_snapshot before playback works.
    • +
    • Enable CLUSTER_TLS_ENABLED with cert/key/CA for production peer links; certificate subjects must embed lrtmp2-node-{id}.
    • +
    • Learner-to-voter promotion is explicit via the API, not automatic on every join.
    • +
    • Treat clustering as evaluation-grade HA until you have validated your topology end to end.
    • +
    +

    The canonical operator reference is docs/clustering.md in the server repository.

    + +
    +

    Start standalone, then add nodes

    +

    Validate a single-node Docker stack first. Enable clustering only after RTMP publish/play and the panel work cleanly.

    + +
    +
    + + +
    +
    +
    + + diff --git a/guides/self-hosted-rtmp-server-docker/index.php b/guides/self-hosted-rtmp-server-docker/index.php index 7005768..e3928bc 100644 --- a/guides/self-hosted-rtmp-server-docker/index.php +++ b/guides/self-hosted-rtmp-server-docker/index.php @@ -50,6 +50,7 @@ 1935/tcpRTMP publishers and playersExpose when remote RTMP clients need it 8000/tcpWeb control panelPrefer HTTPS through a reverse proxy 8080/tcpREST API and statisticsRestrict; proxy only required routes + 1940/tcp / 1941/tcpCluster control and media meshOnly between peers when CLUSTER_ENABLED=true; see the HA guide @@ -90,6 +91,7 @@
  • Put the panel behind HTTPS and enable secure cookies.
  • Do not expose the administrative REST API broadly.
  • Enable RTMPS when publishers need encrypted transport.
  • +
  • For multi-node HA, follow the clustering guide and give each node its own SQLite volume.
  • Back up the persistent SQLite volume.
  • Pin tested container versions instead of using moving tags.
  • Apply connection, request-body, and rate limits appropriate for the host.
  • @@ -114,6 +116,7 @@
    diff --git a/index.php b/index.php index 66bffb3..d30793a 100644 --- a/index.php +++ b/index.php @@ -1,7 +1,7 @@ 'https://schema.org', @@ -19,7 +19,7 @@ 'name' => 'OpenRTMP Server and Panel', 'applicationCategory' => 'DeveloperApplication', 'operatingSystem' => 'Linux, Docker', - 'description' => 'Self-hosted RTMP/RTMPS server with REST API, stream keys, live statistics, and a web control panel.', + 'description' => 'Self-hosted RTMP/RTMPS server with REST API, stream keys, optional HA clustering, live statistics, and a web control panel.', 'url' => 'https://openrtmp.org/quickstart/' ] ] @@ -84,6 +84,7 @@
  • RTMP and optional RTMPS listeners
  • Per-stream publish, play, and statistics keys
  • SQLite persistence and Bearer-authenticated REST API
  • +
  • Optional multi-node HA clustering (off by default)
  • JSON and nginx-compatible XML statistics
  • Web panel for stream creation and live monitoring
  • @@ -155,6 +156,11 @@

    Monitoring-friendly

    Use modern JSON statistics or nginx-rtmp-compatible XML for existing monitoring and automation tools.

    +
    +
    🖥️
    +

    Optional HA clustering

    +

    Run multiple server nodes with replicated stream state and a media mesh for playback across nodes. Standalone mode stays the default.

    +
    🧩

    Composable projects

    @@ -172,9 +178,9 @@

    That separation makes it clear which project to adopt and where to contribute.

    -
    PanelBrowser UI for stream lifecycle, copyable URLs, keys, and live statistics
    +
    PanelBrowser UI for stream lifecycle, copyable URLs, keys, live statistics, and optional cluster node management
    -
    ServerREST API, authentication, SQLite, statistics, listener configuration, and stream registry
    +
    ServerREST API, authentication, SQLite, statistics, listeners, stream registry, and optional HA clustering
    librtmp2RTMP/RTMPS connection, handshake, chunking, AMF commands, relay primitives, and E-RTMP modules
    @@ -198,6 +204,7 @@
  • Custom Rust or FFI-based RTMP applications
  • OBS/FFmpeg integration testing
  • Stream-key and statistics tooling
  • +
  • Multi-node HA evaluation with optional clustering
  • Protocol research and contribution
  • @@ -230,13 +237,13 @@
    📡

    librtmp2-server

    -

    RTMP/RTMPS application layer with SQLite, keys, REST API, and monitoring endpoints.

    +

    RTMP/RTMPS application layer with SQLite, keys, REST API, monitoring endpoints, and optional HA clustering.

    🎨

    librtmp2-server-panel

    -

    Flask web UI for creating streams, copying URLs, and monitoring live publisher/player statistics.

    +

    Flask web UI for creating streams, copying URLs, monitoring live statistics, and managing cluster nodes when HA is enabled.

    diff --git a/sitemap.xml b/sitemap.xml index 55284b5..63d33fc 100644 --- a/sitemap.xml +++ b/sitemap.xml @@ -2,7 +2,7 @@ https://openrtmp.org/ - 2026-07-18 + 2026-08-09 weekly 1.0 @@ -14,13 +14,13 @@ https://openrtmp.org/guides/ - 2026-07-26 + 2026-08-09 weekly 0.8 https://openrtmp.org/guides/self-hosted-rtmp-server-docker/ - 2026-07-18 + 2026-08-09 monthly 0.8 @@ -30,6 +30,12 @@ monthly 0.8 + + https://openrtmp.org/guides/rtmp-server-ha-clustering/ + 2026-08-09 + monthly + 0.8 + https://openrtmp.org/guides/enhanced-rtmp-hevc-av1-opus/ 2026-07-18 @@ -44,19 +50,19 @@ https://openrtmp.org/guides/openrtmp-vs-nginx-rtmp/ - 2026-07-18 + 2026-08-09 monthly 0.8 https://openrtmp.org/docs/ - 2026-07-18 + 2026-08-09 weekly 0.8 https://openrtmp.org/download/ - 2026-07-18 + 2026-08-09 weekly 0.8