Viibestream is a self-hosted live streaming platform that runs entirely in the browser. Broadcast from your camera and mic — or share a video file — and viewers watch instantly over a WebSocket, with no plugins, native apps, or third-party services in the loop. You own the server, the stream, and the data.
Features
- Browser broadcasting from camera + mic, or share a video file straight from the browser
- Public viewer page with autoplay, mute/unmute, volume, fullscreen and a live viewer count
- "Now Showing" panel — title, description, IMDB link and poster, updated live for viewers
- Real-time chat with custom names and emoji avatars, replies, @-mentions and emoji reactions
- Voice talk-back — viewers can be heard via voice-activity detection, with multi-speaker mixing
- Moderation — per-person mute, "mute all", participant roster with speaking indicators, and IP bans
- Role-based access — admin / streamer / viewer, with a login-gated admin dashboard
- Hardened by default — bcrypt passwords, CSRF on every form, per-request CSP nonces, session hardening, login rate limiting and account lockout, optional Cloudflare Turnstile
Requirements
- Docker Engine 20.10+ and the Docker Compose v2 plugin
- A modern browser for broadcasting (camera/mic needs HTTPS or localhost)
Install with Docker Compose
Create docker-compose.yml using the published image:
services:
viibestream:
image: hyprlab/viibestream:latest
container_name: viibestream
restart: unless-stopped
env_file:
- .env
environment:
- FLASK_ENV=production
ports:
- "0.0.0.0:${PORT:-8080}:${INTERNAL_PORT:-8000}"
volumes:
- viibestream_data:/app/instance
security_opt:
- no-new-privileges:true
tmpfs:
- /tmp
cap_drop:
- ALL
cap_add:
- CHOWN
- SETGID
- SETUID
volumes:
viibestream_data:
Grab the example env file and generate a secret key:
curl -fsSL https://raw.githubusercontent.com/hyprlab/viibestream/main/.env.example -o .env
python3 -c "import secrets; print(secrets.token_urlsafe(64))"
Set the essentials in .env, then launch:
SECRET_KEY=<paste-long-random-string>
INITIAL_ADMIN_USERNAME=admin
INITIAL_ADMIN_PASSWORD=<strong-one-time-password>
PUBLIC_ORIGIN=https://stream.example.com
docker compose pull
docker compose up -d
Open the public viewer at http://localhost:8080, sign in at /auth/login, change your password, then go live at /admin/stream. To build from source, clone the repo and run docker compose up --build -d.
Configuration
| Variable | Default | Purpose |
|---|---|---|
SECRET_KEY |
required | Signs session cookies and CSRF tokens |
INITIAL_ADMIN_PASSWORD |
— | One-time bootstrap password; blank it after first sign-in |
PUBLIC_ORIGIN |
http://localhost:8080 |
Allowed browser origin(s) for Socket.IO |
BEHIND_HTTPS_PROXY |
0 |
1 behind a TLS-terminating reverse proxy (recommended) |
TLS_ENABLE |
0 |
1 serves self-signed HTTPS on :8443 for LAN/demo |
PORT / INTERNAL_PORT |
8080 / 8000 |
Host port / container listen port |
Behind a reverse proxy, forward the WebSocket upgrade for /socket.io/* and send X-Forwarded-Proto: https.
Example .env
Copy this to .env next to your docker-compose.yml and adjust:
# Copy to .env and fill in. NEVER commit .env to git.
# Generate a strong key: python -c "import secrets; print(secrets.token_urlsafe(64))"
SECRET_KEY=change-me-generate-with-secrets-token_urlsafe-64
# Initial admin user, seeded only if no admin exists yet.
# Sign in once and change the password from the Settings modal.
INITIAL_ADMIN_USERNAME=admin
INITIAL_ADMIN_EMAIL=<your-email>
INITIAL_ADMIN_PASSWORD=change-me-on-first-login
# ── HTTPS strategy ─────────────────────────────────────────────────────
# Browsers refuse to expose navigator.mediaDevices.getUserMedia (camera
# and microphone) on any non-localhost HTTP origin. Pick ONE of the
# strategies below so broadcasters can capture media.
#
# Strategy A — Reverse proxy in front (recommended for real domains):
# You run Caddy / nginx / Cloudflare / etc. with a real cert. The
# proxy forwards to this container on plain HTTP. Set:
# BEHIND_HTTPS_PROXY=1
# TLS_ENABLE=0
# The proxy MUST forward:
# - WebSocket upgrade headers (Connection, Upgrade)
# - X-Forwarded-Proto: https
# - X-Forwarded-For: $remote_addr
# - Host: $host
#
# Strategy B — In-container self-signed TLS (LAN / quick demos):
# The container generates a self-signed cert at first boot and serves
# HTTPS itself on :8443. Browsers will warn once per device. Set:
# BEHIND_HTTPS_PROXY=0
# TLS_ENABLE=1
# TLS_HOSTS=localhost,127.0.0.1,10.0.1.14 # SANs on the cert
# PORT=8443
#
# Strategy C — HTTP only on localhost (single-machine dev):
# BEHIND_HTTPS_PROXY=0
# TLS_ENABLE=0
BEHIND_HTTPS_PROXY=0
TLS_ENABLE=0
TLS_HOSTS=localhost,127.0.0.1
# Every origin from which a browser might load the page, comma-separated.
# Socket.IO's CORS check rejects WebSocket handshakes whose Origin is
# not in this list. For a public domain, include the https:// version.
PUBLIC_ORIGIN=http://localhost:8080
# Host port → container. The container listens on :8000 (plain) or
# :8443 (TLS_ENABLE=1) internally; this is the port you'll publish.
PORT=8080
# SQLite path inside the container (instance volume).
DATABASE_URL=sqlite:////app/instance/viibestream.db
# ── Cloudflare Turnstile (optional login captcha) ──────────────────────
# Optional: these only SEED the initial config on first boot. After that,
# manage Turnstile from the admin UI: Settings → Security. Leave both blank
# to start disabled and configure it entirely from the interface.
TURNSTILE_SITE_KEY=
TURNSTILE_SECRET_KEY=
Updating
docker compose pull
docker compose up -d
The SQLite database lives in the viibestream_data volume and survives restarts and rebuilds (only docker compose down -v deletes it).
AI notice
Viibestream is built by a human maintainer working with generative AI as a development tool:
- Code — the large majority of the code in the repository was written with Anthropic's Claude (via Claude Code), working from the maintainer's direction. The maintainer decides what gets built, reviews the results, tests every release, and signs off on everything that ships.
- Text — documentation, release notes, and in-app copy are largely AI-drafted and human-edited.
- The app itself contains no AI. Viibestream has no AI features and makes no requests to AI services — AI was used to build it, not to run it.
Bug reports and pull requests are welcome from humans and their AI tools alike; everything merged gets the same human review.
Tech stack & license
Flask 3 · Flask-SocketIO · SQLAlchemy/SQLite · vanilla JS (MediaRecorder / MediaSource) · Gunicorn · Docker. Free and open source under the GNU AGPL-3.0. Full docs and releases on GitHub.