• JavaScript 96.3%
  • CSS 3.3%
  • Dockerfile 0.2%
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
Michelle 4df0fda4ef
All checks were successful
Build & Push Docker Image / build (push) Successful in 3m48s
chore(deps): update follow-redirects to version 1.16.2 and add hasInstallScript
2026-11-01 23:22:43 +01:00
.gitea/workflows ci: stop building images for the develop-calendar branch 2026-10-21 01:14:15 +02:00
public Harden server security, rework landing page and refresh branding 2026-06-11 10:14:36 +02:00
screenshots Add screenshots to README 2026-06-21 22:16:42 +02:00
server chore: bump version to 2.7.2 in package.json, package-lock.json and federation.js 2026-10-22 23:49:09 +02:00
src feat(rooms): option to only let signed-in users join 2026-10-21 01:13:07 +02:00
test feat(rooms): option to only let signed-in users join 2026-10-21 01:13:07 +02:00
.dockerignore Add screenshots to README 2026-06-21 22:16:42 +02:00
.env.example fix(security): route federation requests through an SSRF-safe client 2026-10-21 00:55:10 +02:00
.gitignore Harden server security, rework landing page and refresh branding 2026-06-11 10:14:36 +02:00
CLAUDE.md docs(CLAUDE.md): update stack note and CI triggers 2026-10-21 01:24:30 +02:00
compose.yml fix(security): publish the compose port on localhost only 2026-10-21 01:04:44 +02:00
docker-entrypoint.sh fix(security): run the Docker container as an unprivileged user 2026-10-21 01:04:25 +02:00
Dockerfile fix(security): run the Docker container as an unprivileged user 2026-10-21 01:04:25 +02:00
index.html Harden server security, rework landing page and refresh branding 2026-06-11 10:14:36 +02:00
LICENSE Update language, add LICENSE and README 2026-02-24 21:04:19 +01:00
migrate-from-greenlight.mjs feat(migrate): map glRequireAuthentication to require_signin 2026-10-21 01:17:51 +02:00
package-lock.json chore(deps): update follow-redirects to version 1.16.2 and add hasInstallScript 2026-11-01 23:22:43 +01:00
package.json chore: bump version to 2.7.2 in package.json, package-lock.json and federation.js 2026-10-22 23:49:09 +02:00
postcss.config.js refactor: update class names for consistency and improve styling 2026-05-18 13:07:26 +02:00
README.md docs: neutral Greenlight comparison and README corrections 2026-10-21 01:24:13 +02:00
vite.config.js Init v1.0.0 2026-02-24 18:14:16 +01:00

🔴 Redlight

⚠️ Warning: This project is entirely vibe coded and meant to be a fun/hobby project. Use at your own risk!

A modern, self-hosted BigBlueButton frontend with 24 themes, federation, calendar, CalDAV, OAuth/OIDC, and powerful room management.

Node.js React License BigBlueButton

🖼️ Pictures

Click to expand screenshots

Home Dashboard Rooms

✨ Features

Core Features

  • 🎥 Video Conferencing - Integrated BigBlueButton support for professional video meetings
  • 🎨 24 Themes - Dracula, Nord, Catppuccin, Rosé Pine, Gruvbox, Tokyo Night, Solarized, Everforest, Ayu, Kanagawa, Moonlight, Cyberpunk, Cotton Candy, and more
  • 📝 Room Management - Create unlimited rooms with custom settings, access codes, and moderator codes
  • 🔐 User Management - Registration, login, role-based access control (Admin/User)
  • 📹 Recording Management - View, publish, and delete meeting recordings per room
  • 📊 Learning Analytics - Collect and view per-room participant engagement data (talk time, messages, reactions) via BBB callbacks, secured with HMAC tokens
  • 📅 Calendar - Built-in calendar with event creation, sharing, customizable reminders, and room linking
  • 📆 CalDAV Server - Full CalDAV support for syncing calendars with Thunderbird, Apple Calendar, GNOME Calendar, DAVx⁵ (Android), and other standard clients
  • 🌍 Multi-Language Support - German (Deutsch) and English built-in, easily extensible
  • 🔔 In-App Notifications - Notifications for room shares, federation invites, and calendar reminders
  • ✉️ Email Verification - Optional SMTP-based email verification for user registration
  • 🔑 OAuth / OIDC - Login via OpenID Connect providers (Keycloak, Authentik, etc.) with PKCE, configured in the admin panel
  • 🔒 Two-Factor Authentication - Optional TOTP 2FA for local accounts
  • 👤 User Profiles - Customizable display names, avatars, themes, and language preferences
  • 📱 Responsive Design - Works seamlessly on mobile, tablet, and desktop
  • 🌐 Federation - Invite users from remote Redlight instances via Ed25519-signed messages
  • 🐉 DragonflyDB / Redis - JWT blacklisting for secure token revocation on logout

