๐ŸŽง Listen

You want to stream your desktop โ€” live coding sessions, demos, presentations, or just a shared workspace โ€” to visitors on your own website. Not through YouTube Live, not through Twitch, not through any platform that can change its terms, inject ads, or shut you down. Your server, your stream, your rules.

This guide covers everything you need: the streaming protocols that make it work, the open-source servers you can self-host, how to capture your desktop, how to embed the player on your website, how to lock it down so only authorized users can watch, and a practical recommendation for the fastest path from zero to live.

1. Why Self-Host Your Live Stream?

Third-party streaming platforms are convenient, but they come with strings attached:

๐Ÿ’ก The Core Idea A self-hosted streaming setup has three parts: (1) a capture tool on your desktop that encodes video, (2) a streaming server that receives and repackages the video, and (3) a web player embedded on your site that viewers watch. That's it. The rest is details.

2. Streaming Protocols Explained

Before choosing a server, you need to understand the protocols. Each one makes different tradeoffs between latency, compatibility, and complexity.

RTMP (Real-Time Messaging Protocol)

Originally developed by Macromedia (Adobe) for Flash. Despite Flash being dead, RTMP lives on as the de facto standard for stream ingest โ€” it's what OBS sends to your server. Low latency (1โ€“5 seconds), reliable, well-supported by every streaming tool. However, browsers can't play RTMP directly anymore, so your server must transcode it into something browsers understand (usually HLS).

HLS (HTTP Live Streaming)

Apple's protocol. Breaks video into small chunks (typically 2โ€“6 seconds) served over plain HTTP. Universal browser support โ€” works on every device, every browser, every CDN. The tradeoff is latency: standard HLS has 10โ€“30 seconds of delay. Low-Latency HLS (LL-HLS) reduces this to 2โ€“5 seconds but is more complex to configure. HLS is the standard for delivery to viewers.

DASH (Dynamic Adaptive Streaming over HTTP)

The open standard alternative to HLS. Very similar in concept โ€” chunked HTTP delivery with adaptive bitrate. Less universal than HLS (no native Safari support without workarounds). In practice, HLS has won the delivery war for live streaming.

WebRTC (Web Real-Time Communication)

Built into every modern browser for video calls. Sub-second latency (<500ms typical). Peer-to-peer by design but can work through media servers. The lowest latency option, but harder to scale to many viewers and more complex to set up. Ideal for interactive streams where real-time matters (live coding with audience input, remote pair programming).

SRT (Secure Reliable Transport)

Developed by Haivision, now open-source. Designed for reliable streaming over lossy networks (internet, cellular). Built-in encryption, error correction, and bandwidth adaptation. Increasingly used for ingest (source โ†’ server) as a modern, more resilient alternative to RTMP. Not directly playable in browsers โ€” your server converts it to HLS or WebRTC for viewers.

Protocol Latency Browser Support Best For
RTMP 1โ€“5s โŒ Ingest only Sending stream to server (OBS โ†’ server)
HLS 5โ€“30s (LL-HLS: 2โ€“5s) โœ… Universal Delivery to viewers, CDN distribution
DASH 5โ€“30s โš ๏ธ No Safari native Alternative to HLS (less common)
WebRTC <1s โœ… All modern browsers Real-time interactive streams
SRT 1โ€“3s โŒ Ingest only Resilient ingest over bad networks
โœ… The Standard Combo Most self-hosted setups use RTMP ingest + HLS delivery. OBS sends RTMP to your server, the server converts it to HLS, and viewers watch via an HTML5 player. This gives you universal compatibility with acceptable latency (5โ€“15 seconds). If you need real-time, switch to WebRTC delivery.

3. Self-Hosted Streaming Servers

Here's every serious option for running your own streaming server, from battle-tested classics to modern WebRTC-native platforms.

Nginx + RTMP Module

The classic. The nginx-rtmp-module turns Nginx into a streaming server that accepts RTMP ingest and outputs HLS/DASH. It's been around since 2012 and powers countless streaming setups.

