Skip to main content

Configuration Reference

StreamGate is configured through environment variables. Both services read from .env files in their respective directories, with a root-level .env file providing shared defaults.

File Locations

FileScope
.env (project root)Shared defaults for both services
platform/.envPlatform App overrides
hls-server/.envHLS Media Server overrides

Service-specific .env files take precedence over the root file.


Shared Variables

These variables must match between the Platform App and HLS Media Server.

VariableRequiredDefaultDescription
PLAYBACK_SIGNING_SECRETHMAC-SHA256 secret for signing and verifying JWT playback tokens. Must be at least 32 characters. Must be identical on both services.
INTERNAL_API_KEYAPI key used by the HLS server when polling the Platform App's /api/revocations endpoint. Sent as X-Internal-Api-Key header. Must be identical on both services.

Generating Shared Secrets

# PLAYBACK_SIGNING_SECRET — base64-encoded random bytes
node -e "console.log(require('crypto').randomBytes(32).toString('base64'))"

# INTERNAL_API_KEY — hex-encoded random bytes
node -e "console.log(require('crypto').randomBytes(24).toString('hex'))"

:::danger Secret mismatch If PLAYBACK_SIGNING_SECRET differs between services, JWT validation will fail on every HLS request — viewers will see a loading spinner but no video. If INTERNAL_API_KEY differs, revocation sync will fail — revoked tokens will continue to work until their JWT expires (up to 60 minutes). :::


Platform App Variables

Set these in platform/.env or the root .env file.