Admin Features

  • 👥 User Administration - Create and delete users, assign the admin/user role, reset passwords
  • 🏠 Room Overview - List of all rooms on the instance with their owners
  • 🏢 Branding Customization - Custom app name, logo, default theme, imprint and privacy links
  • 🔧 Settings Management - Registration mode and OpenID Connect configuration
  • ✉️ Invite-Only Registration - Generate invite tokens for controlled user signup

Room Features

  • 🔑 Access Codes - Restrict room access with optional passwords
  • 🔐 Moderator Codes - Separate code to grant moderator privileges
  • 🚪 Guest Access - Unauthenticated users can join via the room link (rate-limited)
  • 👤 Signed-In Users Only - Optionally close a room to guests entirely
  • ⏱️ Max Participants - Set limits on concurrent participants
  • 🎤 Mute on Join - Automatically mute new participants
  • ✅ Approval Mode - Guests and non-members wait in BBB's waiting room until a moderator admits them
  • 🎙️ Anyone Can Start - Allow participants to start the meeting
  • 📹 Recording Settings - Control whether meetings are recorded
  • 📊 Learning Analytics - Toggle per-room to collect participant engagement data after each meeting
  • 📑 Presentation Upload - Upload PDF, PPTX, ODP, DOC, DOCX as default slides
  • 🤝 Room Sharing - Share rooms with other registered users

Security

  • 🛡️ Comprehensive Rate Limiting - Login, register, profile, avatar, guest-join, OAuth, and federation endpoints
  • 🔒 Input Validation - Email format, field length limits, ID format checks, color format validation
  • 🕐 Timing-Safe Comparisons - Access codes and moderator codes compared with crypto.timingSafeEqual
  • 📏 Streaming Upload Limits - Avatar (2 MB) and presentation (50 MB) uploads reject early without buffering
  • 🧹 XSS Prevention - HTML-escaped emails, XML-escaped BBB parameters, uploaded SVG logos served as downloads, Content-Security-Policy
  • 🔐 JWT Blacklist - Token revocation via DragonflyDB/Redis on logout
  • 🌐 SSRF-Safe Federation - Peer requests only reach public addresses, never follow redirects
  • 🌐 CORS Restriction - Locked to APP_URL in production
  • ⚙️ Configurable Trust Proxy - TRUST_PROXY env var for reverse proxy setups
  • 🔏 HMAC-Secured Callbacks - Learning analytics callback URLs signed with HMAC-SHA256

Developer Features

  • 🐳 Docker Support - Easy deployment with Docker Compose (includes PostgreSQL + DragonflyDB)
  • 🗄️ Database Flexibility - SQLite (default) or PostgreSQL support
  • 🔌 JSON API - The API behind the web app (JWT bearer auth), listed below
  • 📦 Open Source - Full source code transparency
  • 🛠️ Self-Hosted - Complete data privacy and control

📊 Comparison: Redlight vs Greenlight v3

The Greenlight column reflects Greenlight v3 (release 3.9, checked October 2026). Corrections welcome.