# nginx.conf โ€” minimal RTMP โ†’ HLS streaming setup
rtmp {
    server {
        listen 1935;
        chunk_size 4096;

        application live {
            live on;
            record off;

            # Convert RTMP to HLS
            hls on;
            hls_path /var/www/hls;
            hls_fragment 3;
            hls_playlist_length 60;

            # Optional: restrict who can publish
            allow publish 127.0.0.1;
            deny publish all;
        }
    }
}

http {
    server {
        listen 8080;

        location /hls {
            types {
                application/vnd.apple.mpegurl m3u8;
                video/mp2t ts;
            }
            root /var/www;
            add_header Cache-Control no-cache;
            add_header Access-Control-Allow-Origin *;
        }
    }
}

Owncast

Owncast is the open-source, self-hosted Twitch alternative. It's a single binary that gives you RTMP ingest, HLS delivery, a built-in web player, live chat, viewer analytics, webhooks, and an admin dashboard โ€” all out of the box.

# Run Owncast with Docker โ€” streaming in 30 seconds
docker run -d --name owncast \
  -p 8080:8080 \
  -p 1935:1935 \
  -v owncast-data:/app/data \
  owncast/owncast:latest

# Default stream key: abc123 (change in admin at http://localhost:8080/admin)
# OBS Settings: Server: rtmp://your-server:1935/live  Key: abc123
# Viewers watch at: http://your-server:8080
๐Ÿ’ก Owncast + S3 Offloading Owncast can push HLS segments to an S3 bucket (or any S3-compatible storage like Wasabi, Backblaze B2) and serve them via CloudFront. This means your VPS handles encoding but not delivery bandwidth โ€” viewers pull from the CDN. Perfect for scaling beyond a handful of viewers.

MediaMTX (formerly rtsp-simple-server)

MediaMTX is a lightweight, zero-dependency media server that supports every major protocol: RTMP, RTSP, HLS, WebRTC, SRT, and more. It's a single binary with a YAML config file.

# mediamtx.yml โ€” accept RTMP, serve as HLS + WebRTC
# Download: https://github.com/bluenviron/mediamtx/releases
paths:
  all_others:
    # Accept any stream name

# Protocols enabled by default:
# RTMP on :1935, RTSP on :8554, HLS on :8888, WebRTC on :8889

# Run it:
./mediamtx

# OBS streams to: rtmp://your-server:1935/live
# Watch HLS at: http://your-server:8888/live
# Watch WebRTC at: http://your-server:8889/live

LiveKit

LiveKit is a full-featured, open-source WebRTC infrastructure platform. It was built for video conferencing and real-time communication but works excellently for live streaming with sub-second latency.

# Run LiveKit server with Docker
docker run -d --name livekit \
  -p 7880:7880 \
  -p 7881:7881 \
  -p 7882:7882/udp \
  -e LIVEKIT_KEYS="devkey: secret" \
  livekit/livekit-server

# Install the CLI to create tokens
# npm install -g livekit-cli
# livekit-cli create-token --api-key devkey --api-secret secret \
#   --join --room mystream --identity streamer

Ant Media Server

Ant Media Server offers both Community (open-source, GPLv2) and Enterprise editions. The Community Edition supports RTMP ingest with WebRTC + HLS playback, adaptive bitrate, and a web management panel.

Janus Gateway

Janus is a general-purpose WebRTC gateway. It's extremely flexible but lower-level โ€” you'd build a streaming solution on top of its plugin architecture (specifically the Streaming plugin).

SRS (Simple Realtime Server)

SRS is a high-performance, open-source streaming server with massive adoption in China (used by companies like Alibaba and Tencent). It supports RTMP, HLS, HTTP-FLV, WebRTC, SRT, and GB28181.

# Run SRS with Docker โ€” full-featured streaming server
docker run -d --name srs \
  -p 1935:1935 \
  -p 1985:1985 \
  -p 8080:8080 \
  -p 8000:8000/udp \
  ossrs/srs:5

# RTMP ingest: rtmp://your-server:1935/live/stream
# HLS playback: http://your-server:8080/live/stream.m3u8
# WebRTC: http://your-server:1985/rtc/v1/whep/?app=live&stream=stream
# HTTP API: http://your-server:1985/api/v1/summaries

PeerTube