VariableRequiredDefaultDescription
DATABASE_URLfile:./dev.dbDatabase connection string. SQLite for development (file:./dev.db), PostgreSQL for production (postgresql://user:pass@host:5432/dbname).
ADMIN_PASSWORD_HASHbcrypt hash of the admin console password. Generate with npm run hash-password.
HLS_SERVER_BASE_URLhttp://localhost:4000Base URL of the HLS Media Server. In development, the actual URL sent to browsers is dynamically derived from the request's hostname (preserving the HLS server port), so LAN clients automatically get a reachable address. In production, set this to the public URL viewers will use.
NEXT_PUBLIC_APP_NAMEStreamGateApplication name displayed in the UI. The NEXT_PUBLIC_ prefix makes it available in the browser.
SESSION_TIMEOUT_SECONDS60Seconds of missed heartbeats before a viewing session is considered abandoned and automatically released. Lower values free up tokens faster; higher values tolerate more network instability.

Database URL Examples

# SQLite (development)
DATABASE_URL=file:./dev.db

# PostgreSQL (production)
DATABASE_URL=postgresql://streamgate:password@localhost:5432/streamgate

# PostgreSQL with SSL (cloud)
DATABASE_URL=postgresql://user:pass@host:5432/db?sslmode=require

Admin Password

Generate the bcrypt hash interactively:

npm run hash-password
# Enter your desired password when prompted
# Copy the output hash to ADMIN_PASSWORD_HASH

:::tip Password strength Use a strong password (12+ characters, mixed case, numbers, symbols) for production deployments. The bcrypt hash uses 12 salt rounds by default. :::


HLS Media Server Variables

Set these in hls-server/.env or the root .env file.

VariableRequiredDefaultDescription
PLATFORM_APP_URLhttp://localhost:3000Internal URL of the Platform App. Used for revocation polling (GET /api/revocations). In Docker, use the container name (e.g., http://platform:3000).
STREAM_ROOTConditional./streamsLocal filesystem path where HLS stream files are stored. Required for local or hybrid mode.
UPSTREAM_ORIGINConditionalBase URL of an upstream HLS origin server. Required for proxy or hybrid mode.
SEGMENT_CACHE_ROOTSTREAM_ROOT/cache/Directory for caching segments fetched from the upstream origin. Only used in proxy/hybrid mode.
SEGMENT_CACHE_MAX_SIZE_GB50Maximum cache size in GB. When exceeded, least-recently-used segments are evicted.
SEGMENT_CACHE_MAX_AGE_HOURS72Maximum age of cached segments in hours. Segments older than this are automatically cleaned up.
REVOCATION_POLL_INTERVAL_MS30000How often (in milliseconds) to poll the Platform App for revocation updates. Lower values = faster revocation at the cost of more API calls.
CORS_ALLOWED_ORIGINhttp://localhost:3000Origin(s) allowed to make cross-origin requests to the HLS server. Must match the Platform App's public URL. Supports comma-separated values for multiple origins (e.g., http://localhost:3000,http://192.168.0.11:3000).
PORT4000Port the HLS server listens on.

Content Source Modes

The HLS server supports three modes for sourcing stream content, determined by which environment variables are set:

ModeSTREAM_ROOTUPSTREAM_ORIGINBehavior
Local✅ Set❌ EmptyServes files directly from the local filesystem
Proxy❌ Empty✅ SetFetches content from upstream origin, caches locally
Hybrid✅ Set✅ SetChecks local filesystem first, falls back to upstream

Local Mode

Best for: Single-server setups, development, and direct FFmpeg ingest.

STREAM_ROOT=./streams
UPSTREAM_ORIGIN=

The server maps requests like GET /streams/:eventId/stream.m3u8 to the local file STREAM_ROOT/:eventId/stream.m3u8.

Proxy Mode

Best for: Edge deployments where content lives on a central origin server or CDN.

STREAM_ROOT=
UPSTREAM_ORIGIN=https://origin.example.com/hls

The server fetches content from https://origin.example.com/hls/:eventId/stream.m3u8 and caches segments locally for rewind/VOD rewatch.

Hybrid Mode

Best for: Environments where some events stream locally and others come from an upstream origin.

STREAM_ROOT=./streams
UPSTREAM_ORIGIN=https://origin.example.com/hls

For each request:

  1. Check STREAM_ROOT/:eventId/ — if the file exists locally, serve it
  2. If not found locally, fetch from UPSTREAM_ORIGIN/:eventId/
  3. Cache fetched segments to SEGMENT_CACHE_ROOT/:eventId/

Choosing a Mode

QuestionRecommended Mode
FFmpeg runs on the same machine as the HLS server?Local
Content is on a separate origin / CDN?Proxy
Mix of local and remote events?Hybrid
Need to cache upstream content for rewind?Proxy or Hybrid
Single-server development setup?Local

Example Configurations

Minimal Development

PLAYBACK_SIGNING_SECRET=my-dev-secret-at-least-32-characters-long
INTERNAL_API_KEY=dev-internal-api-key
ADMIN_PASSWORD_HASH=$2b$12$LJ3m4ys3Lk0TSwMBQWJJF.FzHqKn5A2n3MpGkbP0U7Q67rJFEyxGq
DATABASE_URL=file:./dev.db
HLS_SERVER_BASE_URL=http://localhost:4000
PLATFORM_APP_URL=http://localhost:3000
STREAM_ROOT=./streams
CORS_ALLOWED_ORIGIN=http://localhost:3000

LAN Development (access from other devices)

# Same as minimal, but allow LAN access:
CORS_ALLOWED_ORIGIN=http://localhost:3000,http://192.168.0.11:3000
# HLS_SERVER_BASE_URL remains localhost — the Platform App dynamically
# rewrites it based on the viewer's request origin.

:::tip LAN access in dev mode The next.config.mjs auto-detects LAN IPv4 addresses and adds them to allowedDevOrigins, so Next.js dev mode works from LAN IPs without additional configuration. You only need to update CORS_ALLOWED_ORIGIN to include your LAN origin so the HLS server accepts cross-origin requests. :::

Production (PostgreSQL + Proxy Mode)

PLAYBACK_SIGNING_SECRET=<strong-random-base64-key>
INTERNAL_API_KEY=<strong-random-hex-key>
ADMIN_PASSWORD_HASH=<bcrypt-hash>
DATABASE_URL=postgresql://streamgate:password@db.example.com:5432/streamgate
HLS_SERVER_BASE_URL=https://hls.example.com
NEXT_PUBLIC_APP_NAME=MyStreamingPlatform
SESSION_TIMEOUT_SECONDS=90
PLATFORM_APP_URL=https://app.example.com
UPSTREAM_ORIGIN=https://origin-cdn.example.com/hls
SEGMENT_CACHE_ROOT=/var/cache/streamgate
SEGMENT_CACHE_MAX_SIZE_GB=100
SEGMENT_CACHE_MAX_AGE_HOURS=168
REVOCATION_POLL_INTERVAL_MS=15000
CORS_ALLOWED_ORIGIN=https://app.example.com
PORT=4000

Docker Compose (defaults in docker-compose.yml)

The Docker Compose file includes pre-configured values for local development. Override them by setting values in the root .env file or by adding a docker-compose.override.yml.


Configuration Tips

:::tip Revocation speed vs. API load REVOCATION_POLL_INTERVAL_MS controls the trade-off between revocation speed and API load. At 30,000ms (default), a revoked token could work for up to 30 seconds. Set to 5,000ms for faster revocation (at the cost of 6x more polling requests). :::

:::warning CORS in production CORS_ALLOWED_ORIGIN must exactly match the URL(s) your viewers use to access the Platform App — including protocol, domain, and port. Mismatched CORS settings will cause the player to fail with network errors. For LAN/multi-origin setups, use comma-separated values. :::

:::info Public prefix Only variables prefixed with NEXT_PUBLIC_ are exposed to the browser. All other Platform App variables remain server-side only. :::