Feature Redlight Greenlight v3
Frontend React 19, Tailwind CSS 4, Vite React 17, React-Bootstrap (Bootstrap 5), esbuild
Backend Node.js, Express 5 Ruby on Rails 7.2 (JSON API)
Database SQLite (default) or PostgreSQL PostgreSQL
Redis Optional (logout token blacklist, rate limits) Required in production
Deployment Docker Compose; reverse proxy/TLS set up manually Docker Compose; official install scripts incl. nginx + Let's Encrypt
UI languages 2 (English, German) 25 (community translations)
Look & feel 24 built-in themes, selectable per user; admin sets the default Admin-defined brand colour and logo
Login Local accounts, OpenID Connect (PKCE), built-in TOTP 2FA Local accounts, OpenID Connect; no built-in 2FA
Registration modes Open, invite-only Open, invite-only, admin approval; allowed email domains
Roles & permissions Fixed: admin / user Custom roles with configurable permissions (e.g. room limit, recording, sharing)
Room settings Access code, moderator code, mute on join, guest approval (waiting room), signed-in users only, anyone can start, all join as moderator, max participants, welcome message, recording Viewer/moderator access codes, mute on start, guest approval, require sign-in, anyone can start, all join as moderator, recording; admins can enforce or hide each option
Room sharing ✅ ✅ (can be disabled by admins)
Presentation upload ✅ PDF, PPT/PPTX, ODP, DOC/DOCX (50 MB) ✅ Office, OpenDocument, PDF, images (30 MB); optional ClamAV scan
Recordings List, publish/unpublish, delete (per room) Rename, delete, five visibility levels incl. protected/public, public recordings list on room page, admin overview
Learning analytics ✅ Stored per room, export as CSV/XLSX/PDF ❌ (BBB's in-meeting Learning Dashboard is available with both)
Calendar / CalDAV ✅ Built-in calendar, CalDAV server, ICS export ❌
Federation ✅ Room and calendar invites between Redlight instances ❌
Notifications In-app (room shares, invites, calendar reminders) + email Email (invitations, sign-up approvals)
Admin panel Users, invites, rooms, branding, registration mode, OIDC Users (incl. pending/banned), roles, server rooms, server recordings, room configuration, site settings, tenants
Multi-tenancy / Scalelite tags ❌ ✅
File storage Local disk Local disk, S3, Google Cloud Storage
License GPL-3.0-or-later LGPL-3.0

Coming from Greenlight? migrate-from-greenlight.mjs imports users (incl. SSO users), rooms with their settings, shares and selected site settings from a Greenlight v3 database. Uploaded files (presentations, avatars, custom logo) and recording visibility are not migrated; see the header of the script for details.


🚀 Quick Start

Prerequisites

  • Docker & Docker Compose
  • BigBlueButton server (with API access)
  • SMTP server (optional, for email verification)

Installation

  1. Clone the repository

    git clone https://git.scrunkly.cat/Michelle/redlight
    cd redlight
    
  2. Configure environment

    cp .env.example .env
    

    Edit .env with your settings:

    BBB_URL=https://your-bbb-server.com/bigbluebutton/api/
    BBB_SECRET=your-bbb-shared-secret
    JWT_SECRET=your-secret-key          # REQUIRED - app won't start without this
    APP_URL=https://your-domain.com     # REQUIRED in production - used for CORS and email links
    ADMIN_PASSWORD=choose-a-strong-one  # REQUIRED on first start - initial admin password
    DATABASE_URL=postgres://redlight:redlight@postgres:5432/redlight
    
    POSTGRES_USER=redlight
    POSTGRES_PASSWORD=redlight
    POSTGRES_DB=redlight
    
    # DragonflyDB / Redis (JWT blacklist for logout)
    REDIS_URL=redis://dragonfly:6379
    
    # Reverse proxy trust (default: loopback)
    # TRUST_PROXY=loopback
    
    # Optional: Email verification
    # SMTP_HOST=smtp.gmail.com
    # SMTP_PORT=587
    # SMTP_USER=your-email@gmail.com
    # SMTP_PASS=your-app-password
    
    # Optional: Federation (cross-instance room invites)
    # FEDERATION_DOMAIN=your-domain.com
    

    OAuth / OpenID Connect is not configured via .env: set the issuer, client ID and secret in the admin panel after the first login.

  3. Start the application

    docker compose up -d
    
  4. Access the application

    • Open http://localhost:3001 in your browser
    • Log in as admin@example.com (or your ADMIN_EMAIL) with the ADMIN_PASSWORD you set

🛠️ Development

Local Setup

  1. Install dependencies

    npm install
    
  2. Start development server

    npm run dev
    
  3. Run the tests

    npm test
    
  4. Build for production

    npm run build
    npm start
    

Tech Stack

  • Frontend: React 19, Tailwind CSS 4, React Router 7, Lucide Icons
  • Backend: Node.js 22, Express 5, JWT, bcryptjs
  • Database: SQLite / PostgreSQL with better-sqlite3 / pg
  • Cache: DragonflyDB / Redis (ioredis) - JWT blacklisting
  • Email: Nodemailer
  • CalDAV: xml2js-based WebDAV/CalDAV server
  • Auth: JWT + OAuth/OIDC (PKCE)
  • Build: Vite

📁 Project Structure

redlight/
├── server/                 # Node.js/Express backend
│   ├── config/            # Database, Redis, mailer, BBB, federation, OAuth & notification config
│   ├── i18n/              # Server-side translations (email templates)
│   ├── jobs/              # Background jobs (federation sync, calendar reminders)
│   ├── middleware/        # JWT authentication, logging & token blacklisting
│   ├── routes/            # API endpoints (auth, rooms, recordings, admin, branding,
│   │                      #   federation, calendar, caldav, notifications, oauth, analytics)
│   └── index.js           # Server entry point
├── src/                   # React frontend
│   ├── components/        # Reusable components (RecordingList, AnalyticsList, etc.)
│   ├── contexts/          # React context (Auth, Language, Theme, Branding, Notification)
│   ├── i18n/              # Translations (DE, EN)
│   ├── pages/             # Page components
│   ├── services/          # API client
│   ├── themes/            # 24 theme definitions
│   └── main.jsx           # Frontend entry point
├── public/                # Static assets
├── uploads/               # User avatars, branding & presentations (runtime)
├── keys/                  # Federation Ed25519 key pair (auto-generated)
├── compose.yml            # Docker Compose (Redlight + PostgreSQL + DragonflyDB)
├── Dockerfile             # Multi-stage container image
└── package.json           # Dependencies

🔐 Security

  • JWT Authentication - Secure token-based auth with 7-day expiration and jti-based blacklisting via DragonflyDB/Redis; password changes and resets revoke all sessions and CalDAV tokens
  • Mandatory Secrets - Server refuses to start without JWT_SECRET, and in production without APP_URL and BBB_SECRET
  • OAuth / OIDC - OpenID Connect with PKCE (S256) and single-use state tokens bound to the browser
  • Two-Factor Authentication - TOTP with per-account attempt limits and replay protection
  • HTTPS Ready - Configure behind reverse proxy (nginx, Caddy); trust proxy via TRUST_PROXY env
  • Password Hashing - bcryptjs with salt rounds 12, minimum 8-character passwords
  • Email Verification - Optional SMTP-based email verification with resend support
  • CORS Protection - Restricted to APP_URL in production, open in development
  • Rate Limiting - Login, register, profile, password, avatar, guest-join, OAuth, and federation endpoints
  • Input Validation - Email regex, field length limits, ID format checks, hex-color format checks
  • Timing-Safe Comparisons - Access codes and moderator codes compared via crypto.timingSafeEqual
  • Upload Safety - Streaming body size limits (avatar 2 MB, presentation 50 MB) abort early without buffering; file types are checked by content
  • XSS / Injection Prevention - HTML-escaped emails, XML-escaped BBB API parameters, SVG logos served as attachment, escaped ICS/CalDAV output, Content-Security-Policy
  • HMAC-Secured Callbacks - Learning analytics callback URLs signed with HMAC-SHA256 derived from BBB_SECRET
  • Federation Hardening - Ed25519-signed payloads; outbound requests are SSRF-guarded (public addresses only, connection pinned to the checked IP, no redirects); optional domain allowlist
  • Log Hygiene - Tokens and codes in request URLs are redacted from the access log
  • Admin Isolation - Role-based access control with strict admin checks
  • Container Hardening - The Docker image runs as an unprivileged user; Docker Compose publishes the app on localhost only and uses an internal backend network for DB and cache

📦 API Endpoints

All routes are under /api and use Authorization: Bearer <jwt> unless noted. The API is the one the SPA uses; it is not versioned.

Authentication

  • POST /api/auth/register - Register (invite token required in invite-only mode)
  • GET /api/auth/verify-email?token=... - Verify email with token
  • POST /api/auth/resend-verification - Resend verification email
  • POST /api/auth/forgot-password / POST /api/auth/reset-password - Password reset by email
  • POST /api/auth/login - Login (returns a 2FA step token if 2FA is enabled)
  • POST /api/auth/login/2fa - Complete login with a TOTP code
  • POST /api/auth/logout - Logout (blacklists the JWT)
  • GET /api/auth/me - Current user
  • PUT /api/auth/profile - Update username, display name, email, theme, language, avatar colour
  • PUT /api/auth/password - Change password
  • POST /api/auth/avatar / DELETE /api/auth/avatar - Upload / remove avatar
  • GET /api/auth/2fa/status, POST /api/auth/2fa/setup, POST /api/auth/2fa/enable, POST /api/auth/2fa/disable - Manage TOTP 2FA

Rooms

  • GET /api/rooms / POST /api/rooms - List own and shared rooms / create a room
  • GET /api/rooms/:uid / PUT /api/rooms/:uid / DELETE /api/rooms/:uid - Room details / update / delete
  • GET /api/rooms/users/search?q=... - Search users to share a room with
  • GET /api/rooms/:uid/public - Public room info for the guest page (no auth)
  • POST /api/rooms/:uid/start - Start meeting
  • POST /api/rooms/:uid/join - Join meeting as signed-in user
  • POST /api/rooms/:uid/guest-join - Join as guest (no auth, rate-limited; uses the account if signed in)
  • POST /api/rooms/:uid/end - End meeting
  • GET /api/rooms/:uid/status - Is the meeting running (no auth)
  • GET /api/rooms/:uid/shares, POST /api/rooms/:uid/shares, DELETE /api/rooms/:uid/shares/:userId - Room sharing
  • POST /api/rooms/:uid/presentation / DELETE /api/rooms/:uid/presentation - Default presentation
  • POST /api/rooms/invite-email - Email invitations to guests

Recordings

  • GET /api/recordings/room/:uid - List room recordings (GET /api/recordings?meetingID=... also works)
  • PUT /api/recordings/:recordID/publish - Publish / unpublish
  • DELETE /api/recordings/:recordID - Delete
  • POST /api/recordings/recording-ready - BBB recording-ready callback (signed by BBB)

Learning Analytics

  • POST /api/analytics/callback/:uid?token=... - BBB callback (HMAC-secured)
  • GET /api/analytics/room/:uid - Analytics of a room
  • GET /api/analytics/:id/export/:format - Export as csv, xlsx or pdf
  • DELETE /api/analytics/:id - Delete an entry

Calendar

  • GET /api/calendar/events / POST /api/calendar/events - List / create events
  • GET /api/calendar/events/:id, PUT /api/calendar/events/:id, DELETE /api/calendar/events/:id - Event details / update / delete
  • GET /api/calendar/events/:id/ics - Download as ICS
  • POST /api/calendar/events/:id/share, DELETE /api/calendar/events/:id/share/:userId - Invite / remove local users
  • POST /api/calendar/events/:id/email - Email invitation with ICS attachment
  • POST /api/calendar/events/:id/federation - Send to a user on another Redlight instance
  • GET /api/calendar/local-invitations, POST /api/calendar/local-invitations/:id/accept, DELETE /api/calendar/local-invitations/:id - Invitations from local users
  • GET /api/calendar/caldav-tokens, POST /api/calendar/caldav-tokens, DELETE /api/calendar/caldav-tokens/:id - CalDAV tokens

Notifications

  • GET /api/notifications - List notifications
  • POST /api/notifications/:id/read / POST /api/notifications/read-all - Mark as read
  • DELETE /api/notifications/:id / DELETE /api/notifications/all - Delete

Admin

  • GET /api/admin/users / POST /api/admin/users - List / create users
  • PUT /api/admin/users/:id/role - Change role
  • PUT /api/admin/users/:id/password - Reset password
  • DELETE /api/admin/users/:id - Delete user
  • GET /api/admin/invites, POST /api/admin/invites, DELETE /api/admin/invites/:id - Registration invites
  • GET /api/admin/rooms - All rooms with owners
  • GET /api/admin/oauth, PUT /api/admin/oauth, DELETE /api/admin/oauth - OpenID Connect configuration

Branding

  • GET /api/branding - Branding settings (public)
  • GET /api/branding/logo - Logo (public); POST / DELETE to upload or remove it (admin)
  • PUT /api/branding/name, /default-theme, /registration-mode, /imprint-url, /privacy-url, /hide-app-name - Update settings (admin)

OAuth

  • GET /api/oauth/providers - Configured provider (public)
  • GET /api/oauth/authorize?return_to=/path - Start the OIDC flow (redirects to the provider)
  • GET /api/oauth/callback - Provider callback (PKCE code exchange)

Federation

  • GET /.well-known/redlight - Instance discovery (domain, public key)
  • POST /api/federation/invite - Invite a remote user to a room
  • GET /api/federation/invitations, GET /api/federation/invitations/pending-count - Received room invitations
  • POST /api/federation/invitations/:id/accept, DELETE /api/federation/invitations/:id - Accept / decline
  • GET /api/federation/calendar-invitations, POST .../:id/accept, DELETE .../:id - Received calendar invitations
  • GET /api/federation/federated-rooms, DELETE /api/federation/federated-rooms/:id - Accepted remote rooms
  • POST /api/federation/receive, /calendar-event, /room-sync, /room-deleted, /calendar-event-deleted - Instance-to-instance calls (Ed25519-signed, rate-limited)

CalDAV

Basic auth with email:caldav-token; clients can discover the server via /.well-known/caldav.

  • PROPFIND /caldav/ - CalDAV discovery
  • PROPFIND / REPORT /caldav/:user/calendar/ - Calendar metadata and queries
  • GET / PUT / DELETE /caldav/:user/calendar/:uid.ics - Event CRUD

🌍 Internationalization (i18n)

Redlight comes with built-in support for multiple languages. Currently supported:

  • 🇩🇪 Deutsch (German)
  • 🇬🇧 English

Adding a new language

  1. Create src/i18n/xx.json (e.g., fr.json for French)
  2. Copy structure from de.json or en.json
  3. Translate all strings
  4. Update src/i18n/index.js to include the new language

🎨 Themes

Redlight includes 24 themes:

  • ☀️ Light / 🌙 Dark (default)
  • 🐱 Catppuccin Mocha / Latte
  • 🧛 Dracula
  • ❄️ Nord
  • 🌊 Tokyo Night
  • 💜 One Dark
  • 🐙 GitHub Dark
  • 🌹 Rosé Pine / Rosé Pine Dawn
  • 🍂 Gruvbox Dark / Gruvbox Light
  • ☀️ Solarized Dark / Solarized Light
  • 🌲 Everforest Dark / Everforest Light
  • 🌊 Kanagawa
  • 🌙 Moonlight
  • 🎮 Cyberpunk
  • 🌸 Ayu Dark
  • 🔴 Red Modular Light
  • 🍬 Cotton Candy Light
  • 🐱 scrunkly.cat Dark

Themes are fully customizable by editing src/themes/index.js.


🐳 Docker Deployment

docker compose up -d

Services:

  • redlight - Node.js application (port 3001, published on 127.0.0.1 only; put a TLS-terminating reverse proxy in front)
  • postgres - PostgreSQL 17 database
  • dragonfly - DragonflyDB (Redis-compatible) for JWT blacklisting and rate limits

The compose.yml uses isolated networks: frontend and backend (internal, no external access). PostgreSQL and DragonflyDB data live in named volumes (pgdata, dragonflydata); uploads and federation keys are bind-mounted from ./uploads and ./keys. The container runs as the unprivileged node user; on start it hands ownership of /app/uploads, /app/data and /app/keys to that user, so volumes from older releases keep working.

Environment Variables

Variable Required Default Description
BBB_URL Yes - BigBlueButton API URL (must end with /)
BBB_SECRET Yes - BigBlueButton shared secret; server won't start without it in production
JWT_SECRET Yes - Secret for signing JWTs (server won't start without it); also encrypts the stored OIDC client secret
APP_URL Yes (production) - Public URL of the app (used for CORS + email links); server won't start without it in production
DATABASE_URL No SQLite PostgreSQL connection string
SQLITE_PATH No ./redlight.db SQLite file (when DATABASE_URL is not set)
REDIS_URL No redis://localhost:6379 DragonflyDB / Redis URL
TRUST_PROXY No loopback Express trust proxy setting (number or string)
SMTP_HOST No - SMTP server for email verification
SMTP_PORT No 587 SMTP port
SMTP_USER No - SMTP username
SMTP_PASS No - SMTP password
SMTP_FROM No SMTP_USER Sender address
FEDERATION_DOMAIN No - Domain for federation (enables cross-instance invites)
FEDERATION_KEY_PATH No /app/keys/federation_key.pem Location of the Ed25519 federation key
FEDERATION_ALLOWED_DOMAINS No - (any) Comma-separated list of peer domains to federate with
TRANSCRIPTION_API_URL / TRANSCRIPTION_API_KEY No - Optional recording transcription / AI summary service
ADMIN_EMAIL No admin@example.com Default admin email (first start only)
ADMIN_PASSWORD First start - Initial admin password, 8-64 characters (first start only; no default)

OAuth / OpenID Connect is configured in the admin panel, not via environment variables.

Production Deployment

Behind a reverse proxy (nginx example):

upstream redlight {
  server localhost:3001;
}

server {
  listen 443 ssl http2;
  server_name your-domain.com;
  
  ssl_certificate /path/to/cert.pem;
  ssl_certificate_key /path/to/key.pem;
  
  client_max_body_size 50M;  # presentations may be up to 50 MB

  location / {
    proxy_pass http://redlight;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection upgrade;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;
  }
}

Note: When running behind a reverse proxy, set TRUST_PROXY=1 (or the appropriate value) in .env so Express reads the correct client IP for rate limiting.


🌐 Federation

Federation allows users on different Redlight instances to invite each other into rooms.

Setup

  1. Set FEDERATION_DOMAIN=your-domain.com in .env.
  2. On first start, an Ed25519 key pair is generated automatically and stored in keys/federation_key.pem.
  3. In Docker, mount ./keys:/app/keys (already configured in compose.yml).
  4. Other instances discover your public key via GET /.well-known/redlight.
  5. Optional: restrict federation to known instances with FEDERATION_ALLOWED_DOMAINS=a.example,b.example. By default any instance can send invitations to your users.

How it works

  1. User A on instance-a.com sends an invite to userB@instance-b.com.
  2. Redlight looks up instance-b.com/.well-known/redlight to discover the federation API.
  3. The invite payload is signed with instance A's private key and POSTed to instance B's /api/federation/receive.
  4. Instance B verifies the Ed25519 signature against instance A's public key.
  5. User B sees the invitation and can accept or decline. Accepting provides a join link to the remote room.

🐛 Troubleshooting

Issue: "ERR_ERL_PERMISSIVE_TRUST_PROXY"

Solution: Set TRUST_PROXY in .env. Use loopback (default) or 1 when behind a single reverse proxy.

Issue: "JWT_SECRET is not set"

Solution: The server requires a JWT_SECRET environment variable and will refuse to start without one. Add it to your .env file.

Issue: "Email verification not working"

Solution: Ensure SMTP is configured in .env. If SMTP_HOST is not set, email verification is disabled.

Issue: "BigBlueButton API error"

Solution: Verify BBB_URL and BBB_SECRET are correct. Test the connection with:

curl "https://your-bbb-server/bigbluebutton/api/getMeetings?checksum=..."

Issue: "Database connection failed"

Solution: Check DATABASE_URL format. For PostgreSQL: postgres://user:password@host:5432/redlight

Issue: "Theme not applying"

Solution: Clear browser cache (Ctrl+Shift+Del) or restart dev server with npm run dev.

Issue: "DragonflyDB connection error"

Solution: Ensure DragonflyDB (or Redis) is running and REDIS_URL is correct. If unavailable, the app still works - JWT blacklisting degrades gracefully (logout won't revoke tokens immediately).


📝 License

This project is licensed under the GNU GPL v3 (or later) - see LICENSE file for details.


🤝 Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

  1. Fork the repository
  2. Create a feature branch (git checkout -b feature/amazing-feature)
  3. Commit changes (git commit -m 'Add amazing feature')
  4. Push to branch (git push origin feature/amazing-feature)
  5. Open a Pull Request