PeerTube is a federated video platform (think decentralized YouTube) that also supports live streaming. It uses P2P (WebTorrent/HLS) to reduce server bandwidth โ€” viewers share chunks with each other.

Server Comparison

Server Protocols Out Web UI Chat Complexity Docker
Nginx+RTMP HLS, DASH โŒ โŒ Low โœ…
Owncast HLS โœ… โœ… Very Low โœ…
MediaMTX HLS, WebRTC, RTSP โŒ โŒ Low โœ…
LiveKit WebRTC Dashboard SDK Medium โœ…
Ant Media HLS, WebRTC โœ… โŒ Medium โœ…
Janus WebRTC โŒ โŒ High โœ…
SRS HLS, WebRTC, HTTP-FLV Console โŒ Medium โœ…
PeerTube HLS (P2P) โœ… โœ… High โœ…

4. Desktop Capture Tools

You need something to capture your desktop and send it to your streaming server. Here are your options:

OBS Studio

OBS Studio is the gold standard. Free, open-source, cross-platform (Windows, macOS, Linux). It supports screen capture, window capture, camera overlays, scene switching, and outputs to RTMP, SRT, or custom FFmpeg.

# OBS Settings for self-hosted streaming:
# Settings โ†’ Stream
#   Service: Custom
#   Server: rtmp://your-server:1935/live
#   Stream Key: your-secret-key
#
# Settings โ†’ Output
#   Encoder: x264 (CPU) or NVENC (GPU)
#   Bitrate: 2500-4000 kbps for 1080p
#   Keyframe Interval: 2 seconds
#
# Settings โ†’ Video
#   Base Resolution: 1920x1080
#   Output Resolution: 1920x1080 (or 1280x720 for lower bandwidth)
#   FPS: 30

FFmpeg (Direct)

For headless streaming or automation, FFmpeg can capture your desktop and push it directly to your server. No GUI needed โ€” perfect for scripted/automated streams.

# macOS โ€” capture desktop and stream to RTMP server
ffmpeg -f avfoundation -framerate 30 -i "1:none" \
  -c:v libx264 -preset veryfast -b:v 3000k \
  -maxrate 3000k -bufsize 6000k \
  -pix_fmt yuv420p -g 60 \
  -c:a aac -b:a 128k \
  -f flv rtmp://your-server:1935/live/stream

# Linux โ€” capture desktop with PulseAudio
ffmpeg -f x11grab -framerate 30 -video_size 1920x1080 -i :0.0 \
  -f pulse -i default \
  -c:v libx264 -preset veryfast -b:v 3000k \
  -c:a aac -b:a 128k \
  -f flv rtmp://your-server:1935/live/stream

# Windows โ€” capture desktop
ffmpeg -f gdigrab -framerate 30 -i desktop \
  -c:v libx264 -preset veryfast -b:v 3000k \
  -c:a aac -b:a 128k \
  -f flv rtmp://your-server:1935/live/stream

GStreamer

Lower-level than FFmpeg, more flexible pipeline architecture. Used when you need custom processing (overlays, mixing, hardware acceleration) in a programmable way. Overkill for simple desktop streaming.

# GStreamer โ€” capture desktop and stream to RTMP (Linux)
gst-launch-1.0 ximagesrc ! videoconvert ! \
  x264enc tune=zerolatency bitrate=3000 ! \
  flvmux streamable=true ! \
  rtmpsink location="rtmp://your-server:1935/live/stream"

5. Embedding the Stream on Your Website

Once your server is outputting HLS, you need a player on your webpage. Here are the main options:

HLS.js (Lightweight)

HLS.js is a JavaScript library that plays HLS streams in any browser using Media Source Extensions. It's lightweight (~60KB gzipped) and widely used.

<!-- Minimal HLS player for your website -->
<video id="live-stream" controls autoplay muted
  style="width:100%; max-width:1280px; background:#000; border-radius:8px;">
</video>

<script src="https://cdn.jsdelivr.net/npm/hls.js@latest"></script>
<script>
  const video = document.getElementById('live-stream');
  const streamUrl = 'https://stream.thinksmart.life/hls/live.m3u8';

  if (Hls.isSupported()) {
    const hls = new Hls({
      lowLatencyMode: true,
      liveSyncDurationCount: 3,
    });
    hls.loadSource(streamUrl);
    hls.attachMedia(video);
    hls.on(Hls.Events.MANIFEST_PARSED, () => video.play());
    hls.on(Hls.Events.ERROR, (event, data) => {
      if (data.fatal) {
        // Auto-retry on fatal errors
        setTimeout(() => {
          hls.loadSource(streamUrl);
          hls.attachMedia(video);
        }, 3000);
      }
    });
  } else if (video.canPlayType('application/vnd.apple.mpegurl')) {
    // Safari native HLS support
    video.src = streamUrl;
    video.play();
  }
</script>

Video.js (Full-Featured)

Video.js is a more complete player with built-in UI controls, theming, plugins (including HLS via videojs-http-streaming), quality selectors, and analytics hooks.

<!-- Video.js player with HLS -->
<link href="https://vjs.zencdn.net/8.10.0/video-js.css" rel="stylesheet">

<video id="live-stream" class="video-js vjs-big-play-centered"
  controls autoplay muted preload="auto"
  style="width:100%; max-width:1280px;">
  <source src="https://stream.thinksmart.life/hls/live.m3u8"
    type="application/x-mpegURL">
</video>

<script src="https://vjs.zencdn.net/8.10.0/video.min.js"></script>
<script>
  const player = videojs('live-stream', {
    liveui: true,
    html5: {
      vhs: { overrideNative: true }
    }
  });
</script>

WebRTC Embedding (LiveKit)

If you're using LiveKit for sub-second latency, you embed using their JavaScript SDK:

<!-- LiveKit WebRTC viewer -->
<div id="stream-container" style="width:100%; aspect-ratio:16/9; background:#000;"></div>

<script src="https://unpkg.com/livekit-client/dist/livekit-client.umd.js"></script>
<script>
  const room = new LivekitClient.Room();

  room.on(LivekitClient.RoomEvent.TrackSubscribed, (track, pub, participant) => {
    const element = track.attach();
    document.getElementById('stream-container').appendChild(element);
    element.style.width = '100%';
  });

  // Connect with a viewer token (generated server-side)
  room.connect('wss://stream.thinksmart.life', viewerToken);
</script>

6. Authentication & Access Control

You probably don't want your stream publicly accessible. Here are ways to restrict access:

Stream Key (Publish Auth)

Every streaming server supports stream keys โ€” a secret string that OBS must include to publish. This prevents unauthorized people from streaming to your server. Owncast, MediaMTX, nginx-rtmp, and SRS all support this out of the box.

Token-Based Viewer Auth

The most flexible approach: your website's backend generates a signed JWT or short-lived token. The player includes this token when requesting the HLS manifest. Your server or CDN validates it.

# Nginx config โ€” validate viewer token before serving HLS
location /hls {
    # Validate token via subrequest to your auth backend
    auth_request /auth/validate;
    auth_request_set $auth_status $upstream_status;

    types {
        application/vnd.apple.mpegurl m3u8;
        video/mp2t ts;
    }
    root /var/www;
    add_header Cache-Control no-cache;
}

location = /auth/validate {
    internal;
    proxy_pass http://localhost:3000/api/stream/validate;
    proxy_set_header X-Token $arg_token;
    proxy_pass_request_body off;
    proxy_set_header Content-Length "";
}

CloudFront Signed URLs/Cookies

If you're using CloudFront to distribute HLS, you can use signed URLs or signed cookies to restrict access. Your backend generates a signed URL with an expiration time; only requests with valid signatures can access the stream.

IP Whitelist

Simplest approach โ€” only allow specific IPs to access the stream. Works for internal/team use but breaks for dynamic IPs and mobile users.

Password-Protected Page

Wrap your stream page behind your site's existing authentication (Cognito, Auth0, basic auth, etc.). The stream URL itself can be unprotected if it's on an internal port or private subnet โ€” only authenticated page visitors see the embedded player.

7. AWS-Based Options

Since you're already on AWS, here are the managed and hybrid approaches:

Self-Hosted on EC2 + CloudFront

Run Owncast or MediaMTX on an EC2 instance. Configure it to push HLS segments to S3. Put CloudFront in front of S3 for global CDN delivery. This is the best hybrid approach โ€” you control the streaming server but offload delivery to AWS infrastructure.

# Architecture:
# OBS โ†’ EC2 (Owncast/MediaMTX) โ†’ S3 bucket โ†’ CloudFront โ†’ Viewers
#
# Estimated cost for 10 concurrent viewers, 4h/week:
# - EC2 t3.small: ~$15/month
# - S3 storage: ~$1/month (HLS segments are ephemeral)
# - CloudFront: ~$2/month (minimal at low viewership)
# Total: ~$18/month

AWS MediaLive + MediaPackage

AWS's fully managed live streaming pipeline. MediaLive encodes your input, MediaPackage packages it for delivery (HLS, DASH, CMAF), and CloudFront distributes it. Professional-grade but expensive โ€” $0.75โ€“$3.00/hour just for encoding, plus packaging and delivery costs. Overkill for personal streaming.

Amazon IVS (Interactive Video Service)

AWS's managed Twitch-like service. Send RTMP from OBS, get an embeddable low-latency player. Includes chat, timed metadata, and recording. Pricing is per-hour of live video input (~$2.00/hour for SD, $4.80/hour for HD) plus output per viewer-hour. Simpler than MediaLive but still expensive for personal use.

โš ๏ธ AWS Managed Streaming Is Expensive For a personal desktop stream with <50 viewers, AWS managed services (MediaLive, IVS) will cost $100โ€“500+/month. A $5โ€“15/month VPS running Owncast or MediaMTX does the same job. Use AWS managed services only when you need guaranteed SLAs, massive scale, or enterprise compliance.

The Smart AWS Setup

The cost-effective AWS approach for your use case:

# 1. Run streaming server on EC2
# Use a t3.small or t3.medium instance
# Install Owncast or MediaMTX

# 2. Configure S3 offloading (Owncast example)
# In Owncast admin โ†’ Settings โ†’ Storage:
#   Provider: AWS S3
#   Bucket: your-stream-bucket
#   Region: us-east-1
#   Access Key / Secret: (your IAM credentials)

# 3. Create CloudFront distribution pointing to the S3 bucket
# Origin: your-stream-bucket.s3.amazonaws.com
# Cache behavior: Short TTL (2-4 seconds for live HLS)
# Restrict viewer access: CloudFront signed cookies

# 4. Point your player to CloudFront URL
# https://d1234567.cloudfront.net/hls/live.m3u8

8. Docker Deployment โ€” Quick Start Commands

Every server mentioned here runs in Docker. Here's your copy-paste reference:

Owncast

# Owncast โ€” complete streaming + chat platform
docker run -d --name owncast \
  -p 8080:8080 -p 1935:1935 \
  -v owncast-data:/app/data \
  --restart unless-stopped \
  owncast/owncast:latest

# Admin: http://localhost:8080/admin (default password: abc123)
# Stream to: rtmp://localhost:1935/live
# Watch at: http://localhost:8080

MediaMTX

# MediaMTX โ€” multi-protocol media server
docker run -d --name mediamtx \
  -p 8554:8554 -p 1935:1935 \
  -p 8888:8888 -p 8889:8889 \
  -p 8890:8890/udp \
  --restart unless-stopped \
  bluenviron/mediamtx:latest

# Stream to: rtmp://localhost:1935/mystream
# Watch HLS: http://localhost:8888/mystream
# Watch WebRTC: http://localhost:8889/mystream

SRS

# SRS โ€” high-performance streaming server
docker run -d --name srs \
  -p 1935:1935 -p 1985:1985 \
  -p 8080:8080 -p 8000:8000/udp \
  --restart unless-stopped \
  ossrs/srs:5

# Stream to: rtmp://localhost:1935/live/stream
# Watch HLS: http://localhost:8080/live/stream.m3u8
# Watch WebRTC: http://localhost:1985 (API)
# Console: http://localhost:1985/console

LiveKit

# LiveKit โ€” WebRTC streaming platform
docker run -d --name livekit \
  -p 7880:7880 -p 7881:7881 \
  -p 7882:7882/udp \
  -e LIVEKIT_KEYS="devkey: secret" \
  --restart unless-stopped \
  livekit/livekit-server

# Dashboard: Install livekit-cli for token management
# npm install -g livekit-cli

Nginx + RTMP

# Nginx RTMP โ€” minimal streaming
docker run -d --name nginx-rtmp \
  -p 1935:1935 -p 8080:8080 \
  --restart unless-stopped \
  tiangolo/nginx-rtmp

# Stream to: rtmp://localhost:1935/live/stream
# Watch HLS: http://localhost:8080/hls/stream.m3u8

9. Latency Comparison

Latency is the delay between something happening on your desktop and a viewer seeing it. This matters more for some use cases than others:

Delivery Method Typical Latency Use Case Server Options
WebRTC <1 second Interactive (live coding, Q&A, pair programming) LiveKit, MediaMTX, Janus, SRS
Low-Latency HLS 2โ€“5 seconds Near-real-time viewing with broad compatibility Owncast (tuned), SRS, MediaMTX
Standard HLS 10โ€“30 seconds Presentations, demos, one-way broadcast All servers
RTMP (direct) 1โ€“5 seconds Server-to-server relay (not browser playback) Nginx-RTMP, SRS, MediaMTX
๐Ÿ’ก The Latency Tradeoff Lower latency = more server resources, fewer simultaneous viewers, more complex setup. For most desktop streaming scenarios (demos, presentations, casual sharing), standard HLS with 10โ€“15 seconds of delay is perfectly fine. Only go to WebRTC if viewers need to interact in real-time with what's on your screen.

Tuning HLS Latency

You can reduce standard HLS latency from 30 seconds down to 5โ€“8 seconds with these nginx-rtmp settings:

# nginx.conf โ€” low-latency HLS tuning
application live {
    live on;
    hls on;
    hls_path /var/www/hls;

    # Shorter fragments = lower latency (but less resilient)
    hls_fragment 2;        # 2-second segments (default is 5)
    hls_playlist_length 10; # Keep 10 seconds in playlist (default 30)

    # For very low latency, consider 1-second fragments:
    # hls_fragment 1;
    # hls_playlist_length 6;
}

# Player-side (hls.js):
# Set liveSyncDurationCount: 2 and liveMaxLatencyDurationCount: 5
# to stay close to the live edge

10. Practical Recommendation for ThinkSmart.Life

Given the requirements โ€” stream desktop to thinksmart.life, existing AWS infrastructure, small audience, minimal setup effort โ€” here's the recommended path:

๐Ÿ† Fastest Path: Owncast on EC2

  1. Launch a t3.small EC2 instance (~$15/month) in your existing VPC
  2. Install Owncast via Docker โ€” one command, streaming in 30 seconds
  3. Configure OBS to stream to rtmp://stream.thinksmart.life:1935/live
  4. Embed on your site using HLS.js pointing to Owncast's HLS output
  5. Optional: S3 + CloudFront offloading if you want CDN delivery
  6. Optional: Put behind Cognito auth for restricted access

Total time to first stream: ~30 minutes. Total cost: ~$15โ€“20/month.

๐Ÿš€ If You Want Low Latency: MediaMTX

If sub-5-second latency matters (interactive demos, live coding), use MediaMTX instead of Owncast. Same EC2 setup but you get WebRTC output. You lose the built-in chat and web UI but gain protocol flexibility and much lower latency.

๐Ÿ”ฎ Future-Proof: LiveKit

If you plan to do interactive sessions (pair programming, live Q&A), LiveKit gives you sub-second latency, screen sharing without OBS, and excellent SDKs. It's more complex to set up but the most capable option for real-time use cases.

โœ… The TL;DR Start with Owncast. It's the fastest path from zero to streaming on your own site. One Docker command, point OBS at it, embed the player. If you outgrow it or need lower latency, migrate to MediaMTX (WebRTC) or LiveKit (full real-time platform). All three run on the same EC2 instance.
๐Ÿ›ก๏ธ No Third-Party Tracking