PodWarden
Use Cases

User-Generated Content Streaming

Build a geo-distributed live streaming platform — WebRTC ingest, GPU transcoding, multi-region HLS and WebRTC egress — entirely on your own infrastructure

A user-generated content streaming platform has more moving parts than most distributed systems: streamers push live video from arbitrary locations, your platform ingests it, transcodes it to multiple bitrates, archives it, and distributes it to viewers worldwide — with sub-second latency on the ingest side and smooth playback on egress.

Every component of this stack — ingest servers, transcoders, origin storage, egress nodes, databases, monitoring, auth — can be deployed as a workload from the PodWarden Hub catalog. Bring the pieces you already have; deploy the rest. The result is a fully self-hosted streaming platform running on nodes you control, managed from one dashboard.


What You Need

ComponentBring your ownOr deploy from Hub
WebRTC / RTMP ingestExisting SRS, LiveKit, Ant MediaSRS, LiveKit, or Janus from Hub
TranscoderExisting FFmpeg pipelineFFmpeg transcoder workload from Hub
Object storageAWS S3, GCS, existing MinIOMinIO or RustFS — for HLS segments and VOD archive
CDN / edge cacheExisting CDNnginx-based HLS edge from Hub for self-hosted distribution
DatabaseExisting PostgreSQLPostgreSQL — stream state, user records, stream keys
Auth / SSOExisting identity providerKeycloak — stream key validation, admin access, viewer auth
Secrets managementVault, AWS Secrets ManagerVault — stream keys, API credentials, TURN secrets
Job queueRedis, NATSRedis — for transcoding job coordination
MonitoringExisting Prometheus + GrafanaPrometheus + Grafana + DCGM Exporter
TURN serverExisting coturncoturn — from Hub, required for WebRTC behind NAT

Platform Architecture

Each tier is one or more clusters of PodWarden nodes. Ingest and egress clusters sit at the edge — public IP, multiple regions. The transcoding cluster sits in the middle — mesh only, not publicly exposed.


Building the Foundation

Deploy shared services first. These run on dedicated nodes (or your control plane node for smaller setups) and are referenced by every other tier.

1. Object Storage

HLS segments and VOD archives need to be readable by all egress nodes simultaneously. S3-compatible storage is the right choice.

If you have S3 or a compatible endpoint, register it as a storage connection in PodWarden.

If you don't: import MinIO or RustFS from Hub. Deploy to a well-connected central node (or multiple nodes for HA). Create buckets for live HLS segments (short TTL, high write throughput) and archive/VOD (durable, lower throughput).

2. Database

Stream state, user records, and stream key validation live in PostgreSQL.

Import PostgreSQL from Hub if you don't have one. The ingest servers query it to validate incoming stream keys. The platform API reads and writes stream metadata. Grafana uses it as a data source for stream analytics.

3. Auth / SSO

Keycloak (from Hub) provides:

  • Stream key issuance and validation via the REST API or token introspection
  • Admin UI access (role-based: admin, moderator, viewer)
  • OIDC integration with your platform's user accounts
  • SSO for PodWarden itself — operators sign in with the same identity

If you already have Keycloak or another OIDC provider, configure PodWarden to use it. No Hub deployment needed.

4. Secrets

TURN server credentials, S3 keys, database passwords, and Keycloak client secrets go into Vault (from Hub). stacks reference secrets via secret_refs — injected as environment variables at deploy time, never stored in templates.

5. Monitoring

Prometheus + Grafana + DCGM Exporter (DaemonSet) from Hub. DCGM Exporter runs on every GPU node and surfaces NVENC/NVDEC engine utilization on the transcoding tier — critical for detecting encoder saturation during traffic spikes.

Build Grafana dashboards for:

  • Active concurrent streams per ingest region
  • Transcoding queue depth and latency
  • HLS segment delivery errors per egress region
  • GPU encoder utilization on transcoding nodes

Ingest Tier

WebRTC ingest servers accept live streams from browsers, OBS, and mobile apps. Deploy to nodes with public IP addresses — streamers need to reach them directly.

Template

Kind:               Deployment
Image:              ossrs/srs:6
GPU count:          0
CPU:                8
Memory:             16Gi
Required networks:  public

Set required_network_types: ["public"] on the ingest template. PodWarden warns if you try to deploy it to a cluster that doesn't have public-facing nodes.

Key environment variables

VariableExampleDescription
REGIONeu-westRegion identifier for geo-routing
RELAY_TARGETtranscode.mesh:1935Transcoding node relay address (mesh)
POSTGRES_URL(from secret ref)Stream key validation database
KEYCLOAK_URLhttps://sso.internalAuth endpoint
MAX_STREAMS200Concurrent stream capacity
WEBRTC_PORT_START10000UDP port range start
TURN_URL(from secret ref)TURN server for NAT traversal

TURN server

WebRTC clients behind symmetric NAT need TURN. Import coturn from Hub. Deploy to a public node (it needs a public IP to function). Register the TURN credentials in Vault and inject them into both the ingest server and your client SDK configuration.

Geo-distribution

Deploy ingest clusters in each region where you have significant streamer populations. A Frankfurt streamer hits a Frankfurt ingest node. The stream travels over the mesh VPN to the central transcoding cluster — not across the public internet.


Transcoding Tier

The transcoding layer converts incoming streams to adaptive bitrate ladders, packages HLS segments, and writes them to MinIO/S3.

Template

Kind:               Deployment
Image:              custom-transcoder:latest
GPU count:          1
VRAM:               8Gi
CPU:                16
Memory:             32Gi
Required networks:  mesh

Transcoding nodes need mesh access only — they receive streams from ingest nodes over the VPN and push output to MinIO over the same network.

Key environment variables

VariableExampleDescription
INGEST_LISTEN0.0.0.0:1935Listen address for ingest relay
HLS_BUCKETs3://streams-liveHLS segment output bucket
ARCHIVE_BUCKETs3://streams-archiveVOD archive bucket
HLS_SEGMENT_DURATION2Segment length in seconds
ABR_LADDER1080p,720p,480p,360pOutput resolutions
HWACCELcudaHardware acceleration
QUEUE_URLredis://redis.mesh:6379Transcoding job coordination
S3_ENDPOINT_URLhttp://minio.mesh:9000Internal MinIO

For large platforms, Jetson Orin NX nodes are excellent transcoding workers — see the Video Transcoding article for details on building a Jetson cluster.


Egress Tier

Egress nodes serve HLS and WebRTC streams to viewers. They pull segments from MinIO origin, cache them locally, and serve them to viewers.

Template

Kind:               Deployment
Image:              custom-edge-server:latest
GPU count:          0
CPU:                8
Memory:             16Gi
Required networks:  public

Like ingest, egress nodes require public connectivity — viewers connect directly to them.

Key environment variables

VariableExampleDescription
REGIONus-eastRegion identifier
ORIGIN_BUCKETs3://streams-liveHLS origin (MinIO)
CACHE_TTL2Segment cache duration in seconds
WEBRTC_ORIGINtranscode.mesh:7000WebRTC origin SFU address
MAX_VIEWERS5000Concurrent viewer capacity per node
S3_ENDPOINT_URLhttp://minio.mesh:9000Internal MinIO

Geo-redundancy

Deploy egress clusters in each major viewer region. Viewers connect to the nearest node — lower latency, lower cross-region bandwidth cost. If an egress cluster goes down, your routing layer (geo DNS, anycast) fails over to the next region. PodWarden manages the workloads; routing is external.


Mesh Networking: Connecting the Tiers

All internal communication runs over the mesh VPN (Tailscale, WireGuard, or Nebula). PodWarden auto-detects Tailscale-connected nodes and tags them mesh.

TierNetwork tagsWhy
Ingestpublic + meshPublic for streamers, mesh to relay to transcoder
TranscodingmeshNot publicly exposed; receives relays and pushes to MinIO
Egresspublic + meshPublic for viewers, mesh to pull from MinIO
MinIO, PostgreSQL, Vault, RedismeshInternal services only

PodWarden's deploy-time network check enforces this topology. Deploying a transcoding worker to a public-only node (that has no mesh access to ingest or MinIO) generates a warning before the deployment proceeds.


Live Stream Lifecycle


Hub Templates for This Stack

TemplateRole
SRSWebRTC / RTMP ingest and relay
LiveKitSFU-based WebRTC ingest and egress
JanusVersatile WebRTC gateway
FFmpeg transcoderABR ladder generation, HLS packaging
nginx HLS edgeHLS edge server with S3 origin and local cache
coturnTURN server for WebRTC NAT traversal
MinIOS3 object storage for HLS segments and archive
RustFSHigh-performance S3 storage
PostgreSQLStream state and user database
RedisTranscoding job queue and pub/sub
KeycloakSSO, stream key auth, admin access
VaultSecrets: TURN credentials, S3 keys, DB passwords
PrometheusMetrics collection
GrafanaStream platform dashboards
DCGM ExporterGPU encoder metrics on transcoding nodes (DaemonSet)

Every component in the list above runs as a standard PodWarden workload on nodes you own. The entire platform — ingest, transcoding, origin, egress, storage, auth, monitoring — is self-contained. No external cloud service dependencies unless you choose